Ver código fonte

NEW Add substitution key __DATE_YMD__, __DATE_DUE_YMD__, __AMOUNT__ and
__AMOUNT_WO_TAX__ into emails templates.

Laurent Destailleur 9 anos atrás
pai
commit
af09528738
34 arquivos alterados com 266 adições e 117 exclusões
  1. 35 0
      ChangeLog
  2. 0 1
      build/debian/dolibarr.docs
  3. 1 1
      build/debian/watch
  4. 16 10
      build/doxygen/doxygen_footer.html
  5. 17 3
      build/doxygen/doxygen_header.html
  6. 12 4
      build/makepack-dolibarr.pl
  7. 3 1
      dev/translation/sanity_check_en_langfiles.php
  8. 1 1
      htdocs/adherents/list.php
  9. 1 1
      htdocs/comm/propal/card.php
  10. 36 27
      htdocs/comm/remx.php
  11. 4 2
      htdocs/compta/bank/card.php
  12. 22 19
      htdocs/compta/facture.php
  13. 16 2
      htdocs/compta/facture/class/facture.class.php
  14. 16 4
      htdocs/core/class/html.formmail.class.php
  15. 1 1
      htdocs/core/modules/modAgenda.class.php
  16. 4 3
      htdocs/core/triggers/interface_50_modAgenda_ActionsAuto.class.php
  17. 2 1
      htdocs/don/class/don.class.php
  18. 5 0
      htdocs/expensereport/card.php
  19. 1 0
      htdocs/expensereport/class/expensereport.class.php
  20. 1 1
      htdocs/install/mysql/data/llx_00_c_country.sql
  21. 4 4
      htdocs/install/mysql/data/llx_c_action_trigger.sql
  22. 10 6
      htdocs/install/mysql/data/llx_c_tva.sql
  23. 3 3
      htdocs/install/mysql/tables/llx_product.sql
  24. 1 1
      htdocs/langs/en_US/admin.lang
  25. 5 0
      htdocs/langs/en_US/boxes.lang
  26. 2 0
      htdocs/langs/en_US/companies.lang
  27. 2 3
      htdocs/product/index.php
  28. 13 2
      htdocs/product/stock/class/mouvementstock.class.php
  29. 6 2
      htdocs/product/stock/mouvement.php
  30. 2 2
      htdocs/product/stock/tpl/stockcorrection.tpl.php
  31. 2 3
      htdocs/projet/card.php
  32. 2 2
      htdocs/projet/element.php
  33. 2 2
      htdocs/societe/notify/card.php
  34. 18 5
      htdocs/societe/soc.php

+ 35 - 0
ChangeLog

@@ -162,6 +162,41 @@ So if you included it into your module, change your code like this to be compati
 
 
 
+***** ChangeLog for 3.9.3 compared to 3.9.2 *****
+FIX: #4383 $userid not defined
+FIX: #4448 $filebonprev is not used, $this->filename now
+FIX: #4455
+FIX: #4749
+FIX: #4756
+FIX: #4828
+FIX: #4926
+FIX: #4964 buyprice in customer from shipping buyprice wasn't load in expedition::fetch_lines
+FIX: #5004
+FIX: #5068
+FIX: #5170 tva sign with INVOICE_POSITIVE_CREDIT_NOTE option
+FIX: #5338 use of not initialized var $aphour, $apmin, etc
+FIX: #5343
+FIX: #5380
+FIX: #5383 bad object id on don delete
+FIX: #5414
+FIX: #5470 User of expense report in bank transactions page is not correct
+FIX: a case of corrupted ODT by Word that insert <text:s> when it should not.
+FIX: Can't create thirdparty or validate invoice if profid is mandatory and profid does not exists for other countries
+FIX: dasboard wrong for late invoice
+FIX: duplicate jquery.js files
+FIX: extrafield cloned on project clone
+FIX: Failed to open file
+FIX: Filter on opportunity amount and budget
+FIX: form_confirm to delete payment on supplier invoice
+FIX: javascript error with german-switzerland language
+FIX: large expense note
+FIX: Missing original .js file (license violation if sources are not provided)
+FIX: Option strict mode compatibility
+FIX: product stats all bloc module without enbaled test
+FIX: receiving link never works
+FIX: task ODT company object not correctly retrieved
+FIX: Translate group perms as it is done into user perms
+FIX: We must take the last recent defined price when using price level
 
 ***** ChangeLog for 3.9.2 compared to 3.9.1 *****
 FIX: #4813 Won translation for the key OppStatusWON instead OppStatusWIN

+ 0 - 1
build/debian/dolibarr.docs

@@ -1,2 +1 @@
 README.md
-README-FR.md

+ 1 - 1
build/debian/watch

@@ -2,4 +2,4 @@
 version=3
 
 #http://sf.net/dolibarr/dolibarr-(.+)\.tgz
-http://www.dolibarr.org/files/stable/standard/dolibarr-(.+)\.tgz
+http://www.dolibarr.org/files/stable/package_debian-ubuntu/dolibarr_(.+)\.orig\.tar\.gz

+ 16 - 10
build/doxygen/doxygen_footer.html

@@ -4,17 +4,14 @@ File added into doxygen generated documentation
 
 
 <!-- Google analytics -->
-<script type="text/javascript">
+<script>
+  (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
+  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
+  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
+  })(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
 
-  var _gaq = _gaq || [];
-  _gaq.push(['_setAccount', 'UA-9049390-1']);
-  _gaq.push(['_trackPageview']);
-
-  (function() {
-    var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
-    ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
-    var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
-  })();
+  ga('create', 'UA-9049390-16', 'auto');
+  ga('send', 'pageview');
 
 </script>
 <!-- End google analytics -->
@@ -41,5 +38,14 @@ google_ad_height = 60;
 <br>
 
 </div>
+
+<!-- Twitter ad collector -->
+<script src="//platform.twitter.com/oct.js" type="text/javascript"></script>
+<script type="text/javascript">twttr.conversion.trackPid('ntm4n', { tw_sale_amount: 0, tw_order_quantity: 0 });</script>
+<noscript>
+<img height="1" width="1" style="display:none;" alt="" src="https://analytics.twitter.com/i/adsct?txn_id=ntm4n&p_id=Twitter&tw_sale_amount=0&tw_order_quantity=0" />
+<img height="1" width="1" style="display:none;" alt="" src="//t.co/i/adsct?txn_id=ntm4n&p_id=Twitter&tw_sale_amount=0&tw_order_quantity=0" />
+</noscript>
+
 </body>
 </html>

+ 17 - 3
build/doxygen/doxygen_header.html

@@ -1,6 +1,4 @@
-<!-- 
-File added into doxygen generated documentation
--->
+<!-- File added into doxygen generated documentation -->
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 <html xmlns="http://www.w3.org/1999/xhtml">
 <head>
@@ -14,7 +12,23 @@ File added into doxygen generated documentation
 <link href="tabs.css" rel="stylesheet" type="text/css" />
 <link href="doxygen.css" rel="stylesheet" type="text/css" />
 <!-- End from dolibarr.org -->
+
+<!-- Facebook Pixel Code -->
+<script>
+!function(f,b,e,v,n,t,s){if(f.fbq)return;n=f.fbq=function(){n.callMethod?
+n.callMethod.apply(n,arguments):n.queue.push(arguments)};if(!f._fbq)f._fbq=n;
+n.push=n;n.loaded=!0;n.version='2.0';n.queue=[];t=b.createElement(e);t.async=!0;
+t.src=v;s=b.getElementsByTagName(e)[0];s.parentNode.insertBefore(t,s)}(window,
+document,'script','//connect.facebook.net/en_US/fbevents.js');
+
+fbq('init', '1998533953704960');
+fbq('track', "PageView");</script>
+<noscript><img height="1" width="1" style="display:none"
+src="https://www.facebook.com/tr?id=1998533953704960&ev=PageView&noscript=1"
+/></noscript>
+<!-- End Facebook Pixel Code -->
 </head>
+
 <body>
 <div id="top">
 

+ 12 - 4
build/makepack-dolibarr.pl

@@ -173,6 +173,7 @@ $build =~ s/-.*$//g;
 # now build is 0+nmu1 for example
 $FILENAMEDEBNATIVE="${PROJECT}_${MAJOR}.${MINOR}.${build}";
 $FILENAMEDEB="${PROJECT}_${MAJOR}.${MINOR}.${newbuild}";
+$FILENAMEDEBSHORT="${PROJECT}_${MAJOR}.${MINOR}.${build}";
 
 
 my $copyalreadydone=0;
@@ -389,10 +390,15 @@ if ($nboftargetok) {
 			{
 				print 'Run git tag -a -f -m "'.$MAJOR.'.'.$MINOR.'.'.$BUILD.'" "'.$MAJOR.'.'.$MINOR.'.'.$BUILD.'"'."\n";
 				$ret=`git tag -a -f -m "$MAJOR.$MINOR.$BUILD" "$MAJOR.$MINOR.$BUILD"`;
+				print 'Run git push -f --tags'."\n";
+				$ret=`git push -f --tags`;
 			}
 		}
-		print 'Run git push --tags'."\n";
-		$ret=`git push --tags`;
+		else
+		{
+			print 'Run git push --tags'."\n";
+			$ret=`git push --tags`;
+		}
 		chdir("$olddir");
 	}
 	
@@ -824,7 +830,7 @@ if ($nboftargetok) {
 			$ret=`$cmd`;
 
 			print "Remove other files\n";
-			$ret=`rm -f  $BUILDROOT/$PROJECT.tmp/README-FR`;
+			$ret=`rm -f  $BUILDROOT/$PROJECT.tmp/README-FR.md`;
 			$ret=`rm -f  $BUILDROOT/$PROJECT.tmp/build/README`;
 			$ret=`rm -f  $BUILDROOT/$PROJECT.tmp/build/README-FR`;
 			$ret=`rm -fr $BUILDROOT/$PROJECT.tmp/build/aps`;
@@ -1127,6 +1133,7 @@ if ($nboftargetok) {
 		%filestoscansf=(
 			"$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/${FILENAMEDEBSHORT}.orig.tar.gz"=>'none',
 			"$DESTI/package_windows/$FILENAMEEXEDOLIWAMP.exe"=>'Dolibarr installer for Windows (DoliWamp)',
 			"$DESTI/standard/$FILENAMETGZ.tgz"=>'Dolibarr ERP-CRM',
 			"$DESTI/standard/$FILENAMETGZ.zip"=>'Dolibarr ERP-CRM'
@@ -1134,6 +1141,7 @@ if ($nboftargetok) {
 		%filestoscanstableasso=(
 			"$DESTI/package_rpm_generic/$FILENAMERPM"=>'package_rpm_generic',
 			"$DESTI/package_debian-ubuntu/${FILENAMEDEB}_all.deb"=>'package_debian-ubuntu',
+			"$DESTI/package_debian-ubuntu/${FILENAMEDEBSHORT}.orig.tar.gz"=>'package_debian-ubuntu',
 			"$DESTI/package_windows/$FILENAMEEXEDOLIWAMP.exe"=>'package_windows',
 			"$DESTI/standard/$FILENAMETGZ.tgz"=>'standard',
 			"$DESTI/standard/$FILENAMETGZ.zip"=>'standard'
@@ -1195,7 +1203,7 @@ if ($nboftargetok) {
 
 				print "\n";
 	    		
-	    		if ($target eq 'SF') { 
+	    		if ($target eq 'SF' && $filestoscan{$file} ne 'none') { 
 	    			$destFolder="$NEWPUBLISH/$filestoscan{$file}/".$MAJOR.'.'.$MINOR.'.'.$BUILD;
 	    		}
 	    		elsif ($target eq 'ASSO' and $NEWPUBLISH =~ /stable/) {

+ 3 - 1
dev/translation/sanity_check_en_langfiles.php

@@ -295,7 +295,9 @@ if ((! empty($_REQUEST['unused']) && $_REQUEST['unused'] == 'true') || (isset($a
 	    if (preg_match('/^DescADHERENT_/', $value)) $qualifiedforclean=0;
 	    if (preg_match('/^SubmitTranslation/', $value)) $qualifiedforclean=0;
 	    if (preg_match('/^ModuleCompanyCode/', $value)) $qualifiedforclean=0;
-	    
+	    // boxes.lang
+	    if (preg_match('/^BoxTitleLast/', $value)) $qualifiedforclean=0;
+	    if (preg_match('/^BoxTitleLatest/', $value)) $qualifiedforclean=0;
 	    // main.lang
 	    if (preg_match('/^Duration/', $value)) $qualifiedforclean=0;
 	    if (preg_match('/^FormatDate/', $value)) $qualifiedforclean=0;

+ 1 - 1
htdocs/adherents/list.php

@@ -84,7 +84,7 @@ $search_array_options=$extrafields->getOptionalsFromPost($extralabels,'','search
 // List of fields to search into when doing a "search in all"
 $fieldstosearchall = array(
     'd.rowid'=>'Ref',
-    //'d.ref'=>'Ref',
+    'd.login'=>'Login',
     'd.lastname'=>'Lastname',
     'd.firstname'=>'Firstname',
     'd.login'=>'Login',

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

@@ -2417,7 +2417,7 @@ if ($action == 'create')
 
 		// Tableau des substitutions
 		$formmail->setSubstitFromObject($object);
-		$formmail->substit['__PROPREF__'] = $object->ref;
+		$formmail->substit['__PROPREF__'] = $object->ref; // For backward compatibility
 
 		// Find the good contact adress
 		$custcontact = '';

+ 36 - 27
htdocs/comm/remx.php

@@ -135,7 +135,7 @@ if ($action == 'confirm_split' && GETPOST("confirm") == 'yes')
 	}
 }
 
-if ($action == 'setremise')
+if ($action == 'setremise' && $user->rights->societe->creer)
 {
 	//if ($user->rights->societe->creer)
 	//if ($user->rights->facture->creer)
@@ -266,39 +266,48 @@ if ($socid > 0)
 	print '<tr><td class="titlefield">'.$langs->trans("CustomerAbsoluteDiscountAllUsers").'</td>';
 	print '<td>'.$remise_all.'&nbsp;'.$langs->trans("Currency".$conf->currency).' '.$langs->trans("HT").'</td></tr>';
 
-	print '<tr><td>'.$langs->trans("CustomerAbsoluteDiscountMy").'</td>';
-	print '<td>'.$remise_user.'&nbsp;'.$langs->trans("Currency".$conf->currency).' '.$langs->trans("HT").'</td></tr>';
+	if (! empty($user->fk_soc))    // No need to show this for external users
+	{
+    	print '<tr><td>'.$langs->trans("CustomerAbsoluteDiscountMy").'</td>';
+    	print '<td>'.$remise_user.'&nbsp;'.$langs->trans("Currency".$conf->currency).' '.$langs->trans("HT").'</td></tr>';
+	}
 	print '</table>';
-	print '<br>';
-
-	print load_fiche_titre($langs->trans("NewGlobalDiscount"),'','');
-	print '<table class="border" width="100%">';
-	print '<tr><td width="38%" class="fieldrequired">'.$langs->trans("AmountHT").'</td>';
-	print '<td><input type="text" size="5" name="amount_ht" value="'.$_POST["amount_ht"].'">';
-	print '<span class="hideonsmartphone">&nbsp;'.$langs->trans("Currency".$conf->currency).'</span></td></tr>';
-	print '<tr><td width="38%">'.$langs->trans("VAT").'</td>';
-	print '<td>';
-	print $form->load_tva('tva_tx',GETPOST('tva_tx'),$mysoc,$object);
-	print '</td></tr>';
-	print '<tr><td class="fieldrequired" >'.$langs->trans("NoteReason").'</td>';
-	print '<td><input type="text" size="60" name="desc" value="'.GETPOST('desc').'"></td></tr>';
-
-	print "</table>";
 
+	if ($user->rights->societe->creer)
+	{
+    	print '<br>';
+    
+    	print load_fiche_titre($langs->trans("NewGlobalDiscount"),'','');
+    	print '<table class="border" width="100%">';
+    	print '<tr><td width="38%" class="fieldrequired">'.$langs->trans("AmountHT").'</td>';
+    	print '<td><input type="text" size="5" name="amount_ht" value="'.$_POST["amount_ht"].'">';
+    	print '<span class="hideonsmartphone">&nbsp;'.$langs->trans("Currency".$conf->currency).'</span></td></tr>';
+    	print '<tr><td width="38%">'.$langs->trans("VAT").'</td>';
+    	print '<td>';
+    	print $form->load_tva('tva_tx',GETPOST('tva_tx'),$mysoc,$object);
+    	print '</td></tr>';
+    	print '<tr><td class="fieldrequired" >'.$langs->trans("NoteReason").'</td>';
+    	print '<td><input type="text" size="60" name="desc" value="'.GETPOST('desc').'"></td></tr>';
+    
+    	print "</table>";
+	}
 	print '</div>';
 
 	dol_fiche_end();
 
-	print '<div class="center">';
-	print '<input type="submit" class="button" name="submit" value="'.$langs->trans("AddGlobalDiscount").'">';
-    if (! empty($backtopage))
-    {
-        print '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;';
-	    print '<input type="submit" class="button" name="cancel" value="'.$langs->trans("Cancel").'">';
+	if ($user->rights->societe->creer)
+	{
+        print '<div class="center">';
+    	print '<input type="submit" class="button" name="submit" value="'.$langs->trans("AddGlobalDiscount").'">';
+        if (! empty($backtopage))
+        {
+            print '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;';
+    	    print '<input type="submit" class="button" name="cancel" value="'.$langs->trans("Cancel").'">';
+        }
+    	print '</div>';
     }
-	print '</div>';
 
-	print '</form>';
+    print '</form>';
 
 
 	print '<br>';
@@ -423,7 +432,7 @@ if ($socid > 0)
 	print '<br>';
 
 	/*
-	 * Liste ristournes appliquees (=liees a une ligne de facture ou facture)
+	 * List discount consumed (=liees a une ligne de facture ou facture)
 	 */
 
 	// Remises liees a lignes de factures

+ 4 - 2
htdocs/compta/bank/card.php

@@ -89,7 +89,8 @@ if ($_POST["action"] == 'add')
     $account->proprio 	      = trim($_POST["proprio"]);
     $account->owner_address   = trim($_POST["owner_address"]);
 
-    $account->account_number  = GETPOST('account_number');
+	$account_number 		 = GETPOST('account_number','alpha');
+	if ($account_number <= 0) { $account->account_number = ''; } else { $account->account_number = $account_number; }
 	$account->accountancy_journal  = trim($_POST["accountancy_journal"]);
 
     $account->solde           = $_POST["solde"];
@@ -171,7 +172,8 @@ if ($_POST["action"] == 'update' && ! $_POST["cancel"])
     $account->proprio 	      = trim($_POST["proprio"]);
     $account->owner_address   = trim($_POST["owner_address"]);
 
-    $account->account_number  = GETPOST('account_number');
+	$account_number 		 = GETPOST('account_number', 'int');
+	if ($account_number <= 0) { $account->account_number = ''; } else { $account->account_number = $account_number; }
 	$account->accountancy_journal = trim($_POST["accountancy_journal"]);
 
     $account->currency_code   = trim($_POST["account_currency_code"]);

+ 22 - 19
htdocs/compta/facture.php

@@ -438,7 +438,7 @@ if (empty($reshook))
     			}
     		}
 		}
-		
+
 		$qualified_for_stock_change = 0;
 		if (empty($conf->global->STOCK_SUPPORTS_SERVICES)) {
 			$qualified_for_stock_change = $object->hasProductsOrServices(2);
@@ -1022,7 +1022,7 @@ if (empty($reshook))
 
 						dol_syslog("Try to find source object origin=" . $object->origin . " originid=" . $object->origin_id . " to add lines or deposit lines");
 						$result = $srcobject->fetch($object->origin_id);
-						
+
 					    // If deposit invoice
 						if ($_POST['type'] == Facture::TYPE_DEPOSIT)
 						{
@@ -1183,7 +1183,7 @@ if (empty($reshook))
 								$error ++;
 							}
 						}
-						
+
 						// Now we create same links to contact than the ones found on origin object
 						if (! empty($conf->global->MAIN_PROPAGATE_CONTACTS_FROM_ORIGIN))
 						{
@@ -1196,13 +1196,13 @@ if (empty($reshook))
     						}
     						$sqlcontact = "SELECT code, fk_socpeople FROM ".MAIN_DB_PREFIX."element_contact as ec, ".MAIN_DB_PREFIX."c_type_contact as ctc";
     						$sqlcontact.= " WHERE element_id = ".$originidforcontact." AND ec.fk_c_type_contact = ctc.rowid AND ctc.element = '".$originforcontact."'";
-    
+
     						$resqlcontact = $db->query($sqlcontact);
     						if ($resqlcontact)
     						{
                                 while($objcontact = $db->fetch_object($resqlcontact))
                                 {
-                                    //print $objcontact->code.'-'.$objcontact->fk_socpeople."\n";                                
+                                    //print $objcontact->code.'-'.$objcontact->fk_socpeople."\n";
                                     $object->add_contact($objcontact->fk_socpeople, $objcontact->code);
                                 }
     						}
@@ -1214,14 +1214,17 @@ if (empty($reshook))
 						$reshook = $hookmanager->executeHooks('createFrom', $parameters, $object, $action); // Note that $action and $object may have been
 						// modified by hook
 						if ($reshook < 0)
+						{
+						    setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
 						    $error++;
+						}
 						
 					} else {
 						setEventMessages($object->error, $object->errors, 'errors');
 						$error++;
 					}
-				} 			
-				else 
+				}
+				else
 				{   // If some invoice's lines coming from page
 					$id = $object->create($user);
 
@@ -1393,7 +1396,7 @@ if (empty($reshook))
 			// Ecrase $txtva par celui du produit
 			// Ecrase $base_price_type par celui du produit
 			// Replaces $fk_unit with the product's
-			if (! empty($idprod)) 
+			if (! empty($idprod))
 			{
 				$prod = new Product($db);
 				$prod->fetch($idprod);
@@ -1404,7 +1407,7 @@ if (empty($reshook))
 					$tva_tx = get_default_tva($mysoc, $object->thirdparty, $prod->id);
 					$tva_npr = get_default_npr($mysoc, $object->thirdparty, $prod->id);
 					if (empty($tva_tx)) $tva_npr=0;
-					
+
 					$pu_ht = $prod->price;
 					$pu_ttc = $prod->price_ttc;
 					$price_min = $prod->price_min;
@@ -1451,13 +1454,13 @@ if (empty($reshook))
 					}
 					// On reevalue prix selon taux tva car taux tva transaction peut etre different
 					// de ceux du produit par defaut (par exemple si pays different entre vendeur et acheteur).
-					elseif ($tva_tx != $prod->tva_tx) 
+					elseif ($tva_tx != $prod->tva_tx)
 					{
-						if ($price_base_type != 'HT') 
+						if ($price_base_type != 'HT')
 						{
 							$pu_ht = price2num($pu_ttc / (1 + ($tva_tx / 100)), 'MU');
 						}
-						else 
+						else
 						{
 							$pu_ttc = price2num($pu_ht * (1 + ($tva_tx / 100)), 'MU');
 						}
@@ -1519,7 +1522,7 @@ if (empty($reshook))
 			// Local Taxes
 			$localtax1_tx = get_localtax($tva_tx, 1, $object->thirdparty, $mysoc, $tva_npr);
 			$localtax2_tx = get_localtax($tva_tx, 2, $object->thirdparty, $mysoc, $tva_npr);
-			
+
 			$info_bits = 0;
 			if ($tva_npr)
 				$info_bits |= 0x01;
@@ -1623,7 +1626,7 @@ if (empty($reshook))
 		// 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);
@@ -2082,7 +2085,7 @@ if ($action == 'create')
 	    $invoice_predefined->fetch(GETPOST('fac_rec','int'));
 	    
 	    $dateinvoice = $invoice_predefined->date_when;     // To use next gen date by default later
-	    
+
 		$sql = 'SELECT r.rowid, r.titre, r.total_ttc';
 		$sql .= ' FROM ' . MAIN_DB_PREFIX . 'facture_rec as r';
 		$sql .= ' WHERE r.fk_soc = ' . $invoice_predefined->socid;
@@ -3087,7 +3090,7 @@ else if ($id > 0 || ! empty($ref))
 			// Remise dispo de type avoir
 			if (! $absolute_discount)
 				print '<br>';
-			// $form->form_remise_dispo($_SERVER["PHP_SELF"].'?facid='.$object->id, 0, 'remise_id_for_payment', $soc->id, $absolute_creditnote, $filtercreditnote, $resteapayer		
+			// $form->form_remise_dispo($_SERVER["PHP_SELF"].'?facid='.$object->id, 0, 'remise_id_for_payment', $soc->id, $absolute_creditnote, $filtercreditnote, $resteapayer
 			$more=' ('.$addcreditnote.')';
 			$form->form_remise_dispo($_SERVER["PHP_SELF"] . '?facid=' . $object->id, 0, 'remise_id_for_payment', $soc->id, $absolute_creditnote, $filtercreditnote, 0, $more); // We allow credit note even if amount is higher
 		}
@@ -4038,7 +4041,7 @@ else if ($id > 0 || ! empty($ref))
 					print '<div class="inline-block divButAction"><a class="butAction" href="facture/fiche-rec.php?facid=' . $object->id . '&amp;action=create">' . $langs->trans("ChangeIntoRepeatableInvoice") . '</a></div>';
 				}
 			}
-			
+
 			// Create a credit note
 			if (($object->type == Facture::TYPE_STANDARD || $object->type == Facture::TYPE_DEPOSIT || $object->type == Facture::TYPE_PROFORMA) && $object->statut > 0 && $user->rights->facture->creer)
 			{
@@ -4193,7 +4196,7 @@ else if ($id > 0 || ! empty($ref))
 		{
 			include DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
 			$formmail->frommail=dolAddEmailTrackId($formmail->frommail, 'inv'.$object->id);
-		}		
+		}
 		$formmail->withfrom = 1;
 		$liste = array();
 		foreach ($object->thirdparty->thirdparty_and_contact_email_array(1) as $key => $value) {
@@ -4213,7 +4216,7 @@ else if ($id > 0 || ! empty($ref))
 		$formmail->withdeliveryreceipt = 1;
 		$formmail->withcancel = 1;
 		// Tableau des substitutions
-		$formmail->setSubstitFromObject($object);
+		$formmail->setSubstitFromObject($object, $outputlangs);
 		$formmail->substit['__INVREF__'] = $object->ref;
 
 		// Find the good contact adress

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

@@ -3582,7 +3582,7 @@ class Facture extends CommonInvoice
 					$response->nbtodolate++;
 				}
 			}
-	
+
 			return $response;
 		}
 		else
@@ -4016,7 +4016,7 @@ class Facture extends CommonInvoice
 		global $conf;
 
 		$now = dol_now();
-		
+
 		// Paid invoices have status STATUS_CLOSED
 		if ($this->statut != Facture::STATUS_VALIDATED) return false;
 
@@ -4125,6 +4125,10 @@ class FactureLigne extends CommonInvoiceLine
 		$sql.= ' fd.fk_unit,';
 		$sql.= ' fd.situation_percent, fd.fk_prev_id,';
 		$sql.= ' p.ref as product_ref, p.label as product_libelle, p.description as product_desc';
+		$sql.= ' , fd.multicurrency_subprice';
+		$sql.= ' , fd.multicurrency_total_ht';
+		$sql.= ' , fd.multicurrency_total_tva';
+		$sql.= ' , fd.multicurrency_total_ttc';
 		$sql.= ' FROM '.MAIN_DB_PREFIX.'facturedet as fd';
 		$sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON fd.fk_product = p.rowid';
 		$sql.= ' WHERE fd.rowid = '.$rowid;
@@ -4175,6 +4179,11 @@ class FactureLigne extends CommonInvoiceLine
 			$this->situation_percent    = $objp->situation_percent;
 			$this->fk_prev_id           = $objp->fk_prev_id;
 
+			$this->multicurrency_subprice = $objp->multicurrency_subprice;
+			$this->multicurrency_total_ht = $objp->multicurrency_total_ht;
+			$this->multicurrency_total_tva= $objp->multicurrency_total_tva;
+			$this->multicurrency_total_ttc= $objp->multicurrency_total_ttc;
+
 			$this->db->free($result);
 
 			return 1;
@@ -4428,6 +4437,11 @@ class FactureLigne extends CommonInvoiceLine
 		if (! isset($this->situation_percent) || $this->situation_percent > 100 || (string) $this->situation_percent == '') $this->situation_percent = 100;
 		if (empty($this->pa_ht)) $this->pa_ht=0;
 
+		if (empty($this->multicurrency_subprice)) $this->multicurrency_subprice=0;
+		if (empty($this->multicurrency_total_ht)) $this->multicurrency_total_ht=0;
+		if (empty($this->multicurrency_total_tva)) $this->multicurrency_total_tva=0;
+		if (empty($this->multicurrency_total_ttc)) $this->multicurrency_total_ttc=0;
+
 		// Check parameters
 		if ($this->product_type < 0) return -1;
 

+ 16 - 4
htdocs/core/class/html.formmail.class.php

@@ -928,18 +928,30 @@ class FormMail extends Form
 	/**
 	 * Set substit array from object
 	 * 
-	 * @param	Object	$object		Object to use
+	 * @param	Object	   $object		  Object to use
+	 * @param   Translate  $outputlangs   Object lang 
 	 * @return	void
 	 */
-	function setSubstitFromObject($object)
+	function setSubstitFromObject($object, $outputlangs=null)
 	{
 		global $user;
 		$this->substit['__REF__'] = $object->ref;
-		$this->substit['__SIGNATURE__'] = $user->signature;
 		$this->substit['__REFCLIENT__'] = $object->ref_client;
-		$this->substit['__THIRDPARTY_NAME__'] = $object->thirdparty->name;
+		$this->substit['__REFSUPPLIER__'] = $object->ref_supplier;
+
+		$this->substit['__DATE_YMD__'] = dol_print_date($object->date, 'day', 0, $outputlangs);
+		$this->substit['__DATE_DUE_YMD__'] = dol_print_date($object->date_lim_reglement, 'day', 0, $outputlangs);
+		$this->substit['__AMOUNT__'] = price($object->total_ttc);
+		$this->substit['__AMOUNT_WO_TAX__'] = price($object->total_ht);
+		
+		$this->substit['__THIRDPARTY_ID__'] = (is_object($object->thirdparty)?$object->thirdparty->id:'');
+		$this->substit['__THIRDPARTY_NAME__'] = (is_object($object->thirdparty)?$object->thirdparty->name:'');
+		
+		$this->substit['__PROJECT_ID__'] = (is_object($object->projet)?$object->projet->id:'');
 		$this->substit['__PROJECT_REF__'] = (is_object($object->projet)?$object->projet->ref:'');
 		$this->substit['__PROJECT_NAME__'] = (is_object($object->projet)?$object->projet->title:'');
+		
+		$this->substit['__SIGNATURE__'] = $user->signature;
 		$this->substit['__PERSONALIZED__'] = '';
 		$this->substit['__CONTACTCIVNAME__'] = '';	// Will be replace just before sending
 	}

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

@@ -82,7 +82,7 @@ class modAgenda extends DolibarrModules
 		{
 		    while ($obj = $this->db->fetch_object($sqlreadactions))
 		    {
-		        if (preg_match('/_CREATE$/',$obj->code)) continue;    // We don't track such events (*_CREATE) by default. 
+		        if (preg_match('/_CREATE$/',$obj->code) && ($obj->code != 'COMPANY_CREATE')) continue;    // We don't track such events (*_CREATE) by default, we prefer validation (except thirdparty creation because there is no validation). 
 		        if (preg_match('/^PROJECT_/',$obj->code)) continue;   // We don't track such events by default.
 		        if (preg_match('/^TASK_/',$obj->code)) continue;      // We don't track such events by default.
 		        $this->const[] = array('MAIN_AGENDA_ACTIONAUTO_'.$obj->code, "chaine", "1");

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

@@ -43,13 +43,13 @@ class InterfaceActionsAuto extends DolibarrTriggers
 	 * Function called when a Dolibarrr business event is done.
 	 * All functions "runTrigger" are triggered if file is inside directory htdocs/core/triggers or htdocs/module/code/triggers (and declared)
 	 *
-	 * Following properties must be filled:
+	 * Following properties may be set before calling trigger. The may be completed by this trigger to be used for writing the event into database:
 	 *      $object->actiontypecode (translation action code: AC_OTH, ...)
 	 *      $object->actionmsg (note, long text)
 	 *      $object->actionmsg2 (label, short text)
 	 *      $object->sendtoid (id of contact)
 	 *      $object->socid
-	 *      Optionnal:
+	 *      $object->fk_project
 	 *      $object->fk_element
 	 *      $object->elementtype
 	 *
@@ -779,6 +779,7 @@ class InterfaceActionsAuto extends DolibarrTriggers
 		$actioncomm->code        = 'AC_'.$action;
 		$actioncomm->label       = $object->actionmsg2;
 		$actioncomm->note        = $object->actionmsg;          // TODO Replace with $actioncomm->email_msgid ? $object->email_content : $object->actionmsg
+		$actioncomm->fk_project  = isset($object->fk_project)?$object->fk_project:0;
 		$actioncomm->datep       = $now;
 		$actioncomm->datef       = $now;
 		$actioncomm->durationp   = 0;
@@ -790,7 +791,7 @@ class InterfaceActionsAuto extends DolibarrTriggers
 		$actioncomm->contactid   = $contactforaction->id;
 		$actioncomm->authorid    = $user->id;   // User saving action
 		$actioncomm->userownerid = $user->id;	// Owner of action
-        // Fields when action is en email (coentent should be into note)
+        // Fields when action is en email (content should be added into note)
 		$actioncomm->email_msgid = $object->email_msgid;
 		$actioncomm->email_from  = $object->email_from;
 		$actioncomm->email_sender= $object->email_sender;

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

@@ -4,6 +4,7 @@
  * Copyright (C) 2009      Regis Houssin        <regis.houssin@capnetworks.com>
  * Copyright (C) 2014      Florian Henry        <florian.henry@open-concept.pro>
  * Copyright (C) 2015      Alexandre Spangaro   <aspangaro.dolibarr@gmail.com>
+ * Copyright (C) 2016      Juanjo Menent        <jmenent@2byte.es>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -633,7 +634,7 @@ class Don extends CommonObject
                 $this->town           = $obj->town;
                 $this->zip            = $obj->zip;
                 $this->town           = $obj->town;
-                $this->country_id     = $obj->country_id;
+                $this->country_id     = $obj->fk_country;
                 $this->country_code   = $obj->country_code;
                 $this->country        = $obj->country;
                 $this->country_olddata= $obj->country_olddata;	// deprecated

+ 5 - 0
htdocs/expensereport/card.php

@@ -1984,6 +1984,11 @@ if ($action != 'create' && $action != 'edit')
 		}
 	}
 
+	if ($user->rights->expensereport->approve && $object->fk_statut == 5)
+	{
+	    print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?action=refuse&id='.$object->id.'">'.$langs->trans('Deny').'</a>';
+	}
+	
 	/* Si l'état est "A payer"
 	 *	ET user à droit de "to_paid"
 	 *	Afficher : "Annuler" / "Payer" / "Supprimer"

+ 1 - 0
htdocs/expensereport/class/expensereport.class.php

@@ -1810,6 +1810,7 @@ class ExpenseReportLine
         // Clean parameters
         $this->comments=trim($this->comments);
         $this->vatrate = price2num($this->vatrate);
+        $this->value_unit = price2num($this->value_unit);
 
         $this->db->begin();
 

+ 1 - 1
htdocs/install/mysql/data/llx_00_c_country.sql

@@ -105,7 +105,7 @@ INSERT INTO llx_c_country (rowid,code,code_iso,label,active,favorite) VALUES (74
 INSERT INTO llx_c_country (rowid,code,code_iso,label,active,favorite) VALUES (75,'CR','CRI','Costa Rica',1,0);
 INSERT INTO llx_c_country (rowid,code,code_iso,label,active,favorite) VALUES (76,'HR','HRV','Croatie',1,0);
 INSERT INTO llx_c_country (rowid,code,code_iso,label,active,favorite) VALUES (77,'CU','CUB','Cuba',1,0);
-INSERT INTO llx_c_country (rowid,code,code_iso,label,active,favorite) VALUES (78,'CY','CYP','Chypre',1,0);
+INSERT INTO llx_c_country (rowid,code,code_iso,label,active,favorite) VALUES (78,'CY','CYP','Cyprus',1,0);
 INSERT INTO llx_c_country (rowid,code,code_iso,label,active,favorite) VALUES (79,'CZ','CZE','République Tchèque',1,0);
 INSERT INTO llx_c_country (rowid,code,code_iso,label,active,favorite) VALUES (80,'DK','DNK','Danemark',1,0);
 INSERT INTO llx_c_country (rowid,code,code_iso,label,active,favorite) VALUES (81,'DJ','DJI','Djibouti',1,0);

+ 4 - 4
htdocs/install/mysql/data/llx_c_action_trigger.sql

@@ -50,11 +50,11 @@ insert into llx_c_action_trigger (code,label,description,elementtype,rang) value
 insert into llx_c_action_trigger (code,label,description,elementtype,rang) values ('BILL_CANCEL','Customer invoice canceled','Executed when a customer invoice is conceled','facture',8);
 insert into llx_c_action_trigger (code,label,description,elementtype,rang) values ('BILL_SENTBYMAIL','Customer invoice sent by mail','Executed when a customer invoice is sent by mail','facture',9);
 insert into llx_c_action_trigger (code,label,description,elementtype,rang) values ('BILL_UNVALIDATE','Customer invoice unvalidated','Executed when a customer invoice status set back to draft','facture',10);
-insert into llx_c_action_trigger (code,label,description,elementtype,rang) values ('ORDER_SUPPLIER_CREATE','Supplier order validated','Executed when a supplier order is validated','order_supplier',11);
+insert into llx_c_action_trigger (code,label,description,elementtype,rang) values ('ORDER_SUPPLIER_CREATE','Supplier order created','Executed when a supplier order is created','order_supplier',11);
 insert into llx_c_action_trigger (code,label,description,elementtype,rang) values ('ORDER_SUPPLIER_VALIDATE','Supplier order validated','Executed when a supplier order is validated','order_supplier',12);
-insert into llx_c_action_trigger (code,label,description,elementtype,rang) values ('ORDER_SUPPLIER_APPROVE','Supplier order request approved','Executed when a supplier order is approved','order_supplier',12);
-insert into llx_c_action_trigger (code,label,description,elementtype,rang) values ('ORDER_SUPPLIER_SUBMIT','Supplier order request submited','Executed when a supplier order is approved','order_supplier',12);
-insert into llx_c_action_trigger (code,label,description,elementtype,rang) values ('ORDER_SUPPLIER_RECEIVE','Supplier order request received','Executed when a supplier order is received','order_supplier',12);
+insert into llx_c_action_trigger (code,label,description,elementtype,rang) values ('ORDER_SUPPLIER_APPROVE','Supplier order request approved','Executed when a supplier order is approved','order_supplier',13);
+insert into llx_c_action_trigger (code,label,description,elementtype,rang) values ('ORDER_SUPPLIER_SUBMIT','Supplier order request submited','Executed when a supplier order is approved','order_supplier',13);
+insert into llx_c_action_trigger (code,label,description,elementtype,rang) values ('ORDER_SUPPLIER_RECEIVE','Supplier order request received','Executed when a supplier order is received','order_supplier',13);
 insert into llx_c_action_trigger (code,label,description,elementtype,rang) values ('ORDER_SUPPLIER_REFUSE','Supplier order request refused','Executed when a supplier order is refused','order_supplier',13);
 insert into llx_c_action_trigger (code,label,description,elementtype,rang) values ('ORDER_SUPPLIER_SENTBYMAIL','Supplier order sent by mail','Executed when a supplier order is sent by mail','order_supplier',14);
 insert into llx_c_action_trigger (code,label,description,elementtype,rang) values ('ORDER_SUPPLIER_CLASSIFY_BILLED','Supplier order set billed','Executed when a supplier order is set as billed','order_supplier',14);

+ 10 - 6
htdocs/install/mysql/data/llx_c_tva.sql

@@ -81,14 +81,18 @@ insert into llx_c_tva(rowid,fk_pays,taux,recuperableonly,note,active) values (67
 insert into llx_c_tva(rowid,fk_pays,taux,recuperableonly,note,active) values (672, 67,   '0','0','VAT Rate 0',1);
 
 -- CHINA (id country=9)
-insert into llx_c_tva(rowid,fk_pays,taux,recuperableonly,note,active) values ( 91, 9,   '17','0','VAT standard rate',1);
-insert into llx_c_tva(rowid,fk_pays,taux,recuperableonly,note,active) values ( 92, 9,   '13','0','VAT reduced rate 0',1);
-insert into llx_c_tva(rowid,fk_pays,taux,recuperableonly,note,active) values ( 93, 9,    '3','0','VAT super reduced rate 0',1);
-insert into llx_c_tva(rowid,fk_pays,taux,recuperableonly,note,active) values ( 94, 9,    '0','0','VAT Rate 0',1);
+insert into llx_c_tva(rowid,fk_pays,taux,recuperableonly,note,active) values ( 91,  9,   '17','0','VAT standard rate',1);
+insert into llx_c_tva(rowid,fk_pays,taux,recuperableonly,note,active) values ( 92,  9,   '13','0','VAT reduced rate 0',1);
+insert into llx_c_tva(rowid,fk_pays,taux,recuperableonly,note,active) values ( 93,  9,    '3','0','VAT super reduced rate 0',1);
+insert into llx_c_tva(rowid,fk_pays,taux,recuperableonly,note,active) values ( 94,  9,    '0','0','VAT Rate 0',1);
+
+-- CYPRUS (id country=78)
+insert into llx_c_tva(rowid,fk_pays,taux,recuperableonly,note,active) values (781, 78,   '19','0','VAT standard rate',1);
+insert into llx_c_tva(rowid,fk_pays,taux,recuperableonly,note,active) values (784, 78,    '0','0','VAT Rate 0',1);
 
 -- DANMERK (id country=80)
-insert into llx_c_tva(rowid,fk_pays,taux,recuperableonly,note,active) values (801,80,   '25','0','VAT standard rate',1);
-insert into llx_c_tva(rowid,fk_pays,taux,recuperableonly,note,active) values (802,80,    '0','0','VAT Rate 0',1);
+insert into llx_c_tva(rowid,fk_pays,taux,recuperableonly,note,active) values (801, 80,   '25','0','VAT standard rate',1);
+insert into llx_c_tva(rowid,fk_pays,taux,recuperableonly,note,active) values (802, 80,    '0','0','VAT Rate 0',1);
 
 -- FRANCE (id country=1)
 insert into llx_c_tva(rowid,fk_pays,taux,recuperableonly,note,active) values ( 11,  1,  '20','0','VAT standard rate (France hors DOM-TOM)',1);

+ 3 - 3
htdocs/install/mysql/tables/llx_product.sql

@@ -57,7 +57,7 @@ create table llx_product
   tosell					tinyint      DEFAULT 1,	          -- Product you sell
   tobuy						tinyint      DEFAULT 1,            -- Product you buy
   onportal     				tinyint      DEFAULT 0,	          -- If it is a product you sell and you want to sell it on portal (module website must be on)
-  tobatch					tinyint      DEFAULT 0 NOT NULL,  -- Is it a product that need a batch or eat-by management
+  tobatch					tinyint      DEFAULT 0 NOT NULL,  -- Is it a product that need a batch management (eat-by or lot management)
   fk_product_type			integer      DEFAULT 0,			-- Type of product: 0 for regular product, 1 for service, 9 for other (used by external module)
   duration					varchar(6),
   seuil_stock_alerte		integer      DEFAULT 0,
@@ -81,8 +81,8 @@ create table llx_product
   volume_units				tinyint      DEFAULT NULL,
   stock						real,							-- Current physical stock (dernormalized field)
   pmp						double(24,8) DEFAULT 0 NOT NULL,		-- To store valuation of stock calculated using average price method, for this product
-  fifo						double(24,8),							-- To store valuation of stock calculated using fifo method, for this product
-  lifo						double(24,8),							-- To store valuation of stock calculated using lifo method, for this product
+  fifo						double(24,8),							-- To store valuation of stock calculated using fifo method, for this product. TODO Not used, should be replaced by stock value stored into movement table.
+  lifo						double(24,8),							-- To store valuation of stock calculated using lifo method, for this product. TODO Not used, should be replaced by stock value stored into movement table.
   canvas					varchar(32)  DEFAULT NULL,
   finished					tinyint      DEFAULT NULL,		-- 1=manufactured product, 0=matiere premiere
   hidden					tinyint      DEFAULT 0,			-- Not used. Deprecated.

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

@@ -1529,7 +1529,7 @@ ListOfNotificationsPerUser=List of notifications per user*
 ListOfNotificationsPerUserOrContact=List of notifications per user* or per contact**
 ListOfFixedNotifications=List of fixed notifications
 GoOntoUserCardToAddMore=Go on the tab "Notifications" of a user to add or remove notifications for users
-GoOntoContactCardToAddMore=Go on the tab "Notifications" of a thirdparty contact to add or remove notifications for contacts/addresses
+GoOntoContactCardToAddMore=Go on the tab "Notifications" of a thirdparty to add or remove notifications for contacts/addresses
 Threshold=Threshold
 BackupDumpWizard=Wizard to build database backup dump file
 SomethingMakeInstallFromWebNotPossible=Installation of external module is not possible from the web interface for the following reason:

+ 5 - 0
htdocs/langs/en_US/boxes.lang

@@ -72,6 +72,11 @@ BoxProposalsPerMonth=Proposals per month
 NoTooLowStockProducts=No product under the low stock limit
 BoxProductDistribution=Products/Services distribution
 BoxProductDistributionFor=Distribution of %s for %s
+BoxTitleLastModifiedSupplierBills=Latest %s modified supplier bills
+BoxTitleLatestModifiedSupplierOrders=Latest %s modified supplier orders
+BoxTitleLastModifiedCustomerBills=Latest %s modified customer bills
+BoxTitleLastModifiedCustomerOrders=Latest %s modified customer orders
+BoxTitleLastModifiedPropals=Latest %s modified propals
 ForCustomersInvoices=Customers invoices
 ForCustomersOrders=Customers orders
 ForProposals=Proposals

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

@@ -393,3 +393,5 @@ ThirdpartiesMergeSuccess=Thirdparties have been merged
 SaleRepresentativeLogin=Login of sales representative
 SaleRepresentativeFirstname=Firstname of sales representative
 SaleRepresentativeLastname=Lastname of sales representative
+ErrorThirdpartiesMerge=There was an error when deleting the thirdparties. Please check the log. Changes have been reverted.
+NewCustomerSupplierCodeProposed=New customer or supplier proposed on duplicate code

+ 2 - 3
htdocs/product/index.php

@@ -377,14 +377,13 @@ function activitytrim($product_type)
 
 	// breakdown by quarter
 	$sql = "SELECT DATE_FORMAT(p.datep,'%Y') as annee, DATE_FORMAT(p.datep,'%m') as mois, SUM(fd.total_ht) as Mnttot";
-	$sql.= " FROM ".MAIN_DB_PREFIX."societe as s,".MAIN_DB_PREFIX."facture as f, ".MAIN_DB_PREFIX."facturedet as fd";
+	$sql.= " FROM ".MAIN_DB_PREFIX."facture as f, ".MAIN_DB_PREFIX."facturedet as fd";
 	$sql.= " , ".MAIN_DB_PREFIX."paiement as p,".MAIN_DB_PREFIX."paiement_facture as pf";
-	$sql.= " WHERE f.fk_soc = s.rowid";
+	$sql.= " WHERE f.entity = " . $conf->entity;
 	$sql.= " AND f.rowid = fd.fk_facture";
 	$sql.= " AND pf.fk_facture = f.rowid";
 	$sql.= " AND pf.fk_paiement= p.rowid";
 	$sql.= " AND fd.product_type=".$product_type;
-	$sql.= " AND s.entity IN (".getEntity('societe', 1).")";
 	$sql.= " AND p.datep >= '".$db->idate(dol_get_first_day($yearofbegindate),1)."'";
 	$sql.= " GROUP BY annee, mois ";
 	$sql.= " ORDER BY annee, mois ";

+ 13 - 2
htdocs/product/stock/class/mouvementstock.class.php

@@ -149,8 +149,12 @@ class MouvementStock extends CommonObject
                         {
                             if ($eatby)
                             {
-                        		if ($this->db->jdate($obj->eatby) != $eatby)  // If found and eatby/sellby defined into table and provided and differs, return error
+                                $eatbywithouthour=$eatby;
+                                $tmparray=dol_getdate($eatby, true);
+                                $eatbywithouthour=dol_mktime(0, 0, 0, $tmparray['mon'], $tmparray['mday'], $tmparray['year']);
+                        		if ($this->db->jdate($obj->eatby) != $eatby && $this->db->jdate($obj->eatby) != $eatbywithouthour)    // We test date without hours and with hours for backward compatibility 
                                 {
+                                    // If found and eatby/sellby defined into table and provided and differs, return error
                                     $this->errors[]=$langs->trans("ThisSerialAlreadyExistWithDifferentDate", $batch, dol_print_date($this->db->jdate($obj->eatby)), dol_print_date($eatby));
                                     dol_syslog($langs->transnoentities("ThisSerialAlreadyExistWithDifferentDate", $batch, dol_print_date($this->db->jdate($obj->eatby)), dol_print_date($eatby)), LOG_ERR);
                                     $this->db->rollback();
@@ -183,8 +187,12 @@ class MouvementStock extends CommonObject
                         {
                             if ($sellby)
                             {
-                                if ($this->db->jdate($obj->sellby) != $sellby) // If found and eatby/sellby defined into table and provided and differs, return error
+                                $sellbywithouthour=$sellby;
+                                $tmparray=dol_getdate($eatby, true);
+                                $eatbywithouthour=dol_mktime(0, 0, 0, $tmparray['mon'], $tmparray['mday'], $tmparray['year']);
+                                if ($this->db->jdate($obj->sellby) != $sellby && $this->db->jdate($obj->sellby) != $sellbywithouthour)    // We test date without hours and with hours for backward compatibility
                         		{
+                        		    // If found and eatby/sellby defined into table and provided and differs, return error
             						$this->errors[]=$langs->trans("ThisSerialAlreadyExistWithDifferentDate", $batch, dol_print_date($this->db->jdate($obj->sellby)), dol_print_date($sellby));
             						dol_syslog($langs->transnoentities("ThisSerialAlreadyExistWithDifferentDate", $batch, dol_print_date($this->db->jdate($obj->sellby)), dol_print_date($sellby)), LOG_ERR);
             						$this->db->rollback();
@@ -222,6 +230,9 @@ class MouvementStock extends CommonObject
             	    $productlot = new Productlot($this->db);
             	    $productlot->fk_product = $fk_product;
             	    $productlot->batch = $batch;
+            	    // If we are here = first time we manage this batch, so we used dates provided by users to create lot
+            	    $productlot->eatby = $eatby;
+            	    $productlot->sellby = $sellby;
             	    $result = $productlot->create($user);
             	    if ($result <= 0)
             	    {

+ 6 - 2
htdocs/product/stock/mouvement.php

@@ -128,8 +128,12 @@ if ($action == "correct_stock")
         if ($product->hasbatch())
         {
         	$batch=GETPOST('batch_number');
-        	$eatby=GETPOST('eatby');
-        	$sellby=GETPOST('sellby');
+
+        	//$eatby=GETPOST('eatby');
+        	//$sellby=GETPOST('sellby');
+        	$eatby=dol_mktime(12, 0, 0, GETPOST('eatbymonth'), GETPOST('eatbyday'), GETPOST('eatbyyear'));
+        	$sellby=dol_mktime(12, 0, 0, GETPOST('sellbymonth'), GETPOST('sellbyday'), GETPOST('sellbyyear'));
+        	 
 	        $result=$product->correct_stock_batch(
 	            $user,
 	            $id,

+ 2 - 2
htdocs/product/stock/tpl/stockcorrection.tpl.php

@@ -56,14 +56,14 @@
 		{
 			print '<td width="20%" class="fieldrequired" colspan="2">'.$langs->trans("Warehouse").'</td>';
 			print '<td width="20%">';
-			print $formproduct->selectWarehouses((GETPOST("dwid")?GETPOST("dwid",'int'):(GETPOST('id_entrepot')?GETPOST('id_entrepot','int'):'ifone')), 'id_entrepot', '', 1);
+			print $formproduct->selectWarehouses((GETPOST("dwid")?GETPOST("dwid",'int'):(GETPOST('id_entrepot')?GETPOST('id_entrepot','int'):'ifone')), 'id_entrepot', '', 1, 0, 0, '', 0, 0, null, 'minwidth100');
 			print '</td>';
 		}
 		if ($object->element == 'stock')
 		{
 			print '<td width="20%" class="fieldrequired" colspan="2">'.$langs->trans("Product").'</td>';
 	        print '<td width="20%">';
-	        print $form->select_produits(GETPOST('product_id'), 'product_id', (empty($conf->global->STOCK_SUPPORTS_SERVICES)?'0':''));
+	        print $form->select_produits(GETPOST('product_id'), 'product_id', (empty($conf->global->STOCK_SUPPORTS_SERVICES)?'0':''), 20, 0, -1);
 	        print '</td>';
 		}
 		print '<td width="20%">';

+ 2 - 3
htdocs/projet/card.php

@@ -857,10 +857,9 @@ else
                 var defaultpercent = element.attr("defaultpercent");
                 var elemcode = element.attr("elemcode");
                 /* Change percent of default percent of new status is higher */
-                if (parseFloat(jQuery("#opp_percent").val()) != parseFloat(defaultpercent)
-                    )
+                if (parseFloat(jQuery("#opp_percent").val()) != parseFloat(defaultpercent))
                 {
-                    if (! jQuery("#oldopppercent").text()) jQuery("#oldopppercent").text(\' - '.dol_escape_js($langs->trans("PreviousValue")).': \'+jQuery("#opp_percent").val()+\' %\');
+                    if (jQuery("#opp_percent").val() != \'\' && ! jQuery("#oldopppercent").text()) jQuery("#oldopppercent").text(\' - '.dol_escape_js($langs->trans("PreviousValue")).': \'+jQuery("#opp_percent").val()+\' %\');
                     jQuery("#opp_percent").val(defaultpercent);
                     
                 }

+ 2 - 2
htdocs/projet/element.php

@@ -2,7 +2,7 @@
 /* Copyright (C) 2001-2004 Rodolphe Quiedeville <rodolphe@quiedeville.org>
  * Copyright (C) 2004-2015 Laurent Destailleur  <eldy@users.sourceforge.net>
  * Copyright (C) 2005-2010 Regis Houssin        <regis.houssin@capnetworks.com>
- * Copyright (C) 2012	   Juanjo Menent        <jmenent@2byte.es>
+ * Copyright (C) 2012-2016 Juanjo Menent        <jmenent@2byte.es>
  * Copyright (C) 2015      Alexandre Spangaro	<aspangaro.dolibarr@gmail.com>
  * Copyright (C) 2015      Marcos García        <marcosgdf@gmail.com>
  *
@@ -593,7 +593,7 @@ foreach ($listofreferent as $key => $value)
 		$addform='';
 
 		$idtofilterthirdparty=0;
-		if (! in_array($tablename, array('facture_fourn', 'commande_fourn'))) $idtofilterthirdparty=$object->thirdparty->id;
+		if (! in_array($tablename, array('facture_fourn', 'commande_fournisseur'))) $idtofilterthirdparty=$object->thirdparty->id;
 
        	if (empty($conf->global->PROJECT_LINK_ON_OVERWIEW_DISABLED) && $idtofilterthirdparty > 0) 
        	{

+ 2 - 2
htdocs/societe/notify/card.php

@@ -51,8 +51,8 @@ if ($page == -1) { $page = 0; }
 $offset = $conf->liste_limit * $page;
 $pageprev = $page - 1;
 $pagenext = $page + 1;
-if (! $sortorder) $sortorder="ASC";
-if (! $sortfield) $sortfield="c.lastname";
+if (! $sortorder) $sortorder="DESC";
+if (! $sortfield) $sortfield="a.daten";
 
 $now=dol_now();
 

+ 18 - 5
htdocs/societe/soc.php

@@ -446,7 +446,7 @@ if (empty($reshook))
                 if (empty($object->fournisseur)) $object->code_fournisseur='';
 
                 $result = $object->create($user);
-                if ($result >= 0)
+				if ($result >= 0)
                 {
                     if ($object->particulier)
                     {
@@ -509,6 +509,13 @@ if (empty($reshook))
                 }
                 else
 				{
+					
+					if($result == -3) {
+						$duplicate_code_error = true;
+						$object->code_fournisseur = null;
+						$object->code_client = null;
+					}
+					
                     $error=$object->error; $errors=$object->errors;
                 }
 
@@ -802,8 +809,14 @@ else
         $object->particulier		= $private;
         $object->prefix_comm		= GETPOST('prefix_comm');
         $object->client				= GETPOST('client')?GETPOST('client'):$object->client;
-        $object->code_client		= GETPOST('code_client', 'alpha');
-        $object->fournisseur		= GETPOST('fournisseur')?GETPOST('fournisseur'):$object->fournisseur;
+        
+        if(empty($duplicate_code_error)) {
+	        $object->code_client		= GETPOST('code_client', 'alpha');
+	        $object->fournisseur		= GETPOST('fournisseur')?GETPOST('fournisseur'):$object->fournisseur;
+        }
		else {
+			setEventMessages($langs->trans('NewCustomerSupplierCodeProposed'),'', 'warnings');
+		}
+		
         $object->code_fournisseur	= GETPOST('code_fournisseur', 'alpha');
         $object->address			= GETPOST('address', 'alpha');
         $object->zip				= GETPOST('zipcode', 'alpha');
@@ -1004,7 +1017,7 @@ else
 
         print '<td>'.fieldLabel('CustomerCode','customer_code').'</td><td width="25%">';
         print '<table class="nobordernopadding"><tr><td>';
-        $tmpcode=$object->code_client;
+		$tmpcode=$object->code_client;
         if (empty($tmpcode) && ! empty($modCodeClient->code_auto)) $tmpcode=$modCodeClient->getNextValue($object,0);
         print '<input type="text" name="code_client" id="customer_code" size="16" value="'.dol_escape_htmltag($tmpcode).'" maxlength="15">';
         print '</td><td>';
@@ -2171,7 +2184,7 @@ else
         print '<table class="border tableforfield" width="100%">';
         
         // Legal
-        print '<tr><td width="25%">'.$langs->trans('JuridicalStatus').'</td><td>'.$object->forme_juridique.'</td></tr>';
+        print '<tr><td class="titlefield">'.$langs->trans('JuridicalStatus').'</td><td>'.$object->forme_juridique.'</td></tr>';
 
         // Capital
         print '<tr><td>'.$langs->trans('Capital').'</td><td>';