Browse Source

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

Laurent Destailleur 9 years ago
parent
commit
a57a41a07d
65 changed files with 766 additions and 323 deletions
  1. 1 1
      COPYRIGHT
  2. 1 1
      ChangeLog
  3. 2 1
      build/exe/doliwamp/doliwamp.iss
  4. 20 2
      build/makepack-dolibarr.pl
  5. 2 0
      build/rpm/dolibarr_fedora.spec
  6. 2 0
      build/rpm/dolibarr_generic.spec
  7. 2 0
      build/rpm/dolibarr_mandriva.spec
  8. 2 0
      build/rpm/dolibarr_opensuse.spec
  9. 3 0
      dev/translation/sanity_check_en_langfiles.php
  10. 3 4
      htdocs/accountancy/journal/purchasesjournal.php
  11. 1 1
      htdocs/accountancy/journal/sellsjournal.php
  12. 32 30
      htdocs/adherents/card.php
  13. 24 24
      htdocs/adherents/card_subscriptions.php
  14. 44 21
      htdocs/adherents/class/adherent.class.php
  15. 1 1
      htdocs/adherents/class/cotisation.class.php
  16. 4 2
      htdocs/admin/company.php
  17. 36 5
      htdocs/admin/menus/edit.php
  18. 1 1
      htdocs/admin/menus/index.php
  19. 38 12
      htdocs/admin/tools/export.php
  20. 1 1
      htdocs/cashdesk/include/environnement.php
  21. 2 1
      htdocs/categories/categorie.php
  22. 8 8
      htdocs/categories/class/categorie.class.php
  23. 1 1
      htdocs/comm/action/class/ical.class.php
  24. 2 1
      htdocs/comm/propal/class/propal.class.php
  25. 5 15
      htdocs/commande/class/commande.class.php
  26. 1 1
      htdocs/commande/orderstoinvoice.php
  27. 12 14
      htdocs/compta/bank/card.php
  28. 24 18
      htdocs/compta/bank/index.php
  29. 108 2
      htdocs/compta/facture/class/facture-rec.class.php
  30. 2 0
      htdocs/compta/facture/class/facture.class.php
  31. 163 3
      htdocs/compta/facture/fiche-rec.php
  32. 23 16
      htdocs/conf/conf.php.example
  33. 2 2
      htdocs/contrat/class/contrat.class.php
  34. 7 5
      htdocs/core/actions_printing.inc.php
  35. 1 2
      htdocs/core/class/commonobject.class.php
  36. 1 1
      htdocs/core/class/conf.class.php
  37. 2 1
      htdocs/core/class/extrafields.class.php
  38. 3 1
      htdocs/core/class/interfaces.class.php
  39. 1 1
      htdocs/core/class/translate.class.php
  40. 6 7
      htdocs/core/db/pgsql.class.php
  41. 3 3
      htdocs/core/lib/functions.lib.php
  42. 10 2
      htdocs/core/menus/standard/auguria.lib.php
  43. 35 16
      htdocs/core/menus/standard/eldy.lib.php
  44. 2 2
      htdocs/core/tpl/objectline_create.tpl.php
  45. 2 1
      htdocs/expedition/class/expedition.class.php
  46. 1 1
      htdocs/expensereport/card.php
  47. 2 2
      htdocs/exports/class/export.class.php
  48. 2 1
      htdocs/fourn/class/fournisseur.facture.class.php
  49. 0 2
      htdocs/fourn/class/fournisseur.product.class.php
  50. 8 6
      htdocs/fourn/commande/orderstoinvoice.php
  51. 1 1
      htdocs/fourn/facture/card.php
  52. 11 5
      htdocs/install/step1.php
  53. 3 0
      htdocs/langs/en_US/admin.lang
  54. 1 0
      htdocs/langs/en_US/bills.lang
  55. 2 0
      htdocs/langs/en_US/printing.lang
  56. 7 7
      htdocs/langs/en_US/products.lang
  57. 2 1
      htdocs/livraison/class/livraison.class.php
  58. 1 1
      htdocs/projet/list.php
  59. 2 1
      htdocs/supplier_proposal/class/supplier_proposal.class.php
  60. 1 1
      htdocs/theme/eldy/style.css.php
  61. 48 46
      htdocs/user/card.php
  62. 15 9
      htdocs/user/class/user.class.php
  63. 3 4
      scripts/product/migrate_picture_path.php
  64. 1 1
      test/phpunit/CategorieTest.php
  65. 9 3
      test/phpunit/PgsqlTest.php

+ 1 - 1
COPYRIGHT

@@ -40,7 +40,7 @@ jQuery blockUI         2.70.0        GPL and MIT License         Yes
 jQuery Colorpicker     1.1           MIT License                 Yes             JS library for color picker for a defined list of colors
 jQuery Colorpicker     1.1           MIT License                 Yes             JS library for color picker for a defined list of colors
 jQuery DataTables      1.9.4         BSD                         Yes             JS library for tables output
 jQuery DataTables      1.9.4         BSD                         Yes             JS library for tables output
 jQuery FileUpload      5.0.3         GPL and MIT License         Yes             JS library to upload files
 jQuery FileUpload      5.0.3         GPL and MIT License         Yes             JS library to upload files
-jQuery Flot            0.7           MIT License                 Yes             JS library to build graph
+jQuery Flot            0.8.3         MIT License                 Yes             JS library to build graph
 jQuery JCrop           0.9.8         GPL and MIT License         Yes             JS library plugin Crop (to crop images)
 jQuery JCrop           0.9.8         GPL and MIT License         Yes             JS library plugin Crop (to crop images)
 jQuery Jeditable       1.7.1         GPL and MIT License         Yes             JS library plugin jeditable (to edit in place)
 jQuery Jeditable       1.7.1         GPL and MIT License         Yes             JS library plugin jeditable (to edit in place)
 jQuery jNotify         1.1.00        Apache Software License 2.0 Yes             JS library plugin jNotify (to use ajax popups)
 jQuery jNotify         1.1.00        Apache Software License 2.0 Yes             JS library plugin jNotify (to use ajax popups)

+ 1 - 1
ChangeLog

@@ -12,7 +12,7 @@ Upgrading to any other version or any other database system is abolutely require
 make a Dolibarr upgrade.
 make a Dolibarr upgrade.
 
 
 
 
-***** ChangeLog for 4.0 compared to 3.9.* *****
+***** ChangeLog for 4.0.0 compared to 3.9.* *****
 For users:
 For users:
 
 
 NEW: Add reccuring invoice feature and automatic generation of invoices.
 NEW: Add reccuring invoice feature and automatic generation of invoices.

+ 2 - 1
build/exe/doliwamp/doliwamp.iss

@@ -101,6 +101,7 @@ Source: "build\exe\doliwamp\UsedPort.exe"; DestDir: "{app}\"; Flags: ignoreversi
 ; Put here path of Wampserver applications
 ; Put here path of Wampserver applications
 ; Value OK: apache 2.2.6, php 5.2.5 (5.2.11, 5.3.0 and 5.3.1 fails if php_exif, php_pgsql, php_zip is on), mysql 5.0.45 or 5.1.36
 ; Value OK: apache 2.2.6, php 5.2.5 (5.2.11, 5.3.0 and 5.3.1 fails if php_exif, php_pgsql, php_zip is on), mysql 5.0.45 or 5.1.36
 ; Value OK: apache 2.2.11, php 5.3.0 (if no php_exif, php_pgsql, php_zip), mysql 5.0.45 or 5.1.36
 ; Value OK: apache 2.2.11, php 5.3.0 (if no php_exif, php_pgsql, php_zip), mysql 5.0.45 or 5.1.36
+; Value ???: apache 2.4.19, php 5.5.12, mysql 5.6.17
 Source: "C:\Program Files\Wamp\apps\phpmyadmin4.1.14\*.*"; DestDir: "{app}\apps\phpmyadmin4.1.14"; Flags: ignoreversion recursesubdirs; Excludes: "config.inc.php,wampserver.conf,*.log,*_log,darkblue_orange"
 Source: "C:\Program Files\Wamp\apps\phpmyadmin4.1.14\*.*"; DestDir: "{app}\apps\phpmyadmin4.1.14"; Flags: ignoreversion recursesubdirs; Excludes: "config.inc.php,wampserver.conf,*.log,*_log,darkblue_orange"
 Source: "C:\Program Files\Wamp\bin\apache\apache2.4.9\*.*"; DestDir: "{app}\bin\apache\apache2.4.9"; Flags: ignoreversion recursesubdirs; Excludes: "php.ini,httpd.conf,wampserver.conf,*.log,*_log"
 Source: "C:\Program Files\Wamp\bin\apache\apache2.4.9\*.*"; DestDir: "{app}\bin\apache\apache2.4.9"; Flags: ignoreversion recursesubdirs; Excludes: "php.ini,httpd.conf,wampserver.conf,*.log,*_log"
 Source: "C:\Program Files\Wamp\bin\php\php5.5.12\*.*"; DestDir: "{app}\bin\php\php5.5.12"; Flags: ignoreversion recursesubdirs; Excludes: "php.ini,phpForApache.ini,wampserver.conf,*.log,*_log"
 Source: "C:\Program Files\Wamp\bin\php\php5.5.12\*.*"; DestDir: "{app}\bin\php\php5.5.12"; Flags: ignoreversion recursesubdirs; Excludes: "php.ini,phpForApache.ini,wampserver.conf,*.log,*_log"
@@ -109,7 +110,7 @@ Source: "C:\Program Files\Wamp\bin\mysql\mysql5.6.17\*.*"; DestDir: "{app}\bin\m
 Source: "build\exe\doliwamp\mysql\*.*"; DestDir: "{app}\bin\mysql\data\mysql"; Flags: onlyifdoesntexist ignoreversion recursesubdirs; Excludes: ".gitignore,.project,CVS\*,Thumbs.db"
 Source: "build\exe\doliwamp\mysql\*.*"; DestDir: "{app}\bin\mysql\data\mysql"; Flags: onlyifdoesntexist ignoreversion recursesubdirs; Excludes: ".gitignore,.project,CVS\*,Thumbs.db"
 ; Dolibarr
 ; Dolibarr
 Source: "htdocs\*.*"; DestDir: "{app}\www\dolibarr\htdocs"; Flags: ignoreversion recursesubdirs; Excludes: ".gitignore,.project,CVS\*,Thumbs.db,custom\*,custom2\*,documents\*,includes\ckeditor\_source\*,includes\savant\*,includes\phpmailer\*,jquery\plugins\template\*,nltechno*\*,PHPExcel\Shared\PDF\*,PHPExcel\Shared\PCLZip\*,tcpdf\fonts\dejavu-fonts-ttf-2.33\*,tcpdf\fonts\freefont-20100919\*,tcpdf\fonts\utils\*,*\conf.php,*\conf.php.mysql,*\conf.php.old,*\conf.php.postgres,*\conf.php.sav,*\install.forced.php"
 Source: "htdocs\*.*"; DestDir: "{app}\www\dolibarr\htdocs"; Flags: ignoreversion recursesubdirs; Excludes: ".gitignore,.project,CVS\*,Thumbs.db,custom\*,custom2\*,documents\*,includes\ckeditor\_source\*,includes\savant\*,includes\phpmailer\*,jquery\plugins\template\*,nltechno*\*,PHPExcel\Shared\PDF\*,PHPExcel\Shared\PCLZip\*,tcpdf\fonts\dejavu-fonts-ttf-2.33\*,tcpdf\fonts\freefont-20100919\*,tcpdf\fonts\utils\*,*\conf.php,*\conf.php.mysql,*\conf.php.old,*\conf.php.postgres,*\conf.php.sav,*\install.forced.php"
-Source: "dev\*.*"; DestDir: "{app}\www\dolibarr\dev"; Flags: ignoreversion recursesubdirs; Excludes: ".gitignore,.project,CVS\*,Thumbs.db,dbmodel\*,fpdf\*,initdata\*,iso-normes\*,licence\*,phpcheckstyle\*,phpunit\*,samples\*,test\*,uml\*,vagrant\*,xdebug\*"
+Source: "dev\*.*"; DestDir: "{app}\www\dolibarr\dev"; Flags: ignoreversion recursesubdirs; Excludes: ".gitignore,.project,CVS\*,Thumbs.db,dbmodel\*,fpdf\*,initdata\*,initdemo\*,iso-normes\*,licence\*,phpcheckstyle\*,phpunit\*,samples\*,test\*,uml\*,vagrant\*,xdebug\*"
 Source: "doc\*.*"; DestDir: "{app}\www\dolibarr\doc"; Flags: ignoreversion recursesubdirs; Excludes: ".gitignore,.project,CVS\*,Thumbs.db,wiki\*,plaquette\*,dev\*,images\dolibarr_screenshot2.png,images\dolibarr_screenshot3.png,images\dolibarr_screenshot4.png,images\dolibarr_screenshot5.png,images\dolibarr_screenshot6.png,images\dolibarr_screenshot7.png,images\dolibarr_screenshot8.png,images\dolibarr_screenshot9.png,images\dolibarr_screenshot10.png,images\dolibarr_screenshot11.png,images\dolibarr_screenshot12.png"
 Source: "doc\*.*"; DestDir: "{app}\www\dolibarr\doc"; Flags: ignoreversion recursesubdirs; Excludes: ".gitignore,.project,CVS\*,Thumbs.db,wiki\*,plaquette\*,dev\*,images\dolibarr_screenshot2.png,images\dolibarr_screenshot3.png,images\dolibarr_screenshot4.png,images\dolibarr_screenshot5.png,images\dolibarr_screenshot6.png,images\dolibarr_screenshot7.png,images\dolibarr_screenshot8.png,images\dolibarr_screenshot9.png,images\dolibarr_screenshot10.png,images\dolibarr_screenshot11.png,images\dolibarr_screenshot12.png"
 Source: "scripts\*.*"; DestDir: "{app}\www\dolibarr\scripts"; Flags: ignoreversion recursesubdirs; Excludes: ".gitignore,.project,CVS\*,Thumbs.db,product\materiel.net.php,product\import-product.php"
 Source: "scripts\*.*"; DestDir: "{app}\www\dolibarr\scripts"; Flags: ignoreversion recursesubdirs; Excludes: ".gitignore,.project,CVS\*,Thumbs.db,product\materiel.net.php,product\import-product.php"
 Source: "*.*"; DestDir: "{app}\www\dolibarr"; Flags: ignoreversion; Excludes: ".gitignore,.project,CVS\*,Thumbs.db,default.properties,install.lock"
 Source: "*.*"; DestDir: "{app}\www\dolibarr"; Flags: ignoreversion; Excludes: ".gitignore,.project,CVS\*,Thumbs.db,default.properties,install.lock"

+ 20 - 2
build/makepack-dolibarr.pl

@@ -53,7 +53,7 @@ if (-d "/usr/src/RPM")      { $RPMDIR="/usr/src/RPM"; } # mandrake
 
 
 
 
 use vars qw/ $REVISION $VERSION /;
 use vars qw/ $REVISION $VERSION /;
-$VERSION="3.3";
+$VERSION="4.0";
 
 
 
 
 
 
@@ -356,6 +356,7 @@ if ($nboftargetok) {
 		# Test that the ChangeLog is ok
 		# Test that the ChangeLog is ok
 		$TMPBUILDTOCHECKCHANGELOG=$BUILD;
 		$TMPBUILDTOCHECKCHANGELOG=$BUILD;
 		$TMPBUILDTOCHECKCHANGELOG =~ s/\-rc\d*//;
 		$TMPBUILDTOCHECKCHANGELOG =~ s/\-rc\d*//;
+		$TMPBUILDTOCHECKCHANGELOG =~ s/\-beta\d*//;
 		print "Check if ChangeLog is ok for version $MAJOR.$MINOR\.$TMPBUILDTOCHECKCHANGELOG\n";
 		print "Check if ChangeLog is ok for version $MAJOR.$MINOR\.$TMPBUILDTOCHECKCHANGELOG\n";
 		$ret=`grep "ChangeLog for $MAJOR.$MINOR\.$TMPBUILDTOCHECKCHANGELOG" "$SOURCE/ChangeLog" 2>&1`;
 		$ret=`grep "ChangeLog for $MAJOR.$MINOR\.$TMPBUILDTOCHECKCHANGELOG" "$SOURCE/ChangeLog" 2>&1`;
 		if (! $ret)
 		if (! $ret)
@@ -458,6 +459,7 @@ if ($nboftargetok) {
 		$ret=`rm -fr $BUILDROOT/$PROJECT/dev/codetemplates`;
 		$ret=`rm -fr $BUILDROOT/$PROJECT/dev/codetemplates`;
 		$ret=`rm -fr $BUILDROOT/$PROJECT/dev/dbmodel`;
 		$ret=`rm -fr $BUILDROOT/$PROJECT/dev/dbmodel`;
 		$ret=`rm -fr $BUILDROOT/$PROJECT/dev/initdata`;
 		$ret=`rm -fr $BUILDROOT/$PROJECT/dev/initdata`;
+		$ret=`rm -fr $BUILDROOT/$PROJECT/dev/initdemo`;
 		$ret=`rm -fr $BUILDROOT/$PROJECT/dev/iso-normes`;
 		$ret=`rm -fr $BUILDROOT/$PROJECT/dev/iso-normes`;
 		$ret=`rm -fr $BUILDROOT/$PROJECT/dev/ldap`;
 		$ret=`rm -fr $BUILDROOT/$PROJECT/dev/ldap`;
 		$ret=`rm -fr $BUILDROOT/$PROJECT/dev/licence`;
 		$ret=`rm -fr $BUILDROOT/$PROJECT/dev/licence`;
@@ -1121,7 +1123,7 @@ if ($nboftargetok) {
 	{
 	{
 		if ($CHOOSEDPUBLISH{$target} < 0) { next; }
 		if ($CHOOSEDPUBLISH{$target} < 0) { next; }
 	
 	
-		print "\nList of files to publish\n";
+		print "\nList of files to publish (BUILD=$BUILD)\n";
 		%filestoscansf=(
 		%filestoscansf=(
 			"$DESTI/package_rpm_generic/$FILENAMERPM"=>'Dolibarr installer for Fedora-Redhat-Mandriva-Opensuse (DoliRpm)',
 			"$DESTI/package_rpm_generic/$FILENAMERPM"=>'Dolibarr installer for Fedora-Redhat-Mandriva-Opensuse (DoliRpm)',
 			"$DESTI/package_debian-ubuntu/${FILENAMEDEB}_all.deb"=>'Dolibarr installer for Debian-Ubuntu (DoliDeb)',
 			"$DESTI/package_debian-ubuntu/${FILENAMEDEB}_all.deb"=>'Dolibarr installer for Debian-Ubuntu (DoliDeb)',
@@ -1136,6 +1138,22 @@ if ($nboftargetok) {
 			"$DESTI/standard/$FILENAMETGZ.tgz"=>'standard',
 			"$DESTI/standard/$FILENAMETGZ.tgz"=>'standard',
 			"$DESTI/standard/$FILENAMETGZ.zip"=>'standard'
 			"$DESTI/standard/$FILENAMETGZ.zip"=>'standard'
 		);
 		);
+		if ($target eq 'ASSO' && $BUILD =~ /[a-z]/i)   { 	# Not stable
+			%filestoscansf=(
+				"$DESTI/$FILENAMERPM"=>'Dolibarr installer for Fedora-Redhat-Mandriva-Opensuse (DoliRpm)',
+				"$DESTI/${FILENAMEDEB}_all.deb"=>'Dolibarr installer for Debian-Ubuntu (DoliDeb)',
+				"$DESTI/$FILENAMEEXEDOLIWAMP.exe"=>'Dolibarr installer for Windows (DoliWamp)',
+				"$DESTI/$FILENAMETGZ.tgz"=>'Dolibarr ERP-CRM',
+				"$DESTI/$FILENAMETGZ.zip"=>'Dolibarr ERP-CRM'
+			);
+			%filestoscanstableasso=(
+				"$DESTI/$FILENAMERPM"=>'',
+				"$DESTI/${FILENAMEDEB}_all.deb"=>'',
+				"$DESTI/$FILENAMEEXEDOLIWAMP.exe"=>'',
+				"$DESTI/$FILENAMETGZ.tgz"=>'',
+				"$DESTI/$FILENAMETGZ.zip"=>''
+			);
+		}
 
 
 		use POSIX qw/strftime/;
 		use POSIX qw/strftime/;
 		foreach my $file (sort keys %filestoscansf)
 		foreach my $file (sort keys %filestoscansf)

+ 2 - 0
build/rpm/dolibarr_fedora.spec

@@ -192,6 +192,7 @@ done >>%{name}.lang
 %_datadir/dolibarr/htdocs/loan
 %_datadir/dolibarr/htdocs/loan
 %_datadir/dolibarr/htdocs/mailmanspip
 %_datadir/dolibarr/htdocs/mailmanspip
 %_datadir/dolibarr/htdocs/margin
 %_datadir/dolibarr/htdocs/margin
+%_datadir/dolibarr/htdocs/multicurrency
 %_datadir/dolibarr/htdocs/opensurvey
 %_datadir/dolibarr/htdocs/opensurvey
 %_datadir/dolibarr/htdocs/paybox
 %_datadir/dolibarr/htdocs/paybox
 %_datadir/dolibarr/htdocs/paypal
 %_datadir/dolibarr/htdocs/paypal
@@ -206,6 +207,7 @@ done >>%{name}.lang
 %_datadir/dolibarr/htdocs/theme
 %_datadir/dolibarr/htdocs/theme
 %_datadir/dolibarr/htdocs/user
 %_datadir/dolibarr/htdocs/user
 %_datadir/dolibarr/htdocs/webservices
 %_datadir/dolibarr/htdocs/webservices
+%_datadir/dolibarr/htdocs/websites
 %_datadir/dolibarr/htdocs/*.ico
 %_datadir/dolibarr/htdocs/*.ico
 %_datadir/dolibarr/htdocs/*.patch
 %_datadir/dolibarr/htdocs/*.patch
 %_datadir/dolibarr/htdocs/*.php
 %_datadir/dolibarr/htdocs/*.php

+ 2 - 0
build/rpm/dolibarr_generic.spec

@@ -272,6 +272,7 @@ done >>%{name}.lang
 %_datadir/dolibarr/htdocs/loan
 %_datadir/dolibarr/htdocs/loan
 %_datadir/dolibarr/htdocs/mailmanspip
 %_datadir/dolibarr/htdocs/mailmanspip
 %_datadir/dolibarr/htdocs/margin
 %_datadir/dolibarr/htdocs/margin
+%_datadir/dolibarr/htdocs/multicurrency
 %_datadir/dolibarr/htdocs/opensurvey
 %_datadir/dolibarr/htdocs/opensurvey
 %_datadir/dolibarr/htdocs/paybox
 %_datadir/dolibarr/htdocs/paybox
 %_datadir/dolibarr/htdocs/paypal
 %_datadir/dolibarr/htdocs/paypal
@@ -286,6 +287,7 @@ done >>%{name}.lang
 %_datadir/dolibarr/htdocs/theme
 %_datadir/dolibarr/htdocs/theme
 %_datadir/dolibarr/htdocs/user
 %_datadir/dolibarr/htdocs/user
 %_datadir/dolibarr/htdocs/webservices
 %_datadir/dolibarr/htdocs/webservices
+%_datadir/dolibarr/htdocs/websites
 %_datadir/dolibarr/htdocs/*.ico
 %_datadir/dolibarr/htdocs/*.ico
 %_datadir/dolibarr/htdocs/*.patch
 %_datadir/dolibarr/htdocs/*.patch
 %_datadir/dolibarr/htdocs/*.php
 %_datadir/dolibarr/htdocs/*.php

+ 2 - 0
build/rpm/dolibarr_mandriva.spec

@@ -189,6 +189,7 @@ done >>%{name}.lang
 %_datadir/dolibarr/htdocs/loan
 %_datadir/dolibarr/htdocs/loan
 %_datadir/dolibarr/htdocs/mailmanspip
 %_datadir/dolibarr/htdocs/mailmanspip
 %_datadir/dolibarr/htdocs/margin
 %_datadir/dolibarr/htdocs/margin
+%_datadir/dolibarr/htdocs/multicurrency
 %_datadir/dolibarr/htdocs/opensurvey
 %_datadir/dolibarr/htdocs/opensurvey
 %_datadir/dolibarr/htdocs/paybox
 %_datadir/dolibarr/htdocs/paybox
 %_datadir/dolibarr/htdocs/paypal
 %_datadir/dolibarr/htdocs/paypal
@@ -203,6 +204,7 @@ done >>%{name}.lang
 %_datadir/dolibarr/htdocs/theme
 %_datadir/dolibarr/htdocs/theme
 %_datadir/dolibarr/htdocs/user
 %_datadir/dolibarr/htdocs/user
 %_datadir/dolibarr/htdocs/webservices
 %_datadir/dolibarr/htdocs/webservices
+%_datadir/dolibarr/htdocs/websites
 %_datadir/dolibarr/htdocs/*.ico
 %_datadir/dolibarr/htdocs/*.ico
 %_datadir/dolibarr/htdocs/*.patch
 %_datadir/dolibarr/htdocs/*.patch
 %_datadir/dolibarr/htdocs/*.php
 %_datadir/dolibarr/htdocs/*.php

+ 2 - 0
build/rpm/dolibarr_opensuse.spec

@@ -200,6 +200,7 @@ done >>%{name}.lang
 %_datadir/dolibarr/htdocs/loan
 %_datadir/dolibarr/htdocs/loan
 %_datadir/dolibarr/htdocs/mailmanspip
 %_datadir/dolibarr/htdocs/mailmanspip
 %_datadir/dolibarr/htdocs/margin
 %_datadir/dolibarr/htdocs/margin
+%_datadir/dolibarr/htdocs/multicurrency
 %_datadir/dolibarr/htdocs/opensurvey
 %_datadir/dolibarr/htdocs/opensurvey
 %_datadir/dolibarr/htdocs/paybox
 %_datadir/dolibarr/htdocs/paybox
 %_datadir/dolibarr/htdocs/paypal
 %_datadir/dolibarr/htdocs/paypal
@@ -214,6 +215,7 @@ done >>%{name}.lang
 %_datadir/dolibarr/htdocs/theme
 %_datadir/dolibarr/htdocs/theme
 %_datadir/dolibarr/htdocs/user
 %_datadir/dolibarr/htdocs/user
 %_datadir/dolibarr/htdocs/webservices
 %_datadir/dolibarr/htdocs/webservices
+%_datadir/dolibarr/htdocs/websites
 %_datadir/dolibarr/htdocs/*.ico
 %_datadir/dolibarr/htdocs/*.ico
 %_datadir/dolibarr/htdocs/*.patch
 %_datadir/dolibarr/htdocs/*.patch
 %_datadir/dolibarr/htdocs/*.php
 %_datadir/dolibarr/htdocs/*.php

+ 3 - 0
dev/translation/sanity_check_en_langfiles.php

@@ -316,6 +316,9 @@ if ((! empty($_REQUEST['unused']) && $_REQUEST['unused'] == 'true') || (isset($a
 	    if (preg_match('/^EMailText/', $value)) $qualifiedforclean=0;
 	    if (preg_match('/^EMailText/', $value)) $qualifiedforclean=0;
 	    if (preg_match('/ById$/', $value)) $qualifiedforclean=0;
 	    if (preg_match('/ById$/', $value)) $qualifiedforclean=0;
 	    if (preg_match('/ByLogin$/', $value)) $qualifiedforclean=0;
 	    if (preg_match('/ByLogin$/', $value)) $qualifiedforclean=0;
+	    // printing
+	    if (preg_match('/PrintingDriverDesc$/', $value)) $qualifiedforclean=0;
+	    if (preg_match('/PrintTestDesc$/', $value)) $qualifiedforclean=0;
 	    // products
 	    // products
 	    if (preg_match('/GlobalVariableUpdaterType$/', $value)) $qualifiedforclean=0;
 	    if (preg_match('/GlobalVariableUpdaterType$/', $value)) $qualifiedforclean=0;
 	    if (preg_match('/GlobalVariableUpdaterHelp$/', $value)) $qualifiedforclean=0;
 	    if (preg_match('/GlobalVariableUpdaterHelp$/', $value)) $qualifiedforclean=0;

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

@@ -166,14 +166,13 @@ if ($action == 'writebookkeeping') {
 	$now = dol_now();
 	$now = dol_now();
 	$error = 0;
 	$error = 0;
 
 
-	foreach ( $tabfac as $key => $val ) {
-
+	foreach ($tabfac as $key => $val) 
+	{
 		$companystatic = new Societe($db);
 		$companystatic = new Societe($db);
 		$invoicestatic = new FactureFournisseur($db);
 		$invoicestatic = new FactureFournisseur($db);
 
 
 		$invoicestatic->id = $key;
 		$invoicestatic->id = $key;
-		$invoicestatic->ref = $val["ref"];
-		$invoicestatic->ref = $val["refsologest"];
+		$invoicestatic->ref = (string) $val["refsologest"];
 		$invoicestatic->refsupplier = $val["refsuppliersologest"];
 		$invoicestatic->refsupplier = $val["refsuppliersologest"];
 		$invoicestatic->type = $val["type"];
 		$invoicestatic->type = $val["type"];
 		$invoicestatic->description = html_entity_decode(dol_trunc($val["description"], 32));
 		$invoicestatic->description = html_entity_decode(dol_trunc($val["description"], 32));

+ 1 - 1
htdocs/accountancy/journal/sellsjournal.php

@@ -207,7 +207,7 @@ if ($action == 'writebookkeeping') {
 		$companystatic->client = $tabcompany[$key]['code_client'];
 		$companystatic->client = $tabcompany[$key]['code_client'];
 
 
 		$invoicestatic->id = $key;
 		$invoicestatic->id = $key;
-		$invoicestatic->ref = $val["ref"];
+		$invoicestatic->ref = (string) $val["ref"];
 
 
 		foreach ( $tabttc[$key] as $k => $mt ) {
 		foreach ( $tabttc[$key] as $k => $mt ) {
 			$bookkeeping = new BookKeeping($db);
 			$bookkeeping = new BookKeeping($db);

+ 32 - 30
htdocs/adherents/card.php

@@ -404,11 +404,7 @@ if (empty($reshook))
 			}
 			}
 			else
 			else
 			{
 			{
-				if ($object->error) {
-					setEventMessages($object->error, $object->errors, 'errors');
-				} else {
-					setEventMessages($object->error, $object->errors, 'errors');
-				}
+				setEventMessages($object->error, $object->errors, 'errors');
 				$action='';
 				$action='';
 			}
 			}
 		}
 		}
@@ -1443,6 +1439,12 @@ else
 		if (empty($conf->global->ADHERENT_LOGIN_NOT_REQUIRED))
 		if (empty($conf->global->ADHERENT_LOGIN_NOT_REQUIRED))
 		{
 		{
 			print '<tr><td>'.$langs->trans("Password").'</td><td>'.preg_replace('/./i','*',$object->pass);
 			print '<tr><td>'.$langs->trans("Password").'</td><td>'.preg_replace('/./i','*',$object->pass);
+			if ($object->pass) print preg_replace('/./i','*',$object->pass);
+			else
+			{
+			    if ($user->admin) print $langs->trans("Crypted").': '.$object->pass_indatabase_crypted;
+			    else print $langs->trans("Hidden");
+			}
 			if ((! empty($object->pass) || ! empty($object->pass_crypted)) && empty($object->user_id))
 			if ((! empty($object->pass) || ! empty($object->pass_crypted)) && empty($object->user_id))
 			{
 			{
 			    $langs->load("errors");
 			    $langs->load("errors");
@@ -1451,7 +1453,7 @@ else
 			}
 			}
 			print '</td></tr>';
 			print '</td></tr>';
 		}
 		}
-
+		
         print '</table>';
         print '</table>';
         
         
         print '</div>';
         print '</div>';
@@ -1483,6 +1485,30 @@ else
 			print $object->showOptionals($extrafields, 'view', $parameters);
 			print $object->showOptionals($extrafields, 'view', $parameters);
 		}
 		}
 
 
+        // Date end subscription
+        print '<tr><td>'.$langs->trans("SubscriptionEndDate").'</td><td class="valeur">';
+        if ($object->datefin)
+        {
+            print dol_print_date($object->datefin,'day');
+            if ($object->hasDelay()) {
+                print " ".img_warning($langs->trans("Late"));
+            }
+        }
+        else
+        {
+	        if (! $adht->cotisation)
+	        {
+	        	print $langs->trans("SubscriptionNotRecorded");
+		        if ($object->statut > 0) print " ".img_warning($langs->trans("Late")); // displays delay Pictogram only if not a draft and not terminated
+	        }
+	        else
+	        {
+	            print $langs->trans("SubscriptionNotReceived");
+	            if ($object->statut > 0) print " ".img_warning($langs->trans("Late")); // displays delay Pictogram only if not a draft and not terminated
+	        }
+        }
+        print '</td></tr>';
+		
 		// Third party Dolibarr
 		// Third party Dolibarr
 		if (! empty($conf->societe->enabled))
 		if (! empty($conf->societe->enabled))
 		{
 		{
@@ -1553,30 +1579,6 @@ else
 		}
 		}
 		print '</td></tr>';
 		print '</td></tr>';
 
 
-        // Date end subscription
-        print '<tr><td>'.$langs->trans("SubscriptionEndDate").'</td><td class="valeur">';
-        if ($object->datefin)
-        {
-            print dol_print_date($object->datefin,'day');
-            if ($object->hasDelay()) {
-                print " ".img_warning($langs->trans("Late"));
-            }
-        }
-        else
-        {
-	        if (! $adht->cotisation)
-	        {
-	        	print $langs->trans("SubscriptionNotRecorded");
-		        if ($object->statut > 0) print " ".img_warning($langs->trans("Late")); // displays delay Pictogram only if not a draft and not terminated
-	        }
-	        else
-	        {
-	            print $langs->trans("SubscriptionNotReceived");
-	            if ($object->statut > 0) print " ".img_warning($langs->trans("Late")); // displays delay Pictogram only if not a draft and not terminated
-	        }
-        }
-        print '</td></tr>';
-
 		print "</table>\n";
 		print "</table>\n";
 
 
 		print "</div></div></div>\n";
 		print "</div></div></div>\n";

+ 24 - 24
htdocs/adherents/card_subscriptions.php

@@ -652,6 +652,30 @@ if ($rowid > 0)
 		print $object->showOptionals($extrafields, 'view', $parameters);
 		print $object->showOptionals($extrafields, 'view', $parameters);
 	}
 	}
 
 
+	// Date end subscription
+	print '<tr><td>'.$langs->trans("SubscriptionEndDate").'</td><td class="valeur">';
+	if ($object->datefin)
+	{
+	    print dol_print_date($object->datefin,'day');
+	    if ($object->hasDelay()) {
+	        print " ".img_warning($langs->trans("Late"));
+	    }
+	}
+	else
+	{
+	    if (! $adht->cotisation)
+	    {
+	        print $langs->trans("SubscriptionNotRecorded");
+	        if ($object->statut > 0) print " ".img_warning($langs->trans("Late")); // Affiche picto retard uniquement si non brouillon et non resilie
+	    }
+	    else
+	    {
+	        print $langs->trans("SubscriptionNotReceived");
+	        if ($object->statut > 0) print " ".img_warning($langs->trans("Late")); // Affiche picto retard uniquement si non brouillon et non resilie
+	    }
+	}
+	print '</td></tr>';
+	
 	// Third party Dolibarr
 	// Third party Dolibarr
 	if (! empty($conf->societe->enabled))
 	if (! empty($conf->societe->enabled))
 	{
 	{
@@ -722,30 +746,6 @@ if ($rowid > 0)
 	}
 	}
 	print '</td></tr>';
 	print '</td></tr>';
 
 
-    // Date end subscription
-    print '<tr><td>'.$langs->trans("SubscriptionEndDate").'</td><td class="valeur">';
-    if ($object->datefin)
-    {
-        print dol_print_date($object->datefin,'day');
-        if ($object->hasDelay()) {
-            print " ".img_warning($langs->trans("Late"));
-        }
-    }
-    else
-    {
-	    if (! $adht->cotisation)
-	    {
-	     	print $langs->trans("SubscriptionNotRecorded");
-	        if ($object->statut > 0) print " ".img_warning($langs->trans("Late")); // Affiche picto retard uniquement si non brouillon et non resilie
-	    }
-	    else
-	    {
-	    	print $langs->trans("SubscriptionNotReceived");
-	        if ($object->statut > 0) print " ".img_warning($langs->trans("Late")); // Affiche picto retard uniquement si non brouillon et non resilie
-	    }
-    }
-    print '</td></tr>';
-
     print "</table>\n";
     print "</table>\n";
 
 
 	print "</div></div></div>\n";
 	print "</div></div></div>\n";

+ 44 - 21
htdocs/adherents/class/adherent.class.php

@@ -47,8 +47,15 @@ class Adherent extends CommonObject
     var $mesgs;
     var $mesgs;
 
 
     var $login;
     var $login;
-    var $pass;
-    var $societe;
+
+	//! Clear password in memory
+	var $pass;
+	//! Clear password in database (defined if DATABASE_PWD_ENCRYPTED=0)
+	var $pass_indatabase;
+	//! Encrypted password in database (always defined)
+	var $pass_indatabase_crypted;
+
+	var $societe;
     var $company;
     var $company;
     var $address;
     var $address;
     var $zip;
     var $zip;
@@ -309,7 +316,7 @@ class Adherent extends CommonObject
             if ($id > 0)
             if ($id > 0)
             {
             {
                 $this->id=$id;
                 $this->id=$id;
-                $this->ref=$id;
+                $this->ref=(string) $id;
 
 
                 // Update minor fields
                 // Update minor fields
                 $result=$this->update($user,1,1,0,0,'add'); // nosync is 1 to avoid update data of user
                 $result=$this->update($user,1,1,0,0,'add'); // nosync is 1 to avoid update data of user
@@ -482,8 +489,10 @@ class Adherent extends CommonObject
                 dol_syslog(get_class($this)."::update update password");
                 dol_syslog(get_class($this)."::update update password");
                 if ($this->pass != $this->pass_indatabase && $this->pass != $this->pass_indatabase_crypted)
                 if ($this->pass != $this->pass_indatabase && $this->pass != $this->pass_indatabase_crypted)
                 {
                 {
-                    // Si mot de passe saisi et different de celui en base
-                    $result=$this->setPassword($user,$this->pass,0,$notrigger,$nosyncuserpass);
+                    $isencrypted = empty($conf->global->DATABASE_PWD_ENCRYPTED)?0:1;
+                    
+                    // If password to set differs from the one found into database
+                    $result=$this->setPassword($user,$this->pass,$isencrypted,$notrigger,$nosyncuserpass);
                     if (! $nbrowsaffected) $nbrowsaffected++;
                     if (! $nbrowsaffected) $nbrowsaffected++;
                 }
                 }
             }
             }
@@ -509,7 +518,7 @@ class Adherent extends CommonObject
             if (! $error && $nbrowsaffected)	// If something has change in main data
             if (! $error && $nbrowsaffected)	// If something has change in main data
             {
             {
                 // Update information on linked user if it is an update
                 // Update information on linked user if it is an update
-                if ($this->user_id > 0 && ! $nosyncuser)
+                if (! $error && $this->user_id > 0 && ! $nosyncuser)
                 {
                 {
                     require_once DOL_DOCUMENT_ROOT.'/user/class/user.class.php';
                     require_once DOL_DOCUMENT_ROOT.'/user/class/user.class.php';
 
 
@@ -552,7 +561,7 @@ class Adherent extends CommonObject
                 }
                 }
 
 
                 // Update information on linked thirdparty if it is an update
                 // Update information on linked thirdparty if it is an update
-                if ($this->fk_soc > 0 && ! $nosyncthirdparty)
+                if (! $error && $this->fk_soc > 0 && ! $nosyncthirdparty)
                 {
                 {
                     require_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php';
                     require_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php';
 
 
@@ -810,13 +819,11 @@ class Adherent extends CommonObject
             $password=getRandomPassword(false);
             $password=getRandomPassword(false);
         }
         }
 
 
-        // Cryptage mot de passe
-        if ($isencrypted)
-        {
-            // Encryption
-            $password_indatabase = dol_hash($password);
-        }
-        else
+        // Crypt password
+        $password_crypted = dol_hash($password);
+
+        $password_indatabase = '';
+        if (! $isencrypted)
         {
         {
             $password_indatabase = $password;
             $password_indatabase = $password;
         }
         }
@@ -824,7 +831,17 @@ class Adherent extends CommonObject
         $this->db->begin();
         $this->db->begin();
 
 
         // Mise a jour
         // Mise a jour
-        $sql = "UPDATE ".MAIN_DB_PREFIX."adherent SET pass = '".$this->db->escape($password_indatabase)."'";
+        $sql = "UPDATE ".MAIN_DB_PREFIX."adherent";
+        $sql.= " SET pass_crypted = '".$this->db->escape($password_crypted)."'";
+        //if (! empty($conf->global->DATABASE_PWD_ENCRYPTED))
+        if ($isencrypted)
+        {
+            $sql.= ", pass = null";
+        }
+        else
+        {
+            $sql.= ", pass = '".$this->db->escape($password_indatabase)."'";
+        }
         $sql.= " WHERE rowid = ".$this->id;
         $sql.= " WHERE rowid = ".$this->id;
 
 
         //dol_syslog("Adherent::Password sql=hidden");
         //dol_syslog("Adherent::Password sql=hidden");
@@ -838,7 +855,8 @@ class Adherent extends CommonObject
             {
             {
                 $this->pass=$password;
                 $this->pass=$password;
                 $this->pass_indatabase=$password_indatabase;
                 $this->pass_indatabase=$password_indatabase;
-
+                $this->pass_indatabase_crypted=$password_crypted;
+                
                 if ($this->user_id && ! $nosyncuser)
                 if ($this->user_id && ! $nosyncuser)
                 {
                 {
                     require_once DOL_DOCUMENT_ROOT.'/user/class/user.class.php';
                     require_once DOL_DOCUMENT_ROOT.'/user/class/user.class.php';
@@ -1042,7 +1060,7 @@ class Adherent extends CommonObject
 
 
         $sql = "SELECT d.rowid, d.ref_ext, d.civility as civility_id, d.firstname, d.lastname, d.societe as company, d.fk_soc, d.statut, d.public, d.address, d.zip, d.town, d.note_private,";
         $sql = "SELECT d.rowid, d.ref_ext, d.civility as civility_id, d.firstname, d.lastname, d.societe as company, d.fk_soc, d.statut, d.public, d.address, d.zip, d.town, d.note_private,";
         $sql.= " d.note_public,";
         $sql.= " d.note_public,";
-        $sql.= " d.email, d.skype, d.phone, d.phone_perso, d.phone_mobile, d.login, d.pass,";
+        $sql.= " d.email, d.skype, d.phone, d.phone_perso, d.phone_mobile, d.login, d.pass, d.pass_crypted,";
         $sql.= " d.photo, d.fk_adherent_type, d.morphy, d.entity,";
         $sql.= " d.photo, d.fk_adherent_type, d.morphy, d.entity,";
         $sql.= " d.datec as datec,";
         $sql.= " d.datec as datec,";
         $sql.= " d.tms as datem,";
         $sql.= " d.tms as datem,";
@@ -1087,7 +1105,6 @@ class Adherent extends CommonObject
                 $this->firstname		= $obj->firstname;
                 $this->firstname		= $obj->firstname;
                 $this->lastname			= $obj->lastname;
                 $this->lastname			= $obj->lastname;
                 $this->login			= $obj->login;
                 $this->login			= $obj->login;
-                $this->pass				= $obj->pass;
                 $this->societe			= $obj->company;
                 $this->societe			= $obj->company;
                 $this->company			= $obj->company;
                 $this->company			= $obj->company;
                 $this->fk_soc			= $obj->fk_soc;
                 $this->fk_soc			= $obj->fk_soc;
@@ -1095,6 +1112,10 @@ class Adherent extends CommonObject
                 $this->zip				= $obj->zip;
                 $this->zip				= $obj->zip;
                 $this->town				= $obj->town;
                 $this->town				= $obj->town;
 
 
+                $this->pass				= $obj->pass;
+                $this->pass_indatabase  = $obj->pass;
+                $this->pass_indatabase_crypted = $obj->pass_crypted;
+                
                 $this->state_id			= $obj->state_id;
                 $this->state_id			= $obj->state_id;
                 $this->state_code		= $obj->state_id?$obj->state_code:'';
                 $this->state_code		= $obj->state_id?$obj->state_code:'';
                 $this->state			= $obj->state_id?$obj->state:'';
                 $this->state			= $obj->state_id?$obj->state:'';
@@ -1423,9 +1444,10 @@ class Adherent extends CommonObject
         $err=0;
         $err=0;
 
 
         // mailman
         // mailman
-        if (! empty($conf->global->ADHERENT_USE_MAILMAN))
+        if (! empty($conf->global->ADHERENT_USE_MAILMAN) && ! empty($conf->mailmanspip->enabled))
         {
         {
             $result=$mailmanspip->add_to_mailman($this);
             $result=$mailmanspip->add_to_mailman($this);
+         
             if ($result < 0)
             if ($result < 0)
             {
             {
             	if (! empty($mailmanspip->error)) $this->errors[]=$mailmanspip->error;
             	if (! empty($mailmanspip->error)) $this->errors[]=$mailmanspip->error;
@@ -1444,7 +1466,7 @@ class Adherent extends CommonObject
         }
         }
 
 
         // spip
         // spip
-        if ($conf->global->ADHERENT_USE_SPIP && ! empty($conf->mailmanspip->enabled))
+        if (! empty($conf->global->ADHERENT_USE_SPIP) && ! empty($conf->mailmanspip->enabled))
         {
         {
             $result=$mailmanspip->add_to_spip($this);
             $result=$mailmanspip->add_to_spip($this);
             if ($result < 0)
             if ($result < 0)
@@ -1458,7 +1480,7 @@ class Adherent extends CommonObject
             return -$err;
             return -$err;
         }
         }
         else
         else
-       {
+        {
             return 1;
             return 1;
         }
         }
     }
     }
@@ -1556,6 +1578,7 @@ class Adherent extends CommonObject
             $label.= '<br><b>' . $langs->trans('Name') . ':</b> ' . $this->getFullName($langs);
             $label.= '<br><b>' . $langs->trans('Name') . ':</b> ' . $this->getFullName($langs);
         $linkclose = '" title="'.dol_escape_htmltag($label, 1).'" class="classfortooltip">';
         $linkclose = '" title="'.dol_escape_htmltag($label, 1).'" class="classfortooltip">';
 
 
+        $link=''; $linkend='';
         if ($option == 'card')
         if ($option == 'card')
         {
         {
             $link = '<a href="'.DOL_URL_ROOT.'/adherents/card.php?rowid='.$this->id.$linkclose;
             $link = '<a href="'.DOL_URL_ROOT.'/adherents/card.php?rowid='.$this->id.$linkclose;

+ 1 - 1
htdocs/adherents/class/cotisation.class.php

@@ -213,7 +213,7 @@ class Cotisation extends CommonObject
 				$result=$member->fetch($this->fk_adherent);
 				$result=$member->fetch($this->fk_adherent);
 				$result=$member->update_end_date($user);
 				$result=$member->update_end_date($user);
 
 
-				if ($accountline->id > 0)						// If we found bank account line (this means this->fk_bank defined)
+				if (is_object($accountline) && $accountline->id > 0)						// If we found bank account line (this means this->fk_bank defined)
 				{
 				{
 					$result=$accountline->delete($user);		// Return false if refused because line is conciliated
 					$result=$accountline->delete($user);		// Return false if refused because line is conciliated
 					if ($result > 0)
 					if ($result > 0)

+ 4 - 2
htdocs/admin/company.php

@@ -308,10 +308,12 @@ if ($action == 'edit' || $action == 'updateedit')
 	print '<table class="noborder" width="100%">';
 	print '<table class="noborder" width="100%">';
 	print '<tr class="liste_titre"><th width="35%">'.$langs->trans("CompanyInfo").'</th><th>'.$langs->trans("Value").'</th></tr>'."\n";
 	print '<tr class="liste_titre"><th width="35%">'.$langs->trans("CompanyInfo").'</th><th>'.$langs->trans("Value").'</th></tr>'."\n";
 
 
+	// Name
 	$var=!$var;
 	$var=!$var;
 	print '<tr '.$bc[$var].'><td class="fieldrequired"><label for="name">'.$langs->trans("CompanyName").'</label></td><td>';
 	print '<tr '.$bc[$var].'><td class="fieldrequired"><label for="name">'.$langs->trans("CompanyName").'</label></td><td>';
 	print '<input name="nom" id="name" size="30" value="'. ($conf->global->MAIN_INFO_SOCIETE_NOM?$conf->global->MAIN_INFO_SOCIETE_NOM:$_POST["nom"]) . '" autofocus="autofocus"></td></tr>'."\n";
 	print '<input name="nom" id="name" size="30" value="'. ($conf->global->MAIN_INFO_SOCIETE_NOM?$conf->global->MAIN_INFO_SOCIETE_NOM:$_POST["nom"]) . '" autofocus="autofocus"></td></tr>'."\n";
 
 
+	// Addresse
 	$var=!$var;
 	$var=!$var;
 	print '<tr '.$bc[$var].'><td><label for="address">'.$langs->trans("CompanyAddress").'</label></td><td>';
 	print '<tr '.$bc[$var].'><td><label for="address">'.$langs->trans("CompanyAddress").'</label></td><td>';
 	print '<textarea name="address" id="address" class="quatrevingtpercent" rows="'.ROWS_3.'">'. ($conf->global->MAIN_INFO_SOCIETE_ADDRESS?$conf->global->MAIN_INFO_SOCIETE_ADDRESS:$_POST["address"]) . '</textarea></td></tr>'."\n";
 	print '<textarea name="address" id="address" class="quatrevingtpercent" rows="'.ROWS_3.'">'. ($conf->global->MAIN_INFO_SOCIETE_ADDRESS?$conf->global->MAIN_INFO_SOCIETE_ADDRESS:$_POST["address"]) . '</textarea></td></tr>'."\n";
@@ -392,7 +394,7 @@ if ($action == 'edit' || $action == 'updateedit')
 	// Note
 	// Note
 	$var=!$var;
 	$var=!$var;
 	print '<tr '.$bc[$var].'><td valign="top"><label for="note">'.$langs->trans("Note").'</label></td><td>';
 	print '<tr '.$bc[$var].'><td valign="top"><label for="note">'.$langs->trans("Note").'</label></td><td>';
-	print '<textarea class="flat" name="note" id="note" cols="80" rows="'.ROWS_5.'">'.(! empty($conf->global->MAIN_INFO_SOCIETE_NOTE) ? $conf->global->MAIN_INFO_SOCIETE_NOTE : '').'</textarea></td></tr>';
+	print '<textarea class="flat quatrevingtpercent" name="note" id="note" rows="'.ROWS_5.'">'.(! empty($conf->global->MAIN_INFO_SOCIETE_NOTE) ? $conf->global->MAIN_INFO_SOCIETE_NOTE : '').'</textarea></td></tr>';
 	print '</td></tr>';
 	print '</td></tr>';
 
 
 	print '</table>';
 	print '</table>';
@@ -531,7 +533,7 @@ if ($action == 'edit' || $action == 'updateedit')
 	// Object of the company
 	// Object of the company
 	$var=!$var;
 	$var=!$var;
 	print '<tr '.$bc[$var].'><td width="35%"><label for="object">'.$langs->trans("CompanyObject").'</label></td><td>';
 	print '<tr '.$bc[$var].'><td width="35%"><label for="object">'.$langs->trans("CompanyObject").'</label></td><td>';
-	print '<textarea class="flat" name="object" id="object" cols="80" rows="'.ROWS_5.'">'.(! empty($conf->global->MAIN_INFO_SOCIETE_OBJECT) ? $conf->global->MAIN_INFO_SOCIETE_OBJECT : '').'</textarea></td></tr>';
+	print '<textarea class="flat quatrevingtpercent" name="object" id="object" rows="'.ROWS_5.'">'.(! empty($conf->global->MAIN_INFO_SOCIETE_OBJECT) ? $conf->global->MAIN_INFO_SOCIETE_OBJECT : '').'</textarea></td></tr>';
 	print '</td></tr>';
 	print '</td></tr>';
 
 
 	print '</table>';
 	print '</table>';

+ 36 - 5
htdocs/admin/menus/edit.php

@@ -62,6 +62,23 @@ if ($action == 'update')
 {
 {
     if (! $_POST['cancel'])
     if (! $_POST['cancel'])
     {
     {
+        $leftmenu=''; $mainmenu='';
+        if (! empty($_POST['menuIdParent']) && ! is_numeric($_POST['menuIdParent']))
+        {
+            $tmp=explode('&',$_POST['menuIdParent']);
+            foreach($tmp as $s)
+            {
+                if (preg_match('/fk_mainmenu=/',$s))
+                {
+                    $mainmenu=preg_replace('/fk_mainmenu=/','',$s);
+                }
+                if (preg_match('/fk_leftmenu=/',$s))
+                {
+                    $leftmenu=preg_replace('/fk_leftmenu=/','',$s);
+                }
+            }
+        }
+        
         $menu = new Menubase($db);
         $menu = new Menubase($db);
         $result=$menu->fetch($_POST['menuId']);
         $result=$menu->fetch($_POST['menuId']);
         if ($result > 0)
         if ($result > 0)
@@ -75,7 +92,18 @@ if ($action == 'update')
             $menu->perms=$_POST['perms'];
             $menu->perms=$_POST['perms'];
             $menu->target=$_POST['target'];
             $menu->target=$_POST['target'];
             $menu->user=$_POST['user'];
             $menu->user=$_POST['user'];
-            $menu->fk_menu=$_POST['fk_menu'];
+            if (is_numeric($_POST['menuIdParent']))
+            {
+            	$menu->fk_menu=$_POST['menuIdParent'];
+            }
+            else
+            {
+    	       	if ($_POST['type'] == 'top') $menu->fk_menu=0;
+    	       	else $menu->fk_menu=-1;
+            	$menu->fk_mainmenu=$mainmenu;
+            	$menu->fk_leftmenu=$leftmenu;
+            }
+
             $result=$menu->update($user);
             $result=$menu->update($user);
             if ($result > 0)
             if ($result > 0)
             {
             {
@@ -342,7 +370,7 @@ if ($action == 'create')
     }
     }
     else
     else
     {
     {
-        print '<td><input type="text" size="20" id="menuId" name="menuId" value="'.($_POST["menuId"]?$_POST["menuId"]:'').'"></td>';
+        print '<td><input type="text" size="40" id="menuId" name="menuId" value="'.($_POST["menuId"]?$_POST["menuId"]:'').'"></td>';
     }
     }
     print '<td>'.$langs->trans('DetailMenuIdParent');
     print '<td>'.$langs->trans('DetailMenuIdParent');
     print ', '.$langs->trans("Example").': fk_mainmenu=abc&fk_leftmenu=def';
     print ', '.$langs->trans("Example").': fk_mainmenu=abc&fk_leftmenu=def';
@@ -425,12 +453,15 @@ elseif ($action == 'edit')
     print '<tr><td class="fieldrequired">'.$langs->trans('Type').'</td><td>'.$langs->trans(ucfirst($menu->type)).'</td><td>'.$langs->trans('DetailType').'</td></tr>';
     print '<tr><td class="fieldrequired">'.$langs->trans('Type').'</td><td>'.$langs->trans(ucfirst($menu->type)).'</td><td>'.$langs->trans('DetailType').'</td></tr>';
 
 
     // MenuId Parent
     // MenuId Parent
-    print '<tr><td class="fieldrequired">'.$langs->trans('MenuIdParent').'</td>';
+    print '<tr><td class="fieldrequired">'.$langs->trans('MenuIdParent');
+    print '</td>';
     $valtouse=$menu->fk_menu;
     $valtouse=$menu->fk_menu;
     if ($menu->fk_mainmenu) $valtouse='fk_mainmenu='.$menu->fk_mainmenu;
     if ($menu->fk_mainmenu) $valtouse='fk_mainmenu='.$menu->fk_mainmenu;
     if ($menu->fk_leftmenu) $valtouse.='&fk_leftmenu='.$menu->fk_leftmenu;
     if ($menu->fk_leftmenu) $valtouse.='&fk_leftmenu='.$menu->fk_leftmenu;
-    print '<td><input type="text" name="fk_menu" value="'.$valtouse.'" size="10"></td>';
-    print '<td>'.$langs->trans('DetailMenuIdParent').'</td></tr>';
+    print '<td><input type="text" name="menuIdParent" value="'.$valtouse.'" size="40"></td>';
+    print '<td>'.$langs->trans('DetailMenuIdParent');
+    print ', '.$langs->trans("Example").': fk_mainmenu=abc&fk_leftmenu=def';
+    print '</td></tr>';
 
 
     // Niveau
     // Niveau
     //print '<tr><td>'.$langs->trans('Level').'</td><td>'.$menu->level.'</td><td>'.$langs->trans('DetailLevel').'</td></tr>';
     //print '<tr><td>'.$langs->trans('Level').'</td><td>'.$menu->level.'</td><td>'.$langs->trans('DetailLevel').'</td></tr>';

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

@@ -361,7 +361,7 @@ if ($conf->use_javascript_ajax)
 	
 	
 	if (count($remainingdata))
 	if (count($remainingdata))
 	{
 	{
-    	print '<table class="border" width="100%">';
+    	print '<table class="noborder centpercent">';
     	
     	
     	print '<tr class="liste_titre">';
     	print '<tr class="liste_titre">';
     	print '<td>'.$langs->trans("NotTopTreeMenuPersonalized").'</td>';
     	print '<td>'.$langs->trans("NotTopTreeMenuPersonalized").'</td>';

+ 38 - 12
htdocs/admin/tools/export.php

@@ -53,6 +53,8 @@ if ($file && ! $what)
     exit;
     exit;
 }
 }
 
 
+$errormsg='';
+
 
 
 /*
 /*
  * Actions
  * Actions
@@ -120,16 +122,37 @@ if ($what == 'mysql')
 {
 {
     
     
     $cmddump=GETPOST("mysqldump");	// Do not sanitize here with 'alpha', will be sanitize later by escapeshellarg
     $cmddump=GETPOST("mysqldump");	// Do not sanitize here with 'alpha', will be sanitize later by escapeshellarg
-    if ($cmddump)
+    if (! empty($dolibarr_main_restrict_os_commands))
+    {
+        $arrayofallowedcommand=explode(',', $dolibarr_main_restrict_os_commands);
+        $ok=0;
+        dol_syslog("Command are restricted to ".$dolibarr_main_restrict_os_commands.". We check that on of this command is inside ".$cmddump);
+        foreach($arrayofallowedcommand as $allowedcommand)
+        {
+            if (preg_match('/'.preg_quote($allowedcommand,'/').'/', $cmddump))
+            {
+                $ok=1;
+                break;
+            }
+        }
+        if (! $ok)
+        {
+            $errormsg=$langs->trans('CommandIsNotInsideAllowedCommands');
+        }
+    }
+    
+    if (! $errormsg && $cmddump)
     {
     {
         dolibarr_set_const($db, 'SYSTEMTOOLS_MYSQLDUMP', $cmddump,'chaine',0,'',$conf->entity);
         dolibarr_set_const($db, 'SYSTEMTOOLS_MYSQLDUMP', $cmddump,'chaine',0,'',$conf->entity);
     }
     }
 
 
-    $utils->dumpDatabase(GETPOST('compression','alpha'), $what, 0, $file);
-    
-    $errormsg=$utils->error;
-    $_SESSION["commandbackuplastdone"]=$utils->result['commandbackuplastdone'];
-    $_SESSION["commandbackuptorun"]=$utils->result['commandbackuptorun'];
+    if (! $errormsg) 
+    {
+        $utils->dumpDatabase(GETPOST('compression','alpha'), $what, 0, $file);
+        $errormsg=$utils->error;
+        $_SESSION["commandbackuplastdone"]=$utils->result['commandbackuplastdone'];
+        $_SESSION["commandbackuptorun"]=$utils->result['commandbackuptorun'];
+    }
 }
 }
 
 
 // MYSQL NO BIN
 // MYSQL NO BIN
@@ -146,16 +169,19 @@ if ($what == 'mysqlnobin')
 if ($what == 'postgresql')
 if ($what == 'postgresql')
 {
 {
     $cmddump=GETPOST("postgresqldump");	// Do not sanitize here with 'alpha', will be sanitize later by escapeshellarg
     $cmddump=GETPOST("postgresqldump");	// Do not sanitize here with 'alpha', will be sanitize later by escapeshellarg
-    if ($cmddump)
+    
+    if (! $errormsg && $cmddump)
     {
     {
         dolibarr_set_const($db, 'SYSTEMTOOLS_POSTGRESQLDUMP', $cmddump,'chaine',0,'',$conf->entity);
         dolibarr_set_const($db, 'SYSTEMTOOLS_POSTGRESQLDUMP', $cmddump,'chaine',0,'',$conf->entity);
     }
     }
 
 
-    $utils->dumpDatabase(GETPOST('compression','alpha'), $what, 0, $file);
-    
-    $errormsg=$utils->error;
-    $_SESSION["commandbackuplastdone"]=$utils->result['commandbackuplastdone'];
-    $_SESSION["commandbackuptorun"]=$utils->result['commandbackuptorun'];
+    if (! $errormsg) 
+    {
+        $utils->dumpDatabase(GETPOST('compression','alpha'), $what, 0, $file);
+        $errormsg=$utils->error;
+        $_SESSION["commandbackuplastdone"]=$utils->result['commandbackuplastdone'];
+        $_SESSION["commandbackuptorun"]=$utils->result['commandbackuptorun'];
+    }
 
 
     $what='';   // Clear to show message to run command
     $what='';   // Clear to show message to run command
 }
 }

+ 1 - 1
htdocs/cashdesk/include/environnement.php

@@ -44,7 +44,7 @@ $conf_fkaccount_cb = (! empty($_SESSION["CASHDESK_ID_BANKACCOUNT_CB"]))?$_SESSIO
 
 
 
 
 // View parameters
 // View parameters
-$conf_taille_listes = (empty($conf->global->PRODUIT_LIMIT_SIZE)?500:$conf->global->PRODUIT_LIMIT_SIZE);	// Nombre max de lignes a afficher dans les listes
+$conf_taille_listes = (empty($conf->global->PRODUIT_LIMIT_SIZE)?1000:$conf->global->PRODUIT_LIMIT_SIZE);	// Nombre max de lignes a afficher dans les listes
 $conf_nbr_car_listes = 60;	// Nombre max de caracteres par ligne dans les listes
 $conf_nbr_car_listes = 60;	// Nombre max de caracteres par ligne dans les listes
 
 
 // Add hidden option to force decrease of stock whatever is user setup
 // Add hidden option to force decrease of stock whatever is user setup

+ 2 - 1
htdocs/categories/categorie.php

@@ -617,13 +617,14 @@ else if ($id || $ref)
  * 	@param		Object		$object				Object we want to see categories it can be classified into
  * 	@param		Object		$object				Object we want to see categories it can be classified into
  * 	@param		int			$typeid				Type of category (0, 1, 2, 3)
  * 	@param		int			$typeid				Type of category (0, 1, 2, 3)
  *  @param		int			$socid				Id thirdparty
  *  @param		int			$socid				Id thirdparty
- *  @param		int		$showclassifyform	1=Add form to 'Classify', 0=Do not show form to 'Classify'
+ *  @param		int		    $showclassifyform	1=Add form to 'Classify', 0=Do not show form to 'Classify'
  *  @return		int			0
  *  @return		int			0
  */
  */
 function formCategory($db,$object,$typeid,$socid=0,$showclassifyform=1)
 function formCategory($db,$object,$typeid,$socid=0,$showclassifyform=1)
 {
 {
 	global $user,$langs,$form,$bc;
 	global $user,$langs,$form,$bc;
 
 
+	$title='NotDefined';
 	if ($typeid == Categorie::TYPE_PRODUCT)     $title = $langs->trans("ProductsCategoriesShort");
 	if ($typeid == Categorie::TYPE_PRODUCT)     $title = $langs->trans("ProductsCategoriesShort");
 	if ($typeid == Categorie::TYPE_SUPPLIER)    $title = $langs->trans("SuppliersCategoriesShort");
 	if ($typeid == Categorie::TYPE_SUPPLIER)    $title = $langs->trans("SuppliersCategoriesShort");
 	if ($typeid == Categorie::TYPE_CUSTOMER)    $title = $langs->trans("CustomersProspectsCategoriesShort");
 	if ($typeid == Categorie::TYPE_CUSTOMER)    $title = $langs->trans("CustomersProspectsCategoriesShort");

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

@@ -43,13 +43,13 @@ require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
 class Categorie extends CommonObject
 class Categorie extends CommonObject
 {
 {
 	// Categories types
 	// Categories types
-	const TYPE_PRODUCT = 0;
-	const TYPE_SUPPLIER = 1;
-	const TYPE_CUSTOMER = 2;
-	const TYPE_MEMBER = 3;
-	const TYPE_CONTACT = 4;
-	const TYPE_USER = 4;    // categorie contact and user are same !
-    const TYPE_ACCOUNT = 5; // bank account
+	const TYPE_PRODUCT = 0;    // TODO Replace with value 'product'
+	const TYPE_SUPPLIER = 1;   // TODO Replace this value with 'supplier'
+	const TYPE_CUSTOMER = 2;   // TODO Replace this value with 'customer'
+	const TYPE_MEMBER = 3;     // TODO Replace this value with 'member'
+	const TYPE_CONTACT = 4;    // TODO Replace this value with 'contact'
+	const TYPE_USER = 4;       // categorie contact and user are same !   TODO Replace this value with 'user'
+    const TYPE_ACCOUNT = 5;    // for bank account TODO Replace this value with 'account'
 
 
 	/**
 	/**
 	 * @var array ID mapping from type string
 	 * @var array ID mapping from type string
@@ -63,7 +63,7 @@ class Categorie extends CommonObject
 		'member'   => 3,
 		'member'   => 3,
 		'contact'  => 4,
 		'contact'  => 4,
 		'user'     => 4,
 		'user'     => 4,
-        'account' => 5,
+        'account'  => 5,
 	);
 	);
 	/**
 	/**
 	 * @var array Foreign keys mapping from type string
 	 * @var array Foreign keys mapping from type string

+ 1 - 1
htdocs/comm/action/class/ical.class.php

@@ -208,7 +208,7 @@ class ICal
 
 
         //print 'type='.$type.' key='.$key.' value='.$value.'<br>'."\n";
         //print 'type='.$type.' key='.$key.' value='.$value.'<br>'."\n";
 
 
-        if ($key == false)
+        if (empty($key))
         {
         {
             $key = $this->last_key;
             $key = $this->last_key;
             switch ($type)
             switch ($type)

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

@@ -2611,7 +2611,8 @@ class Propal extends CommonObject
     {
     {
         global $langs;
         global $langs;
 
 
-        // Charge tableau des produits prodids
+        // Load array of products prodids
+        $num_prods = 0;
         $prodids = array();
         $prodids = array();
         $sql = "SELECT rowid";
         $sql = "SELECT rowid";
         $sql.= " FROM ".MAIN_DB_PREFIX."product";
         $sql.= " FROM ".MAIN_DB_PREFIX."product";

+ 5 - 15
htdocs/commande/class/commande.class.php

@@ -449,6 +449,8 @@ class Commande extends CommonOrder
             // If stock is decremented on validate order, we must reincrement it
             // If stock is decremented on validate order, we must reincrement it
             if (! empty($conf->stock->enabled) && $conf->global->STOCK_CALCULATE_ON_VALIDATE_ORDER == 1)
             if (! empty($conf->stock->enabled) && $conf->global->STOCK_CALCULATE_ON_VALIDATE_ORDER == 1)
             {
             {
+                $result = 0;
+                
                 require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
                 require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
                 $langs->load("agenda");
                 $langs->load("agenda");
 
 
@@ -460,22 +462,9 @@ class Commande extends CommonOrder
                         $mouvP = new MouvementStock($this->db);
                         $mouvP = new MouvementStock($this->db);
                         // We increment stock of product (and sub-products)
                         // We increment stock of product (and sub-products)
                         $result=$mouvP->reception($user, $this->lines[$i]->fk_product, $idwarehouse, $this->lines[$i]->qty, 0, $langs->trans("OrderBackToDraftInDolibarr",$this->ref));
                         $result=$mouvP->reception($user, $this->lines[$i]->fk_product, $idwarehouse, $this->lines[$i]->qty, 0, $langs->trans("OrderBackToDraftInDolibarr",$this->ref));
-                        if ($result < 0) { $error++; }
+                        if ($result < 0) { $error++; $this->error=$mouvP->error; break; }
                     }
                     }
                 }
                 }
-
-                if (!$error)
-                {
-                    $this->statut=self::STATUS_DRAFT;
-                    $this->db->commit();
-                    return $result;
-                }
-                else
-                {
-                    $this->error=$mouvP->error;
-                    $this->db->rollback();
-                    return $result;
-                }
             }
             }
 
 
             if (!$error) {
             if (!$error) {
@@ -3258,7 +3247,8 @@ class Commande extends CommonOrder
 
 
         dol_syslog(get_class($this)."::initAsSpecimen");
         dol_syslog(get_class($this)."::initAsSpecimen");
 
 
-        // Charge tableau des produits prodids
+        // Load array of products prodids
+        $num_prods = 0;
         $prodids = array();
         $prodids = array();
         $sql = "SELECT rowid";
         $sql = "SELECT rowid";
         $sql.= " FROM ".MAIN_DB_PREFIX."product";
         $sql.= " FROM ".MAIN_DB_PREFIX."product";

+ 1 - 1
htdocs/commande/orderstoinvoice.php

@@ -72,7 +72,7 @@ $date_endy = dol_mktime(23,59,59,$_REQUEST["date_end_delymonth"],$_REQUEST["date
 
 
 if ($action == 'create')
 if ($action == 'create')
 {
 {
-	if (is_array($selected) == false)
+	if (! is_array($selected))
 	{
 	{
 		$error++;
 		$error++;
 		setEventMessages($langs->trans('Error_OrderNotChecked'), null, 'errors');
 		setEventMessages($langs->trans('Error_OrderNotChecked'), null, 'errors');

+ 12 - 14
htdocs/compta/bank/card.php

@@ -89,8 +89,7 @@ if ($_POST["action"] == 'add')
     $account->proprio 	      = trim($_POST["proprio"]);
     $account->proprio 	      = trim($_POST["proprio"]);
     $account->owner_address   = trim($_POST["owner_address"]);
     $account->owner_address   = trim($_POST["owner_address"]);
 
 
-	if (GETPOST('account_number') <= 0) { $accountancy_code_number = ''; } else { $accountancy_code_number = GETPOST('account_number'); }
-    $account->account_number  = $accountancy_code_number;
+    $account->account_number  = GETPOST('account_number');
 	$account->accountancy_journal  = trim($_POST["accountancy_journal"]);
 	$account->accountancy_journal  = trim($_POST["accountancy_journal"]);
 
 
     $account->solde           = $_POST["solde"];
     $account->solde           = $_POST["solde"];
@@ -172,8 +171,7 @@ if ($_POST["action"] == 'update' && ! $_POST["cancel"])
     $account->proprio 	      = trim($_POST["proprio"]);
     $account->proprio 	      = trim($_POST["proprio"]);
     $account->owner_address   = trim($_POST["owner_address"]);
     $account->owner_address   = trim($_POST["owner_address"]);
 
 
-    if (GETPOST('account_number') <= 0) { $accountancy_code_number = ''; } else { $accountancy_code_number = GETPOST('account_number'); }
-    $account->account_number  = $accountancy_code_number;
+    $account->account_number  = GETPOST('account_number');
 	$account->accountancy_journal = trim($_POST["accountancy_journal"]);
 	$account->accountancy_journal = trim($_POST["accountancy_journal"]);
 
 
     $account->currency_code   = trim($_POST["account_currency_code"]);
     $account->currency_code   = trim($_POST["account_currency_code"]);
@@ -287,7 +285,7 @@ if ($action == 'create')
 
 
 	// Ref
 	// Ref
 	print '<tr><td class="fieldrequired titlefieldcreate">'.$langs->trans("Ref").'</td>';
 	print '<tr><td class="fieldrequired titlefieldcreate">'.$langs->trans("Ref").'</td>';
-	print '<td colspan="3"><input size="8" type="text" class="flat" name="ref" value="'.($_POST["ref"]?$_POST["ref"]:$account->ref).'" maxlength="12"></td></tr>';
+	print '<td colspan="3"><input size="8" type="text" class="flat" name="ref" value="'.(GETPOST("ref")?GETPOST("ref",'alpha'):$account->ref).'" maxlength="12"></td></tr>';
 
 
 	// Label
 	// Label
 	print '<tr><td class="fieldrequired">'.$langs->trans("LabelBankCashAccount").'</td>';
 	print '<tr><td class="fieldrequired">'.$langs->trans("LabelBankCashAccount").'</td>';
@@ -393,10 +391,10 @@ if ($action == 'create')
 	print '</td></tr>';
 	print '</td></tr>';
 
 
 	print '<tr><td>'.$langs->trans("BalanceMinimalAllowed").'</td>';
 	print '<tr><td>'.$langs->trans("BalanceMinimalAllowed").'</td>';
-	print '<td colspan="3"><input size="12" type="text" class="flat" name="account_min_allowed" value="'.($_POST["account_min_allowed"]?$_POST["account_min_allowed"]:$account->min_allowed).'"></td></tr>';
+	print '<td colspan="3"><input size="12" type="text" class="flat" name="account_min_allowed" value="'.(GETPOST("account_min_allowed")?GETPOST("account_min_allowed"):$account->min_allowed).'"></td></tr>';
 
 
 	print '<tr><td>'.$langs->trans("BalanceMinimalDesired").'</td>';
 	print '<tr><td>'.$langs->trans("BalanceMinimalDesired").'</td>';
-	print '<td colspan="3"><input size="12" type="text" class="flat" name="account_min_desired" value="'.($_POST["account_min_desired"]?$_POST["account_min_desired"]:$account->min_desired).'"></td></tr>';
+	print '<td colspan="3"><input size="12" type="text" class="flat" name="account_min_desired" value="'.(GETPOST("account_min_desired")?GETPOST("account_min_desired"):$account->min_desired).'"></td></tr>';
 
 
 	print '</table>';
 	print '</table>';
 	print '<br>';
 	print '<br>';
@@ -407,7 +405,7 @@ if ($action == 'create')
 
 
 		// If bank account
 		// If bank account
 		print '<tr><td class="titlefieldcreate">'.$langs->trans("BankName").'</td>';
 		print '<tr><td class="titlefieldcreate">'.$langs->trans("BankName").'</td>';
-		print '<td colspan="3"><input size="30" type="text" class="flat" name="bank" value="'.$account->bank.'"></td>';
+		print '<td colspan="3"><input size="30" type="text" class="flat" name="bank" value="'.(GETPOST('bank')?GETPOST('bank','alpha'):$account->bank).'"></td>';
 		print '</tr>';
 		print '</tr>';
 
 
 		// Show fields of bank account
 		// Show fields of bank account
@@ -431,7 +429,7 @@ if ($action == 'create')
 			}
 			}
 
 
 			print '<td>'.$langs->trans($val).'</td>';
 			print '<td>'.$langs->trans($val).'</td>';
-			print '<td><input size="'.$size.'" type="text" class="flat" name="'.$name.'" value="'.$content.'"></td>';
+			print '<td><input size="'.$size.'" type="text" class="flat" name="'.$name.'" value="'.(GETPOST($name)?GETPOST($name,'alpha'):$content).'"></td>';
 			print '</tr>';
 			print '</tr>';
 		}
 		}
 		$ibankey = FormBank::getIBANLabel($account);
 		$ibankey = FormBank::getIBANLabel($account);
@@ -440,23 +438,23 @@ if ($action == 'create')
 
 
 		// IBAN
 		// IBAN
 		print '<tr><td>'.$langs->trans($ibankey).'</td>';
 		print '<tr><td>'.$langs->trans($ibankey).'</td>';
-		print '<td colspan="3"><input size="34" maxlength="34" type="text" class="flat" name="iban" value="'.$account->iban.'"></td></tr>';
+		print '<td colspan="3"><input size="34" maxlength="34" type="text" class="flat" name="iban" value="'.(GETPOST('iban')?GETPOST('iban','alpha'):$account->iban).'"></td></tr>';
 
 
 		print '<tr><td>'.$langs->trans($bickey).'</td>';
 		print '<tr><td>'.$langs->trans($bickey).'</td>';
-		print '<td colspan="3"><input size="11" maxlength="11" type="text" class="flat" name="bic" value="'.$account->bic.'"></td></tr>';
+		print '<td colspan="3"><input size="11" maxlength="11" type="text" class="flat" name="bic" value="'.(GETPOST('bic')?GETPOST('bic','alpha'):$account->bic).'"></td></tr>';
 
 
 		print '<tr><td>'.$langs->trans("BankAccountDomiciliation").'</td><td colspan="3">';
 		print '<tr><td>'.$langs->trans("BankAccountDomiciliation").'</td><td colspan="3">';
 		print "<textarea class=\"flat\" name=\"domiciliation\" rows=\"2\" cols=\"40\">";
 		print "<textarea class=\"flat\" name=\"domiciliation\" rows=\"2\" cols=\"40\">";
-		print $account->domiciliation;
+		print (GETPOST('domiciliation')?GETPOST('domiciliation'):$account->domiciliation);
 		print "</textarea></td></tr>";
 		print "</textarea></td></tr>";
 
 
 		print '<tr><td>'.$langs->trans("BankAccountOwner").'</td>';
 		print '<tr><td>'.$langs->trans("BankAccountOwner").'</td>';
-		print '<td colspan="3"><input size="30" type="text" class="flat" name="proprio" value="'.$account->proprio.'">';
+		print '<td colspan="3"><input size="30" type="text" class="flat" name="proprio" value="'.(GETPOST('proprio')?GETPOST('proprio','alpha'):$account->proprio).'">';
 		print '</td></tr>';
 		print '</td></tr>';
 
 
 		print '<tr><td class="tdtop">'.$langs->trans("BankAccountOwnerAddress").'</td><td colspan="3">';
 		print '<tr><td class="tdtop">'.$langs->trans("BankAccountOwnerAddress").'</td><td colspan="3">';
 		print "<textarea class=\"flat\" name=\"owner_address\" rows=\"2\" cols=\"40\">";
 		print "<textarea class=\"flat\" name=\"owner_address\" rows=\"2\" cols=\"40\">";
-		print $account->owner_address;
+		print (GETPOST('owner_address')?GETPOST('owner_address','alpha'):$account->owner_address);
 		print "</textarea></td></tr>";
 		print "</textarea></td></tr>";
 
 
 		print '</table>';
 		print '</table>';

+ 24 - 18
htdocs/compta/bank/index.php

@@ -45,16 +45,9 @@ $statut=GETPOST('statut');
  * View
  * View
  */
  */
 
 
-$help_url='EN:Module_Banks_and_Cash|FR:Module_Banques_et_Caisses|ES:M&oacute;dulo_Bancos_y_Cajas';
-llxHeader('',$langs->trans('AccountsArea'),$help_url);
-
-$link='';
-if ($statut == '') $link='<a href="'.$_SERVER["PHP_SELF"].'?statut=all">'.$langs->trans("IncludeClosedAccount").'</a>';
-if ($statut == 'all') $link='<a href="'.$_SERVER["PHP_SELF"].'">'.$langs->trans("OnlyOpenedAccount").'</a>';
-print load_fiche_titre($langs->trans("AccountsArea"),$link, 'title_bank.png');
+$title=$langs->trans('BankAccounts');
 
 
-
-// On charge tableau des comptes financiers (ouverts par defaut)
+// Load array of financial accounts (opened by default)
 $accounts = array();
 $accounts = array();
 
 
 $sql  = "SELECT rowid, courant, rappro";
 $sql  = "SELECT rowid, courant, rappro";
@@ -66,17 +59,30 @@ $sql.= $db->order('label', 'ASC');
 $resql = $db->query($sql);
 $resql = $db->query($sql);
 if ($resql)
 if ($resql)
 {
 {
-	$num = $db->num_rows($resql);
-	$i = 0;
-	while ($i < $num)
-	{
-		$objp = $db->fetch_object($resql);
-		$accounts[$objp->rowid] = $objp->courant;
-		$i++;
-	}
-	$db->free($resql);
+    $num = $db->num_rows($resql);
+    $i = 0;
+    while ($i < $num)
+    {
+        $objp = $db->fetch_object($resql);
+        $accounts[$objp->rowid] = $objp->courant;
+        $i++;
+    }
+    $db->free($resql);
 }
 }
 
 
+$nbtotalofrecords = $num;
+
+
+$help_url='EN:Module_Banks_and_Cash|FR:Module_Banques_et_Caisses|ES:M&oacute;dulo_Bancos_y_Cajas';
+llxHeader('',$title,$help_url);
+
+$link='';
+if ($statut == '') $link='<a href="'.$_SERVER["PHP_SELF"].'?statut=all">'.$langs->trans("IncludeClosedAccount").'</a>';
+if ($statut == 'all') $link='<a href="'.$_SERVER["PHP_SELF"].'">'.$langs->trans("OnlyOpenedAccount").'</a>';
+
+print_barre_liste($title,$page,$_SERVER["PHP_SELF"],$param,$sortfield,$sortorder,$link,$num,$nbtotalofrecords,'title_bank.png',0,'','',$limit, 1);
+
+
 
 
 /*
 /*
  * Comptes courants (courant = 1)
  * Comptes courants (courant = 1)

+ 108 - 2
htdocs/compta/facture/class/facture-rec.class.php

@@ -509,7 +509,7 @@ class FactureRec extends CommonInvoice
 	    
 	    
 		$facid=$this->id;
 		$facid=$this->id;
 
 
-		dol_syslog("FactureRec::addline facid=$facid,desc=$desc,pu_ht=$pu_ht,qty=$qty,txtva=$txtva,fk_product=$fk_product,remise_percent=$remise_percent,date_start=$date_start,date_end=$date_end,ventil=$ventil,info_bits=$info_bits,fk_remise_except=$fk_remise_except,price_base_type=$price_base_type,pu_ttc=$pu_ttc,type=$type,fk_unit=$fk_unit", LOG_DEBUG);
+		dol_syslog(get_class($this)."::addline facid=$facid,desc=$desc,pu_ht=$pu_ht,qty=$qty,txtva=$txtva,fk_product=$fk_product,remise_percent=$remise_percent,info_bits=$info_bits,fk_remise_except=$fk_remise_except,price_base_type=$price_base_type,pu_ttc=$pu_ttc,type=$type,fk_unit=$fk_unit", LOG_DEBUG);
 		include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
 		include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
 
 
 		// Check parameters
 		// Check parameters
@@ -604,6 +604,111 @@ class FactureRec extends CommonInvoice
 		}
 		}
 	}
 	}
 
 
+	/**
+	 * 	Update a line to invoice
+	 *
+	 *  @param     	int			$rowid           	Id of line to update
+	 *	@param    	string		$desc            	Description de la ligne
+	 *	@param    	double		$pu_ht              Prix unitaire HT (> 0 even for credit note)
+	 *	@param    	double		$qty             	Quantite
+	 *	@param    	double		$txtva           	Taux de tva force, sinon -1
+	 *	@param    	int			$fk_product      	Id du produit/service predefini
+	 *	@param    	double		$remise_percent  	Pourcentage de remise de la ligne
+	 *	@param		string		$price_base_type	HT or TTC
+	 *	@param    	int			$info_bits			Bits de type de lignes
+	 *	@param    	int			$fk_remise_except	Id remise
+	 *	@param    	double		$pu_ttc             Prix unitaire TTC (> 0 even for credit note)
+	 *	@param		int			$type				Type of line (0=product, 1=service)
+	 *	@param      int			$rang               Position of line
+	 *	@param		int			$special_code		Special code
+	 *	@param		string		$label				Label of the line
+	 *	@param		string		$fk_unit			Unit
+	 *	@return    	int             				<0 if KO, Id of line if OK
+	 */
+	function updateline($rowid, $desc, $pu_ht, $qty, $txtva, $fk_product=0, $remise_percent=0, $price_base_type='HT', $info_bits=0, $fk_remise_except='', $pu_ttc=0, $type=0, $rang=-1, $special_code=0, $label='', $fk_unit=null)
+	{
+	    global $mysoc;
+	     
+	    $facid=$this->id;
+	
+	    dol_syslog(get_class($this)."::updateline facid=".$facid." rowid=$rowid,desc=$desc,pu_ht=$pu_ht,qty=$qty,txtva=$txtva,fk_product=$fk_product,remise_percent=$remise_percent,info_bits=$info_bits,fk_remise_except=$fk_remise_except,price_base_type=$price_base_type,pu_ttc=$pu_ttc,type=$type,fk_unit=$fk_unit", LOG_DEBUG);
+	    include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
+	
+	    // Check parameters
+	    if ($type < 0) return -1;
+	
+	    if ($this->brouillon)
+	    {
+	        // Clean parameters
+	        $remise_percent=price2num($remise_percent);
+	        $qty=price2num($qty);
+	        if (! $qty) $qty=1;
+	        if (! $info_bits) $info_bits=0;
+	        $pu_ht=price2num($pu_ht);
+	        $pu_ttc=price2num($pu_ttc);
+	        $txtva=price2num($txtva);
+	
+	        if ($price_base_type=='HT')
+	        {
+	            $pu=$pu_ht;
+	        }
+	        else
+	        {
+	            $pu=$pu_ttc;
+	        }
+	
+	        // Calcul du total TTC et de la TVA pour la ligne a partir de
+	        // qty, pu, remise_percent et txtva
+	        // TRES IMPORTANT: C'est au moment de l'insertion ligne qu'on doit stocker
+	        // la part ht, tva et ttc, et ce au niveau de la ligne qui a son propre taux tva.
+	        $tabprice=calcul_price_total($qty, $pu, $remise_percent, $txtva, 0, 0, 0, $price_base_type, $info_bits, $type, $mysoc);
+	        $total_ht  = $tabprice[0];
+	        $total_tva = $tabprice[1];
+	        $total_ttc = $tabprice[2];
+	        	
+	        $product_type=$type;
+	        if ($fk_product)
+	        {
+	            $product=new Product($this->db);
+	            $result=$product->fetch($fk_product);
+	            $product_type=$product->type;
+	        }
+	
+	        $sql = "UPDATE ".MAIN_DB_PREFIX."facturedet_rec SET ";
+	        $sql.= "fk_facture = '".$facid."'";
+	        $sql.= ", label=".(! empty($label)?"'".$this->db->escape($label)."'":"null");
+	        $sql.= ", description='".$this->db->escape($desc)."'";
+	        $sql.= ", price=".price2num($pu_ht);
+	        $sql.= ", qty=".price2num($qty);
+	        $sql.= ", tva_tx=".price2num($txtva);
+	        $sql.= ", fk_product=".(! empty($fk_product)?"'".$fk_product."'":"null");
+	        $sql.= ", product_type=".$product_type;
+	        $sql.= ", remise_percent='".price2num($remise_percent)."'";
+	        $sql.= ", subprice='".price2num($pu_ht)."'";
+	        $sql.= ", total_ht='".price2num($total_ht)."'";
+	        $sql.= ", total_tva='".price2num($total_tva)."'";
+	        $sql.= ", total_ttc='".price2num($total_ttc)."'";
+	        $sql.= ", rang=".$rang;
+	        $sql.= ", special_code=".$special_code;
+	        $sql.= ", fk_unit=".($fk_unit?"'".$this->db->escape($fk_unit)."'":"null");
+	        $sql.= " WHERE rowid = ".$rowid;
+	        
+	        dol_syslog(get_class($this)."::updateline", LOG_DEBUG);
+	        if ($this->db->query($sql))
+	        {
+	            $this->id=$facid;
+	            $this->update_price();
+	            return 1;
+	        }
+	        else
+	        {
+	            $this->error=$this->db->lasterror();
+	            return -1;
+	        }
+	    }
+	}	
+	
+	
 	/**
 	/**
 	 * Return the next date of 
 	 * Return the next date of 
 	 * 
 	 * 
@@ -760,8 +865,9 @@ class FactureRec extends CommonInvoice
 		$arraynow=dol_getdate($now);
 		$arraynow=dol_getdate($now);
 		$nownotime=dol_mktime(0, 0, 0, $arraynow['mon'], $arraynow['mday'], $arraynow['year']);
 		$nownotime=dol_mktime(0, 0, 0, $arraynow['mon'], $arraynow['mday'], $arraynow['year']);
 
 
-		$prodids = array();
+        // Load array of products prodids
 		$num_prods = 0;
 		$num_prods = 0;
+		$prodids = array();
 		
 		
 		$sql = "SELECT rowid";
 		$sql = "SELECT rowid";
 		$sql.= " FROM ".MAIN_DB_PREFIX."product";
 		$sql.= " FROM ".MAIN_DB_PREFIX."product";

+ 2 - 0
htdocs/compta/facture/class/facture.class.php

@@ -3537,6 +3537,8 @@ class Facture extends CommonInvoice
 		$arraynow=dol_getdate($now);
 		$arraynow=dol_getdate($now);
 		$nownotime=dol_mktime(0, 0, 0, $arraynow['mon'], $arraynow['mday'], $arraynow['year']);
 		$nownotime=dol_mktime(0, 0, 0, $arraynow['mon'], $arraynow['mday'], $arraynow['year']);
 
 
+        // Load array of products prodids
+		$num_prods = 0;
 		$prodids = array();
 		$prodids = array();
 		$sql = "SELECT rowid";
 		$sql = "SELECT rowid";
 		$sql.= " FROM ".MAIN_DB_PREFIX."product";
 		$sql.= " FROM ".MAIN_DB_PREFIX."product";

+ 163 - 3
htdocs/compta/facture/fiche-rec.php

@@ -552,9 +552,9 @@ if ($action == 'addline' && $user->rights->facture->creer)
 
 
             if ($result > 0)
             if ($result > 0)
             {
             {
-                // Define output language
                 /*if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE))
                 /*if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE))
                 {
                 {
+                    // Define output language
                     $outputlangs = $langs;
                     $outputlangs = $langs;
                     $newlang = '';
                     $newlang = '';
                     if ($conf->global->MAIN_MULTILANGS && empty($newlang) && GETPOST('lang_id')) $newlang = GETPOST('lang_id','alpha');
                     if ($conf->global->MAIN_MULTILANGS && empty($newlang) && GETPOST('lang_id')) $newlang = GETPOST('lang_id','alpha');
@@ -615,8 +615,168 @@ if ($action == 'addline' && $user->rights->facture->creer)
     }
     }
 }
 }
 
 
+elseif ($action == 'updateligne' && $user->rights->facture->creer && ! GETPOST('cancel'))
+{
+    if (! $object->fetch($id) > 0)	dol_print_error($db);
+    $object->fetch_thirdparty();
+
+    // Clean parameters
+    $date_start = '';
+    $date_end = '';
+    //$date_start = dol_mktime(GETPOST('date_starthour'), GETPOST('date_startmin'), GETPOST('date_startsec'), GETPOST('date_startmonth'), GETPOST('date_startday'), GETPOST('date_startyear'));
+    //$date_end = dol_mktime(GETPOST('date_endhour'), GETPOST('date_endmin'), GETPOST('date_endsec'), GETPOST('date_endmonth'), GETPOST('date_endday'), GETPOST('date_endyear'));
+    $description = dol_htmlcleanlastbr(GETPOST('product_desc') ? GETPOST('product_desc') : GETPOST('desc'));
+    $pu_ht = GETPOST('price_ht');
+    $vat_rate = (GETPOST('tva_tx') ? GETPOST('tva_tx') : 0);
+    $qty = GETPOST('qty');
+
+    // Define info_bits
+    $info_bits = 0;
+    if (preg_match('/\*/', $vat_rate))
+        $info_bits |= 0x01;
+
+        // Define vat_rate
+        $vat_rate = str_replace('*', '', $vat_rate);
+        $localtax1_rate = get_localtax($vat_rate, 1, $object->thirdparty);
+        $localtax2_rate = get_localtax($vat_rate, 2, $object->thirdparty);
+
+        // Add buying price
+        $fournprice = price2num(GETPOST('fournprice') ? GETPOST('fournprice') : '');
+        $buyingprice = price2num(GETPOST('buying_price') != '' ? GETPOST('buying_price') : '');       // If buying_price is '0', we muste keep this value
+
+        // Extrafields
+        $extrafieldsline = new ExtraFields($db);
+        $extralabelsline = $extrafieldsline->fetch_name_optionals_label($object->table_element_line);
+        $array_options = $extrafieldsline->getOptionalsFromPost($extralabelsline);
+        // Unset extrafield
+        if (is_array($extralabelsline)) {
+            // Get extra fields
+            foreach ($extralabelsline as $key => $value) {
+                unset($_POST["options_" . $key]);
+            }
+        }
+
+        // Define special_code for special lines
+        $special_code=GETPOST('special_code');
+        if (! GETPOST('qty')) $special_code=3;
+
+        /*$line = new FactureLigne($db);
+        $line->fetch(GETPOST('lineid'));
+        $percent = $line->get_prev_progress($object->id);
+
+        if (GETPOST('progress') < $percent)
+        {
+            $mesg = '<div class="warning">' . $langs->trans("CantBeLessThanMinPercent") . '</div>';
+            setEventMessages($mesg, null, 'warnings');
+            $error++;
+            $result = -1;
+        }*/
+
+        // Check minimum price
+        $productid = GETPOST('productid', 'int');
+        if (! empty($productid))
+        {
+            $product = new Product($db);
+            $product->fetch($productid);
+
+            $type = $product->type;
+
+            $price_min = $product->price_min;
+            if (! empty($conf->global->PRODUIT_MULTIPRICES) && ! empty($object->thirdparty->price_level))
+                $price_min = $product->multiprices_min [$object->thirdparty->price_level];
+
+                $label = ((GETPOST('update_label') && GETPOST('product_label')) ? GETPOST('product_label') : '');
+
+                // Check price is not lower than minimum (check is done only for standard or replacement invoices)
+                if (($object->type == Facture::TYPE_STANDARD || $object->type == Facture::TYPE_REPLACEMENT) && $price_min && (price2num($pu_ht) * (1 - price2num(GETPOST('remise_percent')) / 100) < price2num($price_min))) {
+                    setEventMessages($langs->trans("CantBeLessThanMinPrice", price(price2num($price_min, 'MU'), 0, $langs, 0, 0, - 1, $conf->currency)), null, 'errors');
+                    $error ++;
+                }
+        } else {
+            $type = GETPOST('type');
+            $label = (GETPOST('product_label') ? GETPOST('product_label') : '');
+
+            // Check parameters
+            if (GETPOST('type') < 0) {
+                setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Type")), null, 'errors');
+                $error ++;
+            }
+        }
+        if ($qty < 0) {
+            $langs->load("errors");
+            setEventMessages($langs->trans('ErrorQtyForCustomerInvoiceCantBeNegative'), null, 'errors');
+            $error ++;
+        }
+
+        // Update line
+        if (! $error) {
+            $result = $object->updateline(GETPOST('lineid'), $description, $pu_ht, $qty,
+                $vat_rate, GETPOST('productid'), GETPOST('remise_percent'), 'HT', $info_bits, 0, 0, $type,
+                0, $special_code, $label, GETPOST('units'));
+
+            if ($result >= 0) {
+                /*if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE)) {
+                    // Define output language
+                    $outputlangs = $langs;
+                    $newlang = '';
+                    if ($conf->global->MAIN_MULTILANGS && empty($newlang) && GETPOST('lang_id'))
+                        $newlang = GETPOST('lang_id');
+                        if ($conf->global->MAIN_MULTILANGS && empty($newlang))
+                            $newlang = $object->thirdparty->default_lang;
+                            if (! empty($newlang)) {
+                                $outputlangs = new Translate("", $conf);
+                                $outputlangs->setDefaultLang($newlang);
+                            }
+
+                            $ret = $object->fetch($id); // Reload to get new records
+                            $object->generateDocument($object->modelpdf, $outputlangs, $hidedetails, $hidedesc, $hideref);
+                }*/
+
+                $object->fetch($object->id);    // Reload lines
+                
+                unset($_POST['qty']);
+                unset($_POST['type']);
+                unset($_POST['productid']);
+                unset($_POST['remise_percent']);
+                unset($_POST['price_ht']);
+                unset($_POST['multicurrency_price_ht']);
+                unset($_POST['price_ttc']);
+                unset($_POST['tva_tx']);
+                unset($_POST['product_ref']);
+                unset($_POST['product_label']);
+                unset($_POST['product_desc']);
+                unset($_POST['fournprice']);
+                unset($_POST['buying_price']);
+                unset($_POST['np_marginRate']);
+                unset($_POST['np_markRate']);
+
+                unset($_POST['dp_desc']);
+                unset($_POST['idprod']);
+                unset($_POST['units']);
+
+                unset($_POST['date_starthour']);
+                unset($_POST['date_startmin']);
+                unset($_POST['date_startsec']);
+                unset($_POST['date_startday']);
+                unset($_POST['date_startmonth']);
+                unset($_POST['date_startyear']);
+                unset($_POST['date_endhour']);
+                unset($_POST['date_endmin']);
+                unset($_POST['date_endsec']);
+                unset($_POST['date_endday']);
+                unset($_POST['date_endmonth']);
+                unset($_POST['date_endyear']);
+
+                unset($_POST['situations']);
+                unset($_POST['progress']);
+            } else {
+                setEventMessages($object->error, $object->errors, 'errors');
+            }
+        }
+}
+
 // Do we click on purge search criteria ?
 // Do we click on purge search criteria ?
-if (GETPOST("button_removefilter_x") || GETPOST("button_removefilter")) // Both test are required to be compatible with all browsers
+if (GETPOST("button_removefilter_x") || GETPOST("button_removefilter.x") || GETPOST("button_removefilter")) // All test are required to be compatible with all browsers
 {
 {
     $search_ref='';
     $search_ref='';
     $search_societe='';
     $search_societe='';
@@ -1302,7 +1462,7 @@ else
 		// Show object lines
 		// Show object lines
 		if (! empty($object->lines))
 		if (! empty($object->lines))
 		{
 		{
-		    $disableedit=1;
+		    //$disableedit=1;
 		    //$disablemove=1;
 		    //$disablemove=1;
 		    $ret = $object->printObjectLines($action, $mysoc, $soc, $lineid, 0);      // No date selector for template invoice
 		    $ret = $object->printObjectLines($action, $mysoc, $soc, $lineid, 0);      // No date selector for template invoice
 		}
 		}

+ 23 - 16
htdocs/conf/conf.php.example

@@ -220,6 +220,25 @@ $dolibarr_main_authentication='dolibarr';
 //
 //
 $dolibarr_main_force_https='0';
 $dolibarr_main_force_https='0';
 
 
+// dolibarr_main_prod
+// When this parameter is defined, all errors messages are not reported.
+// This feature exists for production usage to avoid to give any information to hackers.
+// Default value: 0
+// Possible values: 0 or 1
+// Examples:
+// $dolibarr_main_prod='0';
+//
+$dolibarr_main_prod='0';
+
+// $dolibarr_main_restrict_os_commands
+// To restrict commands you can execute by the backup feature, enter allowed command here.
+// Note: If you can, defining permission on OS linux (using SELinux for example) may be a better choice.
+// Default value: 'mysqldump, mysql, pg_dump, pgrestore'
+// Examples:
+// $dolibarr_main_restrict_os_commands='mysqldump, /usr/local/bin/otherdumptool';
+//
+$dolibarr_main_restrict_os_commands='mysqldump, mysql, pg_dump, pgrestore';
+
 // dolibarr_nocsrfcheck
 // dolibarr_nocsrfcheck
 // This parameter can be used to disable CSRF protection.
 // This parameter can be used to disable CSRF protection.
 // This might be required if you access Dolibarr behind a proxy that make
 // This might be required if you access Dolibarr behind a proxy that make
@@ -231,15 +250,11 @@ $dolibarr_main_force_https='0';
 //
 //
 $dolibarr_nocsrfcheck='0';
 $dolibarr_nocsrfcheck='0';
 
 
-// dolibarr_main_prod
-// When this parameter is defined, all errors messages are not reported.
-// This feature exists for production usage to avoid to give any information to hackers.
-// Default value: 0
-// Possible values: 0 or 1
+// dolibarr_mailing_limit_sendbyweb
+// Can set a limit for mailing send by web. Can be used for a restricted mode.
+// Default value: 0 (use database value if exist)
 // Examples:
 // Examples:
-// $dolibarr_main_prod='0';
-//
-$dolibarr_main_prod='0';
+// $dolibarr_mailing_limit_sendbyweb='0';
 
 
 
 
 
 
@@ -251,8 +266,6 @@ $dolibarr_main_prod='0';
 // This parameter contains prefix of Dolibarr database. 'llx_' if not defined.
 // This parameter contains prefix of Dolibarr database. 'llx_' if not defined.
 // Examples:
 // Examples:
 // $dolibarr_main_db_prefix='llx_';
 // $dolibarr_main_db_prefix='llx_';
-//
-$dolibarr_main_db_prefix='';
 
 
 // dolibarr_main_limit_users
 // dolibarr_main_limit_users
 // Can set a limit on the number of users it will be possible to create
 // Can set a limit on the number of users it will be possible to create
@@ -261,12 +274,6 @@ $dolibarr_main_db_prefix='';
 // Examples:
 // Examples:
 // $dolibarr_main_limit_users='0';
 // $dolibarr_main_limit_users='0';
 
 
-// dolibarr_mailing_limit_sendbyweb
-// Can set a limit for mailing send by web. Can be used for a restricted mode.
-// Default value: 0 (use database value if exist)
-// Examples:
-// $dolibarr_mailing_limit_sendbyweb='0';
-
 // dolibarr_strict_mode
 // dolibarr_strict_mode
 // Set this to 1 to enable the PHP strict mode. For dev environment only.
 // Set this to 1 to enable the PHP strict mode. For dev environment only.
 // Default value: 0 (use database value if exist)
 // Default value: 0 (use database value if exist)

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

@@ -2098,6 +2098,8 @@ class Contrat extends CommonObject
 	{
 	{
 		global $user,$langs,$conf;
 		global $user,$langs,$conf;
 
 
+        // Load array of products prodids
+		$num_prods = 0;
 		$prodids = array();
 		$prodids = array();
 		$sql = "SELECT rowid";
 		$sql = "SELECT rowid";
 		$sql.= " FROM ".MAIN_DB_PREFIX."product";
 		$sql.= " FROM ".MAIN_DB_PREFIX."product";
@@ -2116,8 +2118,6 @@ class Contrat extends CommonObject
 			}
 			}
 		}
 		}
 
 
-
-
 		// Initialise parametres
 		// Initialise parametres
 		$this->id=0;
 		$this->id=0;
 		$this->specimen=1;
 		$this->specimen=1;

+ 7 - 5
htdocs/core/actions_printing.inc.php

@@ -1,6 +1,6 @@
 <?php
 <?php
-/* Copyright (C) 2014 Laurent Destailleur  <eldy@users.sourceforge.net>
- * Copyright (C) 2014 Frederic France      <frederic.france@free.fr>
+/* Copyright (C) 2014-2016 Laurent Destailleur  <eldy@users.sourceforge.net>
+ * Copyright (C) 2014      Frederic France      <frederic.france@free.fr>
  *
  *
  * This program is free software; you can redistribute it and/or modify
  * 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
  * it under the terms of the GNU General Public License as published by
@@ -44,7 +44,8 @@ if ($action == 'print_file' and $user->rights->printing->read)
             $printer = new $classname($db);
             $printer = new $classname($db);
             //print '<pre>'.print_r($printer, true).'</pre>';
             //print '<pre>'.print_r($printer, true).'</pre>';
 
 
-            if (! empty($conf->global->{$printer->active})) {
+            if (! empty($conf->global->{$printer->active})) 
+            {
                 $subdir=(GETPOST('printer', 'alpha')=='expedition'?'sending':'');
                 $subdir=(GETPOST('printer', 'alpha')=='expedition'?'sending':'');
                 $module = GETPOST('printer', 'alpha');
                 $module = GETPOST('printer', 'alpha');
                 if ($module =='commande_fournisseur') {
                 if ($module =='commande_fournisseur') {
@@ -56,10 +57,11 @@ if ($action == 'print_file' and $user->rights->printing->read)
                     //print '<pre>'.print_r($printer->errors, true).'</pre>';
                     //print '<pre>'.print_r($printer->errors, true).'</pre>';
                     setEventMessages($printer->error, $printer->errors, 'errors');
                     setEventMessages($printer->error, $printer->errors, 'errors');
                 }
                 }
-                if ($ret==0) {
+                if ($ret==0) 
+                {
                     //print '<pre>'.print_r($printer->errors, true).'</pre>';
                     //print '<pre>'.print_r($printer->errors, true).'</pre>';
                     setEventMessages($printer->error, $printer->errors);
                     setEventMessages($printer->error, $printer->errors);
-                    setEventMessages($langs->trans("FileWasSentToPrinter", basename(GETPOST('file'))).' '.$langs->trans("ViaModule").' '.$printer->name, null);
+                    setEventMessages($langs->trans("FileWasSentToPrinter", basename(GETPOST('file'))).' '.$langs->transnoentitiesnoconv("ViaModule").' '.$printer->name, null);
                     $printed++;
                     $printed++;
                 }
                 }
             }
             }

+ 1 - 2
htdocs/core/class/commonobject.class.php

@@ -3998,14 +3998,13 @@ abstract class CommonObject
     	{
     	{
     		if (!empty($this->errors))
     		if (!empty($this->errors))
     		{
     		{
-    			$this->errors=array_merge($this->errors,$interface->errors);
+    			$this->errors=array_unique(array_merge($this->errors,$interface->errors));   // We use array_unique because when a trigger call another trigger on same object, this->errors is added twice.
     		}
     		}
     		else
     		else
     		{
     		{
     			$this->errors=$interface->errors;
     			$this->errors=$interface->errors;
     		}
     		}
     	}
     	}
-
     	return $result;
     	return $result;
     }
     }
 
 

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

@@ -429,7 +429,7 @@ class Conf
 		$this->liste_limit=$this->global->MAIN_SIZE_LISTE_LIMIT;
 		$this->liste_limit=$this->global->MAIN_SIZE_LISTE_LIMIT;
 
 
 		// conf->product->limit_size = constante de taille maximale des select de produit
 		// conf->product->limit_size = constante de taille maximale des select de produit
-		if (! isset($this->global->PRODUIT_LIMIT_SIZE)) $this->global->PRODUIT_LIMIT_SIZE=100;
+		if (! isset($this->global->PRODUIT_LIMIT_SIZE)) $this->global->PRODUIT_LIMIT_SIZE=1000;
 		$this->product->limit_size=$this->global->PRODUIT_LIMIT_SIZE;
 		$this->product->limit_size=$this->global->PRODUIT_LIMIT_SIZE;
 
 
 		// conf->theme et $this->css
 		// conf->theme et $this->css

+ 2 - 1
htdocs/core/class/extrafields.class.php

@@ -633,7 +633,8 @@ class ExtraFields
 		}
 		}
 		else
 		else
 		{
 		{
-			print dol_print_error($this->db);
+			$this->error=$this->db->lasterror();
+			dol_syslog(get_class($this)."::fetch_name_optionals_label ".$this->error, LOG_ERR);
 		}
 		}
 
 
 		return $array_name_label;
 		return $array_name_label;

+ 3 - 1
htdocs/core/class/interfaces.class.php

@@ -191,10 +191,12 @@ class Interfaces
                 if ($result < 0)
                 if ($result < 0)
                 {
                 {
                     // Action KO
                     // Action KO
+                    //dol_syslog("Error in trigger ".$action." - Nb of error string returned = ".count($objMod->errors), LOG_ERR);
                     $nbtotal++;
                     $nbtotal++;
                     $nbko++;
                     $nbko++;
                     if (! empty($objMod->errors)) $this->errors=array_merge($this->errors,$objMod->errors);
                     if (! empty($objMod->errors)) $this->errors=array_merge($this->errors,$objMod->errors);
                     else if (! empty($objMod->error))  $this->errors[]=$objMod->error;
                     else if (! empty($objMod->error))  $this->errors[]=$objMod->error;
+                    //dol_syslog("Error in trigger ".$action." - Nb of error string returned = ".count($this->errors), LOG_ERR);
                 }
                 }
             }
             }
             else
             else
@@ -205,7 +207,7 @@ class Interfaces
 
 
         if ($nbko)
         if ($nbko)
         {
         {
-            dol_syslog(get_class($this)."::run_triggers action=".$action." Files found: ".$nbfile.", Files launched: ".$nbtotal.", Done: ".$nbok.", Failed: ".$nbko, LOG_ERR);
+            dol_syslog(get_class($this)."::run_triggers action=".$action." Files found: ".$nbfile.", Files launched: ".$nbtotal.", Done: ".$nbok.", Failed: ".$nbko." - Nb of error string returned in this->errors = ".count($this->errors), LOG_ERR);
             return -$nbko;
             return -$nbko;
         }
         }
         else
         else

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

@@ -167,7 +167,7 @@ class Translate
 		if (empty($domain))
 		if (empty($domain))
 		{
 		{
 			dol_print_error('',get_class($this)."::Load ErrorWrongParameters");
 			dol_print_error('',get_class($this)."::Load ErrorWrongParameters");
-			exit;
+			return -1;
 		}
 		}
 		if ($this->defaultlang == 'none_NONE') return 0;    // Special language code to not translate keys
 		if ($this->defaultlang == 'none_NONE') return 0;    // Special language code to not translate keys
 
 

+ 6 - 7
htdocs/core/db/pgsql.class.php

@@ -163,10 +163,13 @@ class DoliDBPgsql extends DoliDB
 		}
 		}
 		if ($line != "")
 		if ($line != "")
 		{
 		{
-			// group_concat support (PgSQL >= 9.1)
-			$line = preg_replace('/GROUP_CONCAT/i', 'STRING_AGG', $line);
+			// group_concat support (PgSQL >= 9.0)
+			// Replace group_concat(x) or group_concat(x SEPARATOR ',') with string_agg(x, ',')
+		    $line = preg_replace('/GROUP_CONCAT/i', 'STRING_AGG', $line);
 			$line = preg_replace('/ SEPARATOR/i', ',', $line);
 			$line = preg_replace('/ SEPARATOR/i', ',', $line);
-
+			$line = preg_replace('/STRING_AGG\(([^,\)]+)\)/i', 'STRING_AGG(\\1, \',\')', $line);
+			//print $line."\n";
+					
 		    if ($type == 'auto')
 		    if ($type == 'auto')
 		    {
 		    {
               if (preg_match('/ALTER TABLE/i',$line)) $type='dml';
               if (preg_match('/ALTER TABLE/i',$line)) $type='dml';
@@ -315,10 +318,6 @@ class DoliDBPgsql extends DoliDB
 				}
 				}
 			}
 			}
 
 
-			// Replace group_concat(x) with string_agg(x, ',')
-			$line=preg_replace('/GROUP_CONCAT\(([^\)]+)\)/i','STRING_AGG(\\1, \',\')',$line);
-			//print $line."\n";
-			
 			// Remove () in the tables in FROM if 1 table
 			// Remove () in the tables in FROM if 1 table
 			$line=preg_replace('/FROM\s*\((([a-z_]+)\s+as\s+([a-z_]+)\s*)\)/i','FROM \\1',$line);
 			$line=preg_replace('/FROM\s*\((([a-z_]+)\s+as\s+([a-z_]+)\s*)\)/i','FROM \\1',$line);
 			//print $line."\n";
 			//print $line."\n";

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

@@ -4548,9 +4548,9 @@ function dol_textishtml($msg,$option=0)
 		if (preg_match('/<html/i',$msg))				return true;
 		if (preg_match('/<html/i',$msg))				return true;
 		elseif (preg_match('/<body/i',$msg))			return true;
 		elseif (preg_match('/<body/i',$msg))			return true;
 		elseif (preg_match('/<(b|em|i)>/i',$msg))		return true;
 		elseif (preg_match('/<(b|em|i)>/i',$msg))		return true;
-		elseif (preg_match('/<(br|div|font|li|span|strong|table)>/i',$msg)) 	  return true;
-		elseif (preg_match('/<(br|div|font|li|span|strong|table)\s+[^<>\/]*>/i',$msg)) return true;
-		elseif (preg_match('/<(br|div|font|li|span|strong|table)\s+[^<>\/]*\/>/i',$msg)) return true;
+		elseif (preg_match('/<(br|div|font|li|p|span|strong|table)>/i',$msg)) 	  return true;
+		elseif (preg_match('/<(br|div|font|li|p|span|strong|table)\s+[^<>\/]*>/i',$msg)) return true;
+		elseif (preg_match('/<(br|div|font|li|p|span|strong|table)\s+[^<>\/]*\/>/i',$msg)) return true;
 		elseif (preg_match('/<img\s+[^<>]*src[^<>]*>/i',$msg)) return true;	// must accept <img src="http://example.com/aaa.png" />
 		elseif (preg_match('/<img\s+[^<>]*src[^<>]*>/i',$msg)) return true;	// must accept <img src="http://example.com/aaa.png" />
 		elseif (preg_match('/<a\s+[^<>]*href[^<>]*>/i',$msg)) return true;	// must accept <a href="http://example.com/aaa.png" />
 		elseif (preg_match('/<a\s+[^<>]*href[^<>]*>/i',$msg)) return true;	// must accept <a href="http://example.com/aaa.png" />
 		elseif (preg_match('/<h[0-9]>/i',$msg))			return true;
 		elseif (preg_match('/<h[0-9]>/i',$msg))			return true;

+ 10 - 2
htdocs/core/menus/standard/auguria.lib.php

@@ -78,11 +78,19 @@ function print_auguria_menu($db,$atarget,$type_user,&$tabMenu,&$menu,$noout=0,$m
 			
 			
 			if (! preg_match("/^(http:\/\/|https:\/\/)/i",$newTabMenu[$i]['url']))
 			if (! preg_match("/^(http:\/\/|https:\/\/)/i",$newTabMenu[$i]['url']))
 			{
 			{
-				$tmp=explode('?',$newTabMenu[$i]['url'],2);
+			    $tmp=explode('?',$newTabMenu[$i]['url'],2);
 				$url = $shorturl = $tmp[0];
 				$url = $shorturl = $tmp[0];
 				$param = (isset($tmp[1])?$tmp[1]:'');
 				$param = (isset($tmp[1])?$tmp[1]:'');
 
 
-				if (! preg_match('/mainmenu/i',$param) || ! preg_match('/leftmenu/i',$param)) $param.=($param?'&':'').'mainmenu='.$newTabMenu[$i]['mainmenu'].'&amp;leftmenu=';
+				// Complete param to force leftmenu to '' to closed opend menu when we click on a link with no leftmenu defined.
+			    if ((! preg_match('/mainmenu/i',$param)) && (! preg_match('/leftmenu/i',$param)) && ! empty($newTabMenu[$i]['url'])) 
+			    {
+			        $param.=($param?'&':'').'mainmenu='.$newTabMenu[$i]['url'].'&leftmenu=';
+			    }
+			    if ((! preg_match('/mainmenu/i',$param)) && (! preg_match('/leftmenu/i',$param)) && empty($newTabMenu[$i]['url'])) 
+			    {
+			        $param.=($param?'&':'').'leftmenu=';
+			    }
 				//$url.="idmenu=".$newTabMenu[$i]['rowid'];    // Already done by menuLoad
 				//$url.="idmenu=".$newTabMenu[$i]['rowid'];    // Already done by menuLoad
 				$url = dol_buildpath($url,1).($param?'?'.$param:'');
 				$url = dol_buildpath($url,1).($param?'?'.$param:'');
 				$shorturl = $shorturl.($param?'?'.$param:'');
 				$shorturl = $shorturl.($param?'?'.$param:'');

+ 35 - 16
htdocs/core/menus/standard/eldy.lib.php

@@ -857,8 +857,8 @@ function print_left_eldy_menu($db,$menu_array_before,$menu_array_after,&$tabMenu
 			{
 			{
 				$langs->load("donations");
 				$langs->load("donations");
 				$newmenu->add("/don/index.php?leftmenu=donations&amp;mainmenu=accountancy",$langs->trans("Donations"), 0, $user->rights->don->lire, '', $mainmenu, 'donations');
 				$newmenu->add("/don/index.php?leftmenu=donations&amp;mainmenu=accountancy",$langs->trans("Donations"), 0, $user->rights->don->lire, '', $mainmenu, 'donations');
-				if (empty($leftmenu) || $leftmenu=="donations") $newmenu->add("/don/card.php?action=create",$langs->trans("NewDonation"), 1, $user->rights->don->creer);
-				if (empty($leftmenu) || $leftmenu=="donations") $newmenu->add("/don/list.php",$langs->trans("List"), 1, $user->rights->don->lire);
+				if (empty($leftmenu) || $leftmenu=="donations") $newmenu->add("/don/card.php?leftmenu=donations&amp;action=create",$langs->trans("NewDonation"), 1, $user->rights->don->creer);
+				if (empty($leftmenu) || $leftmenu=="donations") $newmenu->add("/don/list.php?leftmenu=donations",$langs->trans("List"), 1, $user->rights->don->lire);
 				// if ($leftmenu=="donations") $newmenu->add("/don/stats/index.php",$langs->trans("Statistics"), 1, $user->rights->don->lire);
 				// if ($leftmenu=="donations") $newmenu->add("/don/stats/index.php",$langs->trans("Statistics"), 1, $user->rights->don->lire);
 			}
 			}
 
 
@@ -1058,6 +1058,7 @@ function print_left_eldy_menu($db,$menu_array_before,$menu_array_after,&$tabMenu
 				$newmenu->add("/compta/bank/index.php?leftmenu=bank&amp;mainmenu=bank",$langs->trans("MenuBankCash"),0,$user->rights->banque->lire, '', $mainmenu, 'bank');
 				$newmenu->add("/compta/bank/index.php?leftmenu=bank&amp;mainmenu=bank",$langs->trans("MenuBankCash"),0,$user->rights->banque->lire, '', $mainmenu, 'bank');
 
 
 				$newmenu->add("/compta/bank/card.php?action=create",$langs->trans("MenuNewFinancialAccount"),1,$user->rights->banque->configurer);
 				$newmenu->add("/compta/bank/card.php?action=create",$langs->trans("MenuNewFinancialAccount"),1,$user->rights->banque->configurer);
+				$newmenu->add("/compta/bank/index.php?leftmenu=bank&amp;mainmenu=bank",$langs->trans("List"),1,$user->rights->banque->lire, '', $mainmenu, 'bank');
 				$newmenu->add("/compta/bank/search.php",$langs->trans("ListTransactions"),1,$user->rights->banque->lire);
 				$newmenu->add("/compta/bank/search.php",$langs->trans("ListTransactions"),1,$user->rights->banque->lire);
 				$newmenu->add("/compta/bank/budget.php",$langs->trans("ListTransactionsByCategory"),1,$user->rights->banque->lire);
 				$newmenu->add("/compta/bank/budget.php",$langs->trans("ListTransactionsByCategory"),1,$user->rights->banque->lire);
 
 
@@ -1184,9 +1185,9 @@ function print_left_eldy_menu($db,$menu_array_before,$menu_array_after,&$tabMenu
 				$langs->load("projects");
 				$langs->load("projects");
 
 
 				// Project affected to user
 				// Project affected to user
-				$newmenu->add("/projet/index.php?leftmenu=projects&mode=mine", $langs->trans("MyProjects"), 0, $user->rights->projet->lire, '', $mainmenu, 'myprojects');
-				$newmenu->add("/projet/card.php?leftmenu=projects&action=create&mode=mine", $langs->trans("NewProject"), 1, $user->rights->projet->creer);
-				$newmenu->add("/projet/list.php?leftmenu=projects&mode=mine&search_status=1", $langs->trans("List"), 1, $user->rights->projet->lire);
+				$newmenu->add("/projet/index.php?leftmenu=myprojects&mode=mine", $langs->trans("MyProjects"), 0, $user->rights->projet->lire, '', $mainmenu, 'myprojects');
+				$newmenu->add("/projet/card.php?leftmenu=myprojects&action=create&mode=mine", $langs->trans("NewProject"), 1, $user->rights->projet->creer);
+				$newmenu->add("/projet/list.php?leftmenu=myprojects&mode=mine&search_status=1", $langs->trans("List"), 1, $user->rights->projet->lire);
 
 
 				// All project i have permission on
 				// All project i have permission on
 				$newmenu->add("/projet/index.php?leftmenu=projects", $langs->trans("Projects"), 0, $user->rights->projet->lire && $user->rights->projet->lire, '', $mainmenu, 'projects');
 				$newmenu->add("/projet/index.php?leftmenu=projects", $langs->trans("Projects"), 0, $user->rights->projet->lire && $user->rights->projet->lire, '', $mainmenu, 'projects');
@@ -1197,10 +1198,10 @@ function print_left_eldy_menu($db,$menu_array_before,$menu_array_after,&$tabMenu
 				if (empty($conf->global->PROJECT_HIDE_TASKS))
 				if (empty($conf->global->PROJECT_HIDE_TASKS))
 				{
 				{
 					// Project affected to user
 					// Project affected to user
-					$newmenu->add("/projet/activity/index.php?mode=mine", $langs->trans("MyActivities"), 0, $user->rights->projet->lire);
-					$newmenu->add("/projet/tasks.php?action=create", $langs->trans("NewTask"), 1, $user->rights->projet->creer);
-					$newmenu->add("/projet/tasks/list.php?mode=mine", $langs->trans("List"), 1, $user->rights->projet->lire);
-					$newmenu->add("/projet/activity/perweek.php?mode=mine", $langs->trans("NewTimeSpent"), 1, $user->rights->projet->creer);
+					$newmenu->add("/projet/activity/index.php?leftmenu=mytasks&mode=mine", $langs->trans("MyActivities"), 0, $user->rights->projet->lire);
+					$newmenu->add("/projet/tasks.php?leftmenu=mytasks&action=create", $langs->trans("NewTask"), 1, $user->rights->projet->creer);
+					$newmenu->add("/projet/tasks/list.php?leftmenu=mytasks&mode=mine", $langs->trans("List"), 1, $user->rights->projet->lire);
+					$newmenu->add("/projet/activity/perweek.php?leftmenu=mytasks&mode=mine", $langs->trans("NewTimeSpent"), 1, $user->rights->projet->creer);
 
 
 					// All project i have permission on
 					// All project i have permission on
 					$newmenu->add("/projet/activity/index.php", $langs->trans("Activities"), 0, $user->rights->projet->lire && $user->rights->projet->lire);
 					$newmenu->add("/projet/activity/index.php", $langs->trans("Activities"), 0, $user->rights->projet->lire && $user->rights->projet->lire);
@@ -1452,15 +1453,33 @@ function print_left_eldy_menu($db,$menu_array_before,$menu_array_after,&$tabMenu
 				}
 				}
 			}
 			}
 
 
-			// For external modules
-			$tmp=explode('?',$menu_array[$i]['url'],2);
-			$url = $tmp[0];
-			$param = (isset($tmp[1])?$tmp[1]:'');
-			$url = dol_buildpath($url,1).($param?'?'.$param:'');
-
+			$url = $shorturl = $menu_array[$i]['url'];
+			
+			if (! preg_match("/^(http:\/\/|https:\/\/)/i",$menu_array[$i]['url']))
+			{
+			    $tmp=explode('?',$menu_array[$i]['url'],2);
+			    $url = $shorturl = $tmp[0];
+			    $param = (isset($tmp[1])?$tmp[1]:'');    // params in url of the menu link
+
+			    // Complete param to force leftmenu to '' to closed opend menu when we click on a link with no leftmenu defined.
+			    if ((! preg_match('/mainmenu/i',$param)) && (! preg_match('/leftmenu/i',$param)) && ! empty($menu_array[$i]['mainmenu'])) 
+			    {
+			        $param.=($param?'&':'').'mainmenu='.$menu_array[$i]['mainmenu'].'&leftmenu=';
+			    }
+			    if ((! preg_match('/mainmenu/i',$param)) && (! preg_match('/leftmenu/i',$param)) && empty($menu_array[$i]['mainmenu'])) 
+			    {
+			        $param.=($param?'&':'').'leftmenu=';
+			    }
+			    //$url.="idmenu=".$menu_array[$i]['rowid'];    // Already done by menuLoad
+			    $url = dol_buildpath($url,1).($param?'?'.$param:'');
+			    $shorturl = $shorturl.($param?'?'.$param:'');
+			}
+				
 			$url=preg_replace('/__LOGIN__/',$user->login,$url);
 			$url=preg_replace('/__LOGIN__/',$user->login,$url);
+			$shorturl=preg_replace('/__LOGIN__/',$user->login,$shorturl);
 			$url=preg_replace('/__USERID__/',$user->id,$url);
 			$url=preg_replace('/__USERID__/',$user->id,$url);
-
+			$shorturl=preg_replace('/__USERID__/',$user->id,$shorturl);
+				
 			print '<!-- Process menu entry with mainmenu='.$menu_array[$i]['mainmenu'].', leftmenu='.$menu_array[$i]['leftmenu'].', level='.$menu_array[$i]['level'].' enabled='.$menu_array[$i]['enabled'].', position='.$menu_array[$i]['position'].' -->'."\n";
 			print '<!-- Process menu entry with mainmenu='.$menu_array[$i]['mainmenu'].', leftmenu='.$menu_array[$i]['leftmenu'].', level='.$menu_array[$i]['level'].' enabled='.$menu_array[$i]['enabled'].', position='.$menu_array[$i]['position'].' -->'."\n";
 
 
 			// Menu niveau 0
 			// Menu niveau 0

+ 2 - 2
htdocs/core/tpl/objectline_create.tpl.php

@@ -694,17 +694,17 @@ function setforpredef() {
 	jQuery("#prod_entry_mode_free").prop('checked',false);
 	jQuery("#prod_entry_mode_free").prop('checked',false);
 	jQuery("#prod_entry_mode_predef").prop('checked',true);
 	jQuery("#prod_entry_mode_predef").prop('checked',true);
 	jQuery("#price_ht").hide();
 	jQuery("#price_ht").hide();
-	jQuery("#title_up_ht").hide();
 	jQuery("#price_ttc").hide();	// May no exists
 	jQuery("#price_ttc").hide();	// May no exists
 	jQuery("#tva_tx").hide();
 	jQuery("#tva_tx").hide();
 	jQuery("#buying_price").show();
 	jQuery("#buying_price").show();
+	//jQuery("#fournprice_predef").show(); // management somewhere else
 	jQuery("#title_vat").hide();
 	jQuery("#title_vat").hide();
+	jQuery("#title_up_ht").hide();
 	jQuery("#title_up_ttc").hide();
 	jQuery("#title_up_ttc").hide();
 	jQuery("#np_marginRate").hide();	// May no exists
 	jQuery("#np_marginRate").hide();	// May no exists
 	jQuery("#np_markRate").hide();	// May no exists
 	jQuery("#np_markRate").hide();	// May no exists
 	jQuery(".np_marginRate").hide();	// May no exists
 	jQuery(".np_marginRate").hide();	// May no exists
 	jQuery(".np_markRate").hide();	// May no exists
 	jQuery(".np_markRate").hide();	// May no exists
-	jQuery(".np_markRate").hide();	// May no exists
 	jQuery("#units, #title_units").hide();
 	jQuery("#units, #title_units").hide();
 }
 }
 
 

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

@@ -1549,7 +1549,8 @@ class Expedition extends CommonObject
 
 
 		dol_syslog(get_class($this)."::initAsSpecimen");
 		dol_syslog(get_class($this)."::initAsSpecimen");
 
 
-		// Charge tableau des produits prodids
+        // Load array of products prodids
+		$num_prods = 0;
 		$prodids = array();
 		$prodids = array();
 		$sql = "SELECT rowid";
 		$sql = "SELECT rowid";
 		$sql.= " FROM ".MAIN_DB_PREFIX."product";
 		$sql.= " FROM ".MAIN_DB_PREFIX."product";

+ 1 - 1
htdocs/expensereport/card.php

@@ -1432,7 +1432,7 @@ else
 				{
 				{
 					$num = $db->num_rows($resql);
 					$num = $db->num_rows($resql);
 					$i = 0; $total = 0;
 					$i = 0; $total = 0;
-					print '<table class="nobordernopadding" width="100%">';
+					print '<table class="nobordernopadding paymenttable" width="100%">';
 					print '<tr class="liste_titre">';
 					print '<tr class="liste_titre">';
 					print '<td>'.$langs->trans("RefPayment").'</td>';
 					print '<td>'.$langs->trans("RefPayment").'</td>';
 					print '<td>'.$langs->trans("Date").'</td>';
 					print '<td>'.$langs->trans("Date").'</td>';

+ 2 - 2
htdocs/exports/class/export.class.php

@@ -241,7 +241,7 @@ class Export
 			// Loop on each condition to add
 			// Loop on each condition to add
 			foreach ($array_filterValue as $key => $value)
 			foreach ($array_filterValue as $key => $value)
 			{
 			{
-			    if (preg_match('/group_concat/', $key)) continue;
+			    if (preg_match('/GROUP_CONCAT/i', $key)) continue;
 				if ($value != '') $sqlWhere.=" and ".$this->build_filterQuery($this->array_export_TypeFields[$indice][$key], $key, $array_filterValue[$key]);
 				if ($value != '') $sqlWhere.=" and ".$this->build_filterQuery($this->array_export_TypeFields[$indice][$key], $key, $array_filterValue[$key]);
 			}
 			}
 			$sql.=$sqlWhere;
 			$sql.=$sqlWhere;
@@ -256,7 +256,7 @@ class Export
 		    // Loop on each condition to add
 		    // Loop on each condition to add
 		    foreach ($array_filterValue as $key => $value)
 		    foreach ($array_filterValue as $key => $value)
 		    {
 		    {
-		        if (preg_match('/group_concat/', $key) and $value != '') $sql.=" HAVING ".$this->build_filterQuery($this->array_export_TypeFields[$indice][$key], $key, $array_filterValue[$key]);
+		        if (preg_match('/GROUP_CONCAT/i', $key) and $value != '') $sql.=" HAVING ".$this->build_filterQuery($this->array_export_TypeFields[$indice][$key], $key, $array_filterValue[$key]);
 		    }
 		    }
 		}
 		}
 		
 		

+ 2 - 1
htdocs/fourn/class/fournisseur.facture.class.php

@@ -1647,7 +1647,8 @@ class FactureFournisseur extends CommonInvoice
 
 
         $now = dol_now();
         $now = dol_now();
 
 
-        // Charge tableau des produits prodids
+        // Load array of products prodids
+        $num_prods = 0;
         $prodids = array();
         $prodids = array();
 
 
         $sql = "SELECT rowid";
         $sql = "SELECT rowid";

+ 0 - 2
htdocs/fourn/class/fournisseur.product.class.php

@@ -6,8 +6,6 @@
  * Copyright (C) 2012		Christophe Battarel	<christophe.battarel@altairis.fr>
  * Copyright (C) 2012		Christophe Battarel	<christophe.battarel@altairis.fr>
  * Copyright (C) 2015		Marcos García           <marcosgdf@gmail.com>
  * Copyright (C) 2015		Marcos García           <marcosgdf@gmail.com>
  * Copyright (C) 2016		Charlie Benke           <charlie@patas-monkey.com>
  * Copyright (C) 2016		Charlie Benke           <charlie@patas-monkey.com>
- 
- status
  *
  *
  * This program is free software; you can redistribute it and/or modify
  * 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
  * it under the terms of the GNU General Public License as published by

+ 8 - 6
htdocs/fourn/commande/orderstoinvoice.php

@@ -71,11 +71,12 @@ $date_end = dol_mktime(23, 59, 59, $_REQUEST["date_endmonth"], $_REQUEST["date_e
 $date_starty = dol_mktime(0, 0, 0, $_REQUEST["date_start_delymonth"], $_REQUEST["date_start_delyday"], $_REQUEST["date_start_delyyear"]); // Date for local PHP server
 $date_starty = dol_mktime(0, 0, 0, $_REQUEST["date_start_delymonth"], $_REQUEST["date_start_delyday"], $_REQUEST["date_start_delyyear"]); // Date for local PHP server
 $date_endy = dol_mktime(23, 59, 59, $_REQUEST["date_end_delymonth"], $_REQUEST["date_end_delyday"], $_REQUEST["date_end_delyyear"]);
 $date_endy = dol_mktime(23, 59, 59, $_REQUEST["date_end_delymonth"], $_REQUEST["date_end_delyday"], $_REQUEST["date_end_delyyear"]);
 
 
-if ($action == 'create') {
-	if (is_array($selected) == false) {
-		$mesgs = array (
-				'<div class="error">' . $langs->trans('Error_OrderNotChecked') . '</div>'
-		);
+if ($action == 'create') 
+{
+	if (! is_array($selected)) 
+	{
+		$error++;
+		setEventMessages($langs->trans('Error_OrderNotChecked'), null, 'errors');
 	} else {
 	} else {
 		$origin = GETPOST('origin');
 		$origin = GETPOST('origin');
 		$originid = GETPOST('originid');
 		$originid = GETPOST('originid');
@@ -87,11 +88,12 @@ include_once DOL_DOCUMENT_ROOT . '/core/class/hookmanager.class.php';
 $hookmanager = new HookManager($db);
 $hookmanager = new HookManager($db);
 $hookmanager->initHooks(array('orderstoinvoicesupplier'));
 $hookmanager->initHooks(array('orderstoinvoicesupplier'));
 
 
+
 /*
 /*
  * Actions
  * Actions
  */
  */
 
 
-if (($action == 'create' || $action == 'add') && empty($mesgs)) {
+if (($action == 'create' || $action == 'add') && ! $error) {
 
 
 	require_once DOL_DOCUMENT_ROOT . '/core/lib/fourn.lib.php';
 	require_once DOL_DOCUMENT_ROOT . '/core/lib/fourn.lib.php';
 	if (! empty($conf->projet->enabled))
 	if (! empty($conf->projet->enabled))

+ 1 - 1
htdocs/fourn/facture/card.php

@@ -1736,7 +1736,7 @@ else
         {
         {
             $num = $db->num_rows($result);
             $num = $db->num_rows($result);
             $i = 0; $totalpaye = 0;
             $i = 0; $totalpaye = 0;
-            print '<table class="nobordernopadding" width="100%">';
+            print '<table class="nobordernopadding paymenttable" width="100%">';
             print '<tr class="liste_titre">';
             print '<tr class="liste_titre">';
             print '<td>'.$langs->trans('Payments').'</td>';
             print '<td>'.$langs->trans('Payments').'</td>';
 			print '<td>'.$langs->trans('Date').'</td>';
 			print '<td>'.$langs->trans('Date').'</td>';

+ 11 - 5
htdocs/install/step1.php

@@ -853,24 +853,30 @@ function write_conf_file($conffile)
 		fputs($fp,"\n");
 		fputs($fp,"\n");
 
 
 		/* Authentication */
 		/* Authentication */
+		fputs($fp, '// Authentication settings');
+        fputs($fp,"\n");
+
 		fputs($fp, '$dolibarr_main_authentication=\'dolibarr\';');
 		fputs($fp, '$dolibarr_main_authentication=\'dolibarr\';');
 		fputs($fp,"\n\n");
 		fputs($fp,"\n\n");
 
 
-		fputs($fp, '// Specific settings');
-        fputs($fp,"\n");
-
         fputs($fp, '//$dolibarr_main_demo=\'autologin,autopass\';');
         fputs($fp, '//$dolibarr_main_demo=\'autologin,autopass\';');
         fputs($fp,"\n");
         fputs($fp,"\n");
 
 
-        fputs($fp, '$dolibarr_main_prod=\'0\';');
+		fputs($fp, '// Security settings');
         fputs($fp,"\n");
         fputs($fp,"\n");
 
 
-        fputs($fp, '$dolibarr_nocsrfcheck=\'0\';');
+        fputs($fp, '$dolibarr_main_prod=\'0\';');
         fputs($fp,"\n");
         fputs($fp,"\n");
 
 
         fputs($fp, '$dolibarr_main_force_https=\''.$main_force_https.'\';');
         fputs($fp, '$dolibarr_main_force_https=\''.$main_force_https.'\';');
 		fputs($fp,"\n");
 		fputs($fp,"\n");
 
 
+        fputs($fp, '$dolibarr_main_restrict_os_commands=\'mysqldump, mysql, pg_dump, pgrestore\';');
+		fputs($fp,"\n");
+		
+        fputs($fp, '$dolibarr_nocsrfcheck=\'0\';');
+        fputs($fp,"\n");
+
 		fputs($fp, '$dolibarr_main_cookie_cryptkey=\''.$key.'\';');
 		fputs($fp, '$dolibarr_main_cookie_cryptkey=\''.$key.'\';');
 		fputs($fp,"\n");
 		fputs($fp,"\n");
 
 

+ 3 - 0
htdocs/langs/en_US/admin.lang

@@ -512,6 +512,8 @@ Module5000Name=Multi-company
 Module5000Desc=Allows you to manage multiple companies
 Module5000Desc=Allows you to manage multiple companies
 Module6000Name=Workflow
 Module6000Name=Workflow
 Module6000Desc=Workflow management
 Module6000Desc=Workflow management
+Module10000Name=Websites
+Module10000Desc=Create public websites with a WYSIWG editor. Just setup your web server to point to the dedicated directory to have it online on the Internet.
 Module20000Name=Leave Requests management
 Module20000Name=Leave Requests management
 Module20000Desc=Declare and follow employees leaves requests
 Module20000Desc=Declare and follow employees leaves requests
 Module39000Name=Product lot
 Module39000Name=Product lot
@@ -1589,3 +1591,4 @@ DetectionNotPossible=Detection not possible
 UrlToGetKeyToUseAPIs=Url to get token to use API (once token has been received it is saved on database user table and will be checked on each future access) 
 UrlToGetKeyToUseAPIs=Url to get token to use API (once token has been received it is saved on database user table and will be checked on each future access) 
 ListOfAvailableAPIs=List of available APIs
 ListOfAvailableAPIs=List of available APIs
 activateModuleDependNotSatisfied=Module "%s" depends on module "%s" that is missing, so module "%1$s" may not work correclty. Please install module "%2$s" or disable module "%1$s" if you want to be safe from any surprise
 activateModuleDependNotSatisfied=Module "%s" depends on module "%s" that is missing, so module "%1$s" may not work correclty. Please install module "%2$s" or disable module "%1$s" if you want to be safe from any surprise
+CommandIsNotInsideAllowedCommands=The command you try to run is not inside list of allowed commands defined into parameter <strong>$dolibarr_main_restrict_os_commands</strong> into <strong>conf.php</strong> file.

+ 1 - 0
htdocs/langs/en_US/bills.lang

@@ -323,6 +323,7 @@ NextDateToExecution=Date for next invoice generation
 DateLastGeneration=Date of latest generation
 DateLastGeneration=Date of latest generation
 MaxPeriodNumber=Max nb of invoice generation
 MaxPeriodNumber=Max nb of invoice generation
 NbOfGenerationDone=Nb of invoice generation already done
 NbOfGenerationDone=Nb of invoice generation already done
+MaxGenerationReached=Maximum nb of generations reached
 InvoiceAutoValidate=Validate invoices automatically
 InvoiceAutoValidate=Validate invoices automatically
 GeneratedFromRecurringInvoice=Generated from template recurring invoice %s
 GeneratedFromRecurringInvoice=Generated from template recurring invoice %s
 DateIsNotEnough=Date not reached yet
 DateIsNotEnough=Date not reached yet

+ 2 - 0
htdocs/langs/en_US/printing.lang

@@ -51,3 +51,5 @@ IPP_Supported=Type of media
 DirectPrintingJobsDesc=This page lists printing jobs found for available printers.
 DirectPrintingJobsDesc=This page lists printing jobs found for available printers.
 GoogleAuthNotConfigured=Google OAuth setup not done. Enable module OAuth and set a Google ID/Secret.
 GoogleAuthNotConfigured=Google OAuth setup not done. Enable module OAuth and set a Google ID/Secret.
 GoogleAuthConfigured=Google OAuth credentials found into setup of module OAuth.
 GoogleAuthConfigured=Google OAuth credentials found into setup of module OAuth.
+PrintingDriverDescprintgcp=Configuration variables for printing driver Google Cloud Print.
+PrintTestDescprintgcp=List of Printers for Google Cloud Print.

+ 7 - 7
htdocs/langs/en_US/products.lang

@@ -83,7 +83,7 @@ SetDefaultBarcodeType=Set barcode type
 BarcodeValue=Barcode value
 BarcodeValue=Barcode value
 NoteNotVisibleOnBill=Note (not visible on invoices, proposals...)
 NoteNotVisibleOnBill=Note (not visible on invoices, proposals...)
 ServiceLimitedDuration=If product is a service with limited duration:
 ServiceLimitedDuration=If product is a service with limited duration:
-MultiPricesAbility=Several level of prices per product/service
+MultiPricesAbility=Several segment of prices per product/service (each customer is in one segment)
 MultiPricesNumPrices=Number of prices
 MultiPricesNumPrices=Number of prices
 AssociatedProductsAbility=Activate the package feature
 AssociatedProductsAbility=Activate the package feature
 AssociatedProducts=Package product
 AssociatedProducts=Package product
@@ -174,13 +174,13 @@ AlwaysUseNewPrice=Always use current price of product/service
 AlwaysUseFixedPrice=Use the fixed price
 AlwaysUseFixedPrice=Use the fixed price
 PriceByQuantity=Different prices by quantity
 PriceByQuantity=Different prices by quantity
 PriceByQuantityRange=Quantity range
 PriceByQuantityRange=Quantity range
-MultipriceRules=Price level rules
-UseMultipriceRules=Use price level rules (defined into product module setup) to autocalculate prices of all other level according to first level
+MultipriceRules=Price segment rules
+UseMultipriceRules=Use price segment rules (defined into product module setup) to autocalculate prices of all other segment according to first segment
 PercentVariationOver=%% variation over %s
 PercentVariationOver=%% variation over %s
 PercentDiscountOver=%% discount over %s
 PercentDiscountOver=%% discount over %s
 ### composition fabrication
 ### composition fabrication
 Build=Produce
 Build=Produce
-ProductsMultiPrice=Products and prices for each price level
+ProductsMultiPrice=Products and prices for each price segment
 ProductsOrServiceMultiPrice=Customer prices (of products or services, multi-prices)
 ProductsOrServiceMultiPrice=Customer prices (of products or services, multi-prices)
 ProductSellByQuarterHT=Products turnover quarterly before tax
 ProductSellByQuarterHT=Products turnover quarterly before tax
 ServiceSellByQuarterHT=Services turnover quarterly before tax
 ServiceSellByQuarterHT=Services turnover quarterly before tax
@@ -201,9 +201,9 @@ DefinitionOfBarCodeForThirdpartyNotComplete=Definition of type or value of bar c
 BarCodeDataForProduct=Barcode information of product %s :
 BarCodeDataForProduct=Barcode information of product %s :
 BarCodeDataForThirdparty=Barcode information of thirdparty %s :
 BarCodeDataForThirdparty=Barcode information of thirdparty %s :
 ResetBarcodeForAllRecords=Define barcode value for all records (this will also reset barcode value already defined with new values)
 ResetBarcodeForAllRecords=Define barcode value for all records (this will also reset barcode value already defined with new values)
-PriceByCustomer=Different price for each customer
-PriceCatalogue=Unique price per product/service
-PricingRule=Rules for customer prices
+PriceByCustomer=Different prices for each customer
+PriceCatalogue=A single sell price per product/service
+PricingRule=Rules for sell prices
 AddCustomerPrice=Add price by customer
 AddCustomerPrice=Add price by customer
 ForceUpdateChildPriceSoc=Set same price on customer subsidiaries
 ForceUpdateChildPriceSoc=Set same price on customer subsidiaries
 PriceByCustomerLog=Log of previous customer prices
 PriceByCustomerLog=Log of previous customer prices

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

@@ -833,7 +833,8 @@ class Livraison extends CommonObject
 
 
 		$now=dol_now();
 		$now=dol_now();
 
 
-		// Charge tableau des produits prodids
+        // Load array of products prodids
+		$num_prods = 0;
 		$prodids = array();
 		$prodids = array();
 		$sql = "SELECT rowid";
 		$sql = "SELECT rowid";
 		$sql.= " FROM ".MAIN_DB_PREFIX."product";
 		$sql.= " FROM ".MAIN_DB_PREFIX."product";

+ 1 - 1
htdocs/projet/list.php

@@ -416,7 +416,7 @@ if ($resql)
     if (! empty($arrayfields['p.opp_amount']['checked']))    print_liste_field_titre($arrayfields['p.opp_amount']['label'],$_SERVER["PHP_SELF"],'p.opp_amount',"",$param,'align="right"',$sortfield,$sortorder);
     if (! empty($arrayfields['p.opp_amount']['checked']))    print_liste_field_titre($arrayfields['p.opp_amount']['label'],$_SERVER["PHP_SELF"],'p.opp_amount',"",$param,'align="right"',$sortfield,$sortorder);
 	if (! empty($arrayfields['p.fk_opp_status']['checked'])) print_liste_field_titre($arrayfields['p.fk_opp_status']['label'],$_SERVER["PHP_SELF"],'p.fk_opp_status',"",$param,'align="center"',$sortfield,$sortorder);
 	if (! empty($arrayfields['p.fk_opp_status']['checked'])) print_liste_field_titre($arrayfields['p.fk_opp_status']['label'],$_SERVER["PHP_SELF"],'p.fk_opp_status',"",$param,'align="center"',$sortfield,$sortorder);
     if (! empty($arrayfields['p.opp_percent']['checked']))   print_liste_field_titre($arrayfields['p.opp_percent']['label'],$_SERVER["PHP_SELF"],'p.opp_percent',"",$param,'align="right"',$sortfield,$sortorder);
     if (! empty($arrayfields['p.opp_percent']['checked']))   print_liste_field_titre($arrayfields['p.opp_percent']['label'],$_SERVER["PHP_SELF"],'p.opp_percent',"",$param,'align="right"',$sortfield,$sortorder);
-    if (! empty($arrayfields['p.budget_amount']['checked'])) print_liste_field_titre($arrayfields['p.budget_amount']['label'],$_SERVER["PHP_SELF"],'p.budget_amount',"",$param,'align="center"',$sortfield,$sortorder);
+    if (! empty($arrayfields['p.budget_amount']['checked'])) print_liste_field_titre($arrayfields['p.budget_amount']['label'],$_SERVER["PHP_SELF"],'p.budget_amount',"",$param,'align="right"',$sortfield,$sortorder);
     // Extra fields
     // Extra fields
 	if (is_array($extrafields->attribute_label) && count($extrafields->attribute_label))
 	if (is_array($extrafields->attribute_label) && count($extrafields->attribute_label))
 	{
 	{

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

@@ -2186,7 +2186,8 @@ class SupplierProposal extends CommonObject
     {
     {
         global $user,$langs,$conf;
         global $user,$langs,$conf;
 
 
-        // Charge tableau des produits prodids
+        // Load array of products prodids
+        $num_prods = 0; 
         $prodids = array();
         $prodids = array();
         $sql = "SELECT rowid";
         $sql = "SELECT rowid";
         $sql.= " FROM ".MAIN_DB_PREFIX."product";
         $sql.= " FROM ".MAIN_DB_PREFIX."product";

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

@@ -4093,7 +4093,7 @@ select {
     /* display: inline-block; */	/* We can't set this. This disable ability to make */
     /* display: inline-block; */	/* We can't set this. This disable ability to make */
     /* TODO modified by jmobile, replace jmobile with pure css*/
     /* TODO modified by jmobile, replace jmobile with pure css*/
     overflow:hidden;
     overflow:hidden;
-    white-space: nowrap;
+    white-space: nowrap;			/* Enabling this make behaviour strange when selecting the empty value if this empty value is '' instead of '&nbsp;' */
     text-overflow: ellipsis;
     text-overflow: ellipsis;
 }
 }
 .fiche .ui-controlgroup {
 .fiche .ui-controlgroup {

+ 48 - 46
htdocs/user/card.php

@@ -54,6 +54,7 @@ $mode		= GETPOST('mode','alpha');
 $confirm	= GETPOST('confirm','alpha');
 $confirm	= GETPOST('confirm','alpha');
 $subaction	= GETPOST('subaction','alpha');
 $subaction	= GETPOST('subaction','alpha');
 $group		= GETPOST("group","int",3);
 $group		= GETPOST("group","int",3);
+$cancel     = GETPOST('cancel');
 
 
 // Define value to know what current user can do on users
 // Define value to know what current user can do on users
 $canadduser=(! empty($user->admin) || $user->rights->user->user->creer);
 $canadduser=(! empty($user->admin) || $user->rights->user->user->creer);
@@ -299,7 +300,8 @@ if (empty($reshook)) {
 		}
 		}
 	}
 	}
 
 
-	if ($action == 'update' && !$_POST["cancel"]) {
+	if ($action == 'update' && ! $cancel) 
+	{
 		require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
 		require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
 
 
 		if ($caneditfield)    // Case we can edit all field
 		if ($caneditfield)    // Case we can edit all field
@@ -395,7 +397,7 @@ if (empty($reshook)) {
 					if (!$error) {
 					if (!$error) {
 						$ret = $object->update($user);
 						$ret = $object->update($user);
 						if ($ret < 0) {
 						if ($ret < 0) {
-							$error ++;
+							$error++;
 							if ($db->errno() == 'DB_ERROR_RECORD_ALREADY_EXISTS') {
 							if ($db->errno() == 'DB_ERROR_RECORD_ALREADY_EXISTS') {
 								$langs->load("errors");
 								$langs->load("errors");
 								setEventMessages($langs->trans("ErrorLoginAlreadyExists", $object->login), null, 'errors');
 								setEventMessages($langs->trans("ErrorLoginAlreadyExists", $object->login), null, 'errors');
@@ -1440,6 +1442,49 @@ else
 				print '</td></tr>';
 				print '</td></tr>';
 		    }
 		    }
 
 
+		    // Multicompany
+		    // TODO This should be done with hook formObjectOption
+		    if (is_object($mc))
+		    {
+		        if (! empty($conf->multicompany->enabled) && empty($conf->multicompany->transverse_mode) && $conf->entity == 1 && $user->admin && ! $user->entity)
+		        {
+		            print '<tr><td>'.$langs->trans("Entity").'</td><td>';
+		            if (empty($object->entity))
+		            {
+		                print $langs->trans("AllEntities");
+		            }
+		            else
+		            {
+		                $mc->getInfo($object->entity);
+		                print $mc->label;
+		            }
+		            print "</td></tr>\n";
+		        }
+		    }
+		    
+		    if (isset($conf->file->main_authentication) && preg_match('/openid/',$conf->file->main_authentication) && ! empty($conf->global->MAIN_OPENIDURL_PERUSER))
+		    {
+		        print '<tr><td>'.$langs->trans("OpenIDURL").'</td>';
+		        print '<td>'.$object->openid.'</td>';
+		        print "</tr>\n";
+		    }
+		    
+		    print '<tr><td class="titlefield">'.$langs->trans("LastConnexion").'</td>';
+		    print '<td>'.dol_print_date($object->datelastlogin,"dayhour").'</td>';
+		    print "</tr>\n";
+		    
+		    print '<tr><td>'.$langs->trans("PreviousConnexion").'</td>';
+		    print '<td>'.dol_print_date($object->datepreviouslogin,"dayhour").'</td>';
+		    print "</tr>\n";
+		    
+		    // Other attributes
+		    $parameters=array();
+		    $reshook=$hookmanager->executeHooks('formObjectOptions',$parameters,$object,$action);    // Note that $action and $object may have been modified by hook
+		    if (empty($reshook) && ! empty($extrafields->attribute_label))
+		    {
+		        print $object->showOptionals($extrafields);
+		    }
+		    
             // Company / Contact
             // Company / Contact
             if (! empty($conf->societe->enabled))
             if (! empty($conf->societe->enabled))
             {
             {
@@ -1488,49 +1533,6 @@ else
                 print '</tr>'."\n";
                 print '</tr>'."\n";
             }
             }
 
 
-            // Multicompany
-            // TODO This should be done with hook formObjectOption
-            if (is_object($mc))
-            {
-	            if (! empty($conf->multicompany->enabled) && empty($conf->multicompany->transverse_mode) && $conf->entity == 1 && $user->admin && ! $user->entity)
-	            {
-	            	print '<tr><td>'.$langs->trans("Entity").'</td><td>';
-	            	if (empty($object->entity))
-	            	{
-	            		print $langs->trans("AllEntities");
-	            	}
-	            	else
-	            	{
-	            		$mc->getInfo($object->entity);
-	            		print $mc->label;
-	            	}
-	            	print "</td></tr>\n";
-	            }
-            }
-
-            if (isset($conf->file->main_authentication) && preg_match('/openid/',$conf->file->main_authentication) && ! empty($conf->global->MAIN_OPENIDURL_PERUSER))
-            {
-                print '<tr><td>'.$langs->trans("OpenIDURL").'</td>';
-                print '<td>'.$object->openid.'</td>';
-                print "</tr>\n";
-            }
-
-            print '<tr><td class="titlefield">'.$langs->trans("LastConnexion").'</td>';
-            print '<td>'.dol_print_date($object->datelastlogin,"dayhour").'</td>';
-            print "</tr>\n";
-
-            print '<tr><td>'.$langs->trans("PreviousConnexion").'</td>';
-            print '<td>'.dol_print_date($object->datepreviouslogin,"dayhour").'</td>';
-            print "</tr>\n";
-
-            // Other attributes
-			$parameters=array();
-			$reshook=$hookmanager->executeHooks('formObjectOptions',$parameters,$object,$action);    // Note that $action and $object may have been modified by hook
-			if (empty($reshook) && ! empty($extrafields->attribute_label))
-			{
-				print $object->showOptionals($extrafields);
-			}
-
 			print "</table>\n";
 			print "</table>\n";
 			print '</div>';
 			print '</div>';
 
 
@@ -2222,7 +2224,7 @@ else
 			print '<td>';
 			print '<td>';
 			$cate_arbo = $form->select_all_categories( Categorie::TYPE_CONTACT, null, null, null, null, 1 );
 			$cate_arbo = $form->select_all_categories( Categorie::TYPE_CONTACT, null, null, null, null, 1 );
 			$c = new Categorie( $db );
 			$c = new Categorie( $db );
-			$cats = $c->containing( $object->id, 'user' );
+			$cats = $c->containing($object->id, Categorie::TYPE_USER);
 			foreach ($cats as $cat) {
 			foreach ($cats as $cat) {
 				$arrayselected[] = $cat->id;
 				$arrayselected[] = $cat->id;
 			}
 			}

+ 15 - 9
htdocs/user/class/user.class.php

@@ -1332,14 +1332,14 @@ class User extends CommonObject
 			// If user is linked to a member, remove old link to this member
 			// If user is linked to a member, remove old link to this member
 			if ($this->fk_member > 0)
 			if ($this->fk_member > 0)
 			{
 			{
-				$sql = "UPDATE ".MAIN_DB_PREFIX."user SET fk_member = NULL where fk_member = ".$this->fk_member;
-				dol_syslog(get_class($this)."::update", LOG_DEBUG);
+				dol_syslog(get_class($this)."::update remove link with member. We will recreate it later", LOG_DEBUG);
+			    $sql = "UPDATE ".MAIN_DB_PREFIX."user SET fk_member = NULL where fk_member = ".$this->fk_member;
 				$resql = $this->db->query($sql);
 				$resql = $this->db->query($sql);
 				if (! $resql) { $this->error=$this->db->error(); $this->db->rollback(); return -5; }
 				if (! $resql) { $this->error=$this->db->error(); $this->db->rollback(); return -5; }
 			}
 			}
 			// Set link to user
 			// Set link to user
+			dol_syslog(get_class($this)."::update set link with member", LOG_DEBUG);
 			$sql = "UPDATE ".MAIN_DB_PREFIX."user SET fk_member =".($this->fk_member>0?$this->fk_member:'null')." where rowid = ".$this->id;
 			$sql = "UPDATE ".MAIN_DB_PREFIX."user SET fk_member =".($this->fk_member>0?$this->fk_member:'null')." where rowid = ".$this->id;
-			dol_syslog(get_class($this)."::update", LOG_DEBUG);
 			$resql = $this->db->query($sql);
 			$resql = $this->db->query($sql);
 			if (! $resql) { $this->error=$this->db->error(); $this->db->rollback(); return -5; }
 			if (! $resql) { $this->error=$this->db->error(); $this->db->rollback(); return -5; }
 
 
@@ -1347,6 +1347,8 @@ class User extends CommonObject
 			{
 			{
 				if ($this->fk_member > 0 && ! $nosyncmember)
 				if ($this->fk_member > 0 && ! $nosyncmember)
 				{
 				{
+				    dol_syslog(get_class($this)."::update user is linked with a member. We try to update member too.", LOG_DEBUG);
+				    
 					require_once DOL_DOCUMENT_ROOT.'/adherents/class/adherent.class.php';
 					require_once DOL_DOCUMENT_ROOT.'/adherents/class/adherent.class.php';
 
 
 					// This user is linked with a member, so we also update members informations
 					// This user is linked with a member, so we also update members informations
@@ -1360,7 +1362,9 @@ class User extends CommonObject
 						$adh->lastname=$this->lastname;
 						$adh->lastname=$this->lastname;
 						$adh->login=$this->login;
 						$adh->login=$this->login;
 						$adh->gender=$this->gender;
 						$adh->gender=$this->gender;
+						
 						$adh->pass=$this->pass;
 						$adh->pass=$this->pass;
+						
 						$adh->societe=(empty($adh->societe) && $this->societe_id ? $this->societe_id : $adh->societe);
 						$adh->societe=(empty($adh->societe) && $this->societe_id ? $this->societe_id : $adh->societe);
 
 
 						$adh->email=$this->email;
 						$adh->email=$this->email;
@@ -1373,17 +1377,19 @@ class User extends CommonObject
 						$adh->user_id=$this->id;
 						$adh->user_id=$this->id;
 						$adh->user_login=$this->login;
 						$adh->user_login=$this->login;
 
 
-						$result=$adh->update($user,0,1);
-						if ($result < 0)
+						$result=$adh->update($user,0,1,0);
+                        if ($result < 0)
 						{
 						{
-							$this->error=$luser->error;
-							dol_syslog(get_class($this)."::update ".$this->error,LOG_ERR);
+						    $this->error=$adh->error;
+						    $this->errors=$adh->errors;
+							dol_syslog(get_class($this)."::update error after calling adh->update to sync it with user: ".$this->error, LOG_ERR);
 							$error++;
 							$error++;
 						}
 						}
 					}
 					}
 					else
 					else
 					{
 					{
 						$this->error=$adh->error;
 						$this->error=$adh->error;
+						$this->errors=$adh->errors;
 						$error++;
 						$error++;
 					}
 					}
 				}
 				}
@@ -1495,7 +1501,7 @@ class User extends CommonObject
 			$password=getRandomPassword(false);
 			$password=getRandomPassword(false);
 		}
 		}
 
 
-		// Crypte avec md5
+		// Crypt password
 		$password_crypted = dol_hash($password);
 		$password_crypted = dol_hash($password);
 
 
 		// Mise a jour
 		// Mise a jour
@@ -1539,7 +1545,7 @@ class User extends CommonObject
 
 
 						if ($result >= 0)
 						if ($result >= 0)
 						{
 						{
-							$result=$adh->setPassword($user,$this->pass,0,1);	// Cryptage non gere dans module adherent
+							$result=$adh->setPassword($user,$this->pass,(empty($conf->global->DATABASE_PWD_ENCRYPTED)?0:1),1);	// Cryptage non gere dans module adherent
 							if ($result < 0)
 							if ($result < 0)
 							{
 							{
 								$this->error=$adh->error;
 								$this->error=$adh->error;

+ 3 - 4
scripts/product/migrate_picture_path.php

@@ -1,6 +1,6 @@
 #!/usr/bin/env php
 #!/usr/bin/env php
 <?php
 <?php
-/* Copyright (C) 2007-2013 Laurent Destailleur  <eldy@users.sourceforge.net>
+/* Copyright (C) 2007-2016 Laurent Destailleur  <eldy@users.sourceforge.net>
  * Copyright (C) 2015 Jean Heimburger  <http://tiaris.eu>
  * Copyright (C) 2015 Jean Heimburger  <http://tiaris.eu>
  *
  *
  * This program is free software; you can redistribute it and/or modify
  * This program is free software; you can redistribute it and/or modify
@@ -21,7 +21,6 @@
  *      \file       scripts/product/migrate_picture_path.php
  *      \file       scripts/product/migrate_picture_path.php
  *		\ingroup    scripts
  *		\ingroup    scripts
  *      \brief      Migrate pictures from old system prior to 3.7 to new path for 3.7+
  *      \brief      Migrate pictures from old system prior to 3.7 to new path for 3.7+
- *
  */
  */
 
 
 $sapi_type = php_sapi_name();
 $sapi_type = php_sapi_name();
@@ -119,7 +118,7 @@ function migrate_product_photospath($product)
 		$handle=opendir($origin_osencoded);
 		$handle=opendir($origin_osencoded);
         if (is_resource($handle))
         if (is_resource($handle))
         {
         {
-        	while (($file = readdir($handle)) != false)
+        	while (($file = readdir($handle)) !== false)
     		{
     		{
      			if ($file != '.' && $file != '..' && is_dir($origin_osencoded.'/'.$file))
      			if ($file != '.' && $file != '..' && is_dir($origin_osencoded.'/'.$file))
     			{
     			{
@@ -127,7 +126,7 @@ function migrate_product_photospath($product)
     				if (is_resource($thumbs))
     				if (is_resource($thumbs))
         			{
         			{
 	     				dol_mkdir($destin.'/'.$file);
 	     				dol_mkdir($destin.'/'.$file);
-	     				while (($thumb = readdir($thumbs)) != false)
+	     				while (($thumb = readdir($thumbs)) !== false)
 		    			{
 		    			{
 		    				dol_move($origin.'/'.$file.'/'.$thumb, $destin.'/'.$file.'/'.$thumb);
 		    				dol_move($origin.'/'.$file.'/'.$thumb, $destin.'/'.$file.'/'.$thumb);
 		    			}
 		    			}

+ 1 - 1
test/phpunit/CategorieTest.php

@@ -200,7 +200,7 @@ class CategorieTest extends PHPUnit_Framework_TestCase
 
 
         // Get list of categories for product
         // Get list of categories for product
         $localcateg=new Categorie($this->savdb);
         $localcateg=new Categorie($this->savdb);
-        $listofcateg=$localcateg->containing($localobject2->id, 'product', 'label');
+        $listofcateg=$localcateg->containing($localobject2->id, Categorie::TYPE_PRODUCT, 'label');
         $this->assertTrue(in_array('Specimen Category for product',$listofcateg), 'Categ not found linked to product when it should');
         $this->assertTrue(in_array('Specimen Category for product',$listofcateg), 'Categ not found linked to product when it should');
 
 
         return $id;
         return $id;

+ 9 - 3
test/phpunit/PgsqlTest.php

@@ -162,11 +162,17 @@ class PgsqlTest extends PHPUnit_Framework_TestCase
         print __METHOD__." result=".$result."\n";
         print __METHOD__." result=".$result."\n";
     	$this->assertEquals($result, $sql.' DEFERRABLE INITIALLY IMMEDIATE;');
     	$this->assertEquals($result, $sql.' DEFERRABLE INITIALLY IMMEDIATE;');
 
 
-        // Create a constraint
-		$sql='SELECT a.b, GROUP_CONCAT(a.c) FROM table GROUP BY a.b';
+        // Test GROUP_CONCAT (without SEPARATOR)
+		$sql="SELECT a.b, GROUP_CONCAT(a.c) FROM table GROUP BY a.b";
+		$result=DoliDBPgsql::convertSQLFromMysql($sql);
+        print __METHOD__." result=".$result."\n";
+    	$this->assertEquals($result, "SELECT a.b, STRING_AGG(a.c, ',') FROM table GROUP BY a.b", 'Test GROUP_CONCAT (without SEPARATOR)');
+    	
+        // Test GROUP_CONCAT (with SEPARATOR)
+		$sql="SELECT a.b, GROUP_CONCAT(a.c SEPARATOR ',') FROM table GROUP BY a.b";
 		$result=DoliDBPgsql::convertSQLFromMysql($sql);
 		$result=DoliDBPgsql::convertSQLFromMysql($sql);
         print __METHOD__." result=".$result."\n";
         print __METHOD__." result=".$result."\n";
-    	$this->assertEquals($result, "SELECT a.b, STRING_AGG(a.c, ',') FROM table GROUP BY a.b");
+    	$this->assertEquals($result, "SELECT a.b, STRING_AGG(a.c, ',') FROM table GROUP BY a.b", 'Test GROUP_CONCAT (with SEPARATOR)');
     	
     	
     	return $result;
     	return $result;
     }
     }