ソースを参照

Merge branch 'develop' into 8.0-a6_vat

Laurent Destailleur 7 年 前
コミット
f597e08d06
99 ファイル変更1503 行追加716 行削除
  1. 13 11
      htdocs/accountancy/admin/journals_list.php
  2. 3 2
      htdocs/accountancy/journal/bankjournal.php
  3. 3 0
      htdocs/accountancy/journal/expensereportsjournal.php
  4. 4 0
      htdocs/accountancy/journal/purchasesjournal.php
  5. 4 0
      htdocs/accountancy/journal/sellsjournal.php
  6. 1 1
      htdocs/adherents/card.php
  7. 303 10
      htdocs/adherents/class/adherent.class.php
  8. 6 2
      htdocs/adherents/class/subscription.class.php
  9. 28 247
      htdocs/adherents/subscription.php
  10. 2 0
      htdocs/admin/agenda_extsites.php
  11. 18 7
      htdocs/admin/company.php
  12. 0 17
      htdocs/admin/pdf.php
  13. 24 10
      htdocs/admin/system/dbtable.php
  14. 7 6
      htdocs/admin/system/dolibarr.php
  15. 1 0
      htdocs/admin/taxes.php
  16. 2 2
      htdocs/blockedlog/admin/blockedlog_list.php
  17. 1 1
      htdocs/blockedlog/ajax/block-info.php
  18. 49 8
      htdocs/blockedlog/class/blockedlog.class.php
  19. 1 1
      htdocs/comm/action/card.php
  20. 12 5
      htdocs/comm/action/class/actioncomm.class.php
  21. 104 35
      htdocs/comm/action/index.php
  22. 3 3
      htdocs/comm/action/list.php
  23. 12 10
      htdocs/compta/facture/class/facture.class.php
  24. 1 1
      htdocs/compta/facture/fiche-rec.php
  25. 4 4
      htdocs/compta/facture/list.php
  26. 15 15
      htdocs/compta/localtax/class/localtax.class.php
  27. 2 2
      htdocs/compta/paiement.php
  28. 2 1
      htdocs/compta/paiement/class/paiement.class.php
  29. 2 2
      htdocs/compta/paiement/tovalidate.php
  30. 1 1
      htdocs/compta/prelevement/factures.php
  31. 1 1
      htdocs/compta/resultat/clientfourn.php
  32. 0 1
      htdocs/compta/resultat/index.php
  33. 12 12
      htdocs/compta/stats/index.php
  34. 33 18
      htdocs/core/actions_linkedfiles.inc.php
  35. 1 1
      htdocs/core/boxes/box_commandes.php
  36. 1 1
      htdocs/core/boxes/box_contracts.php
  37. 2 0
      htdocs/core/boxes/box_graph_invoices_permonth.php
  38. 2 2
      htdocs/core/boxes/box_produits.php
  39. 1 1
      htdocs/core/boxes/box_produits_alerte_stock.php
  40. 2 2
      htdocs/core/boxes/box_propales.php
  41. 2 2
      htdocs/core/boxes/box_services_contracts.php
  42. 1 1
      htdocs/core/boxes/box_services_expired.php
  43. 1 1
      htdocs/core/boxes/modules_boxes.php
  44. 1 1
      htdocs/core/class/commondocgenerator.class.php
  45. 7 3
      htdocs/core/class/commonobject.class.php
  46. 1 0
      htdocs/core/class/extrafields.class.php
  47. 2 1
      htdocs/core/class/html.form.class.php
  48. 1 0
      htdocs/core/class/html.formactions.class.php
  49. 3 2
      htdocs/core/class/html.formcompany.class.php
  50. 3 2
      htdocs/core/class/html.formother.class.php
  51. 3 4
      htdocs/core/class/html.formwebsite.class.php
  52. 4 4
      htdocs/core/class/utils.class.php
  53. 3 2
      htdocs/core/lib/admin.lib.php
  54. 18 8
      htdocs/core/lib/functions.lib.php
  55. 1 0
      htdocs/core/lib/website.lib.php
  56. 1 1
      htdocs/core/menus/standard/eldy.lib.php
  57. 4 4
      htdocs/core/tpl/contacts.tpl.php
  58. 46 5
      htdocs/core/triggers/interface_50_modAgenda_ActionsAuto.class.php
  59. 4 2
      htdocs/core/triggers/interface_50_modBlockedlog_ActionsBlockedLog.class.php
  60. 4 4
      htdocs/expedition/class/expedition.class.php
  61. 14 14
      htdocs/index.php
  62. 3 1
      htdocs/install/mysql/data/llx_c_action_trigger.sql
  63. 6 1
      htdocs/install/mysql/migration/6.0.0-7.0.0.sql
  64. 1 1
      htdocs/install/mysql/tables/llx_expensereport_rules.sql
  65. 0 1
      htdocs/langs/en_US/admin.lang
  66. 3 1
      htdocs/langs/en_US/agenda.lang
  67. 1 0
      htdocs/langs/en_US/compta.lang
  68. 5 0
      htdocs/langs/en_US/main.lang
  69. 2 2
      htdocs/langs/en_US/other.lang
  70. 3 1
      htdocs/langs/en_US/paypal.lang
  71. 2 1
      htdocs/langs/en_US/stripe.lang
  72. 2 2
      htdocs/langs/fr_FR/accountancy.lang
  73. 2 2
      htdocs/langs/fr_FR/other.lang
  74. 11 0
      htdocs/paybox/admin/paybox.php
  75. 9 0
      htdocs/paypal/admin/paypal.php
  76. 87 29
      htdocs/paypal/lib/paypal.lib.php
  77. 24 4
      htdocs/product/stock/mouvement.php
  78. 10 10
      htdocs/product/stock/tpl/stockcorrection.tpl.php
  79. 9 9
      htdocs/product/stock/tpl/stocktransfer.tpl.php
  80. 20 16
      htdocs/projet/class/task.class.php
  81. 1 1
      htdocs/projet/tasks/contact.php
  82. 1 1
      htdocs/projet/tasks/document.php
  83. 1 1
      htdocs/projet/tasks/note.php
  84. 3 3
      htdocs/projet/tasks/task.php
  85. 6 2
      htdocs/projet/tasks/time.php
  86. 3 1
      htdocs/public/members/new.php
  87. 22 9
      htdocs/public/payment/newpayment.php
  88. 362 40
      htdocs/public/payment/paymentok.php
  89. 1 1
      htdocs/public/paypal/newpayment.php
  90. 1 1
      htdocs/public/stripe/newpayment.php
  91. 23 25
      htdocs/societe/class/societe.class.php
  92. 13 1
      htdocs/stripe/admin/stripe.php
  93. 1 0
      htdocs/supplier_proposal/class/supplier_proposal.class.php
  94. 35 21
      htdocs/theme/eldy/style.css.php
  95. 10 8
      htdocs/theme/md/style.css.php
  96. 3 3
      htdocs/user/class/user.class.php
  97. 8 12
      htdocs/user/perms.php
  98. 1 1
      htdocs/website/class/website.class.php
  99. 1 0
      scripts/product/migrate_picture_path.php

+ 13 - 11
htdocs/accountancy/admin/journals_list.php

@@ -177,6 +177,11 @@ if (GETPOST('actionadd') || GETPOST('actionmodify'))
 	    	$msg .= $langs->transnoentities('ErrorFieldFormat', $langs->transnoentities('Code')).'<br>';
 	    }*/
 	}
+	if (! GETPOST('label','alpha'))
+	{
+		setEventMessages($langs->transnoentities("ErrorFieldRequired", $langs->transnoentitiesnoconv("Label")), null, 'errors');
+		$ok=0;
+	}
 
 	// Clean some parameters
 	if ($_POST["accountancy_code"] <= 0) $_POST["accountancy_code"]='';	// If empty, we force to null
@@ -208,7 +213,7 @@ if (GETPOST('actionadd') || GETPOST('actionmodify'))
 		if ($tabrowid[$id] && ! in_array($tabrowid[$id],$listfieldinsert))
 			$sql.= $tabrowid[$id].",";
 		$sql.= $tabfieldinsert[$id];
-		$sql.=",active)";
+		$sql.=",active,entity)";
 		$sql.= " VALUES(";
 
 		// List of values
@@ -221,11 +226,11 @@ if (GETPOST('actionadd') || GETPOST('actionmodify'))
 				$_POST[$listfieldvalue[$i]] = $conf->entity;
 			}
 			if ($i) $sql.=",";
-			if ($_POST[$listfieldvalue[$i]] == '' && ! ($listfieldvalue[$i] == 'code' && $id == 10)) $sql.="null";  // For vat, we want/accept code = ''
+			if ($_POST[$listfieldvalue[$i]] == '') $sql.="null";  // For vat, we want/accept code = ''
 			else $sql.="'".$db->escape($_POST[$listfieldvalue[$i]])."'";
 			$i++;
 		}
-		$sql.=",1)";
+		$sql.=",1,".$conf->entity.")";
 
 		dol_syslog("actionadd", LOG_DEBUG);
 		$result = $db->query($sql);
@@ -275,6 +280,7 @@ if (GETPOST('actionadd') || GETPOST('actionmodify'))
 			$i++;
 		}
 		$sql.= " WHERE ".$rowidcol." = '".$rowid."'";
+		$sql.=" AND entity = ".$conf->entity;
 
 		dol_syslog("actionmodify", LOG_DEBUG);
 		//print $sql;
@@ -298,6 +304,7 @@ if ($action == 'confirm_delete' && $confirm == 'yes')       // delete
 	else { $rowidcol="rowid"; }
 
 	$sql = "DELETE from ".$tabname[$id]." WHERE ".$rowidcol."='".$rowid."'";
+	$sql.=" AND entity = ".$conf->entity;
 
 	dol_syslog("delete", LOG_DEBUG);
 	$result = $db->query($sql);
@@ -326,6 +333,7 @@ if ($action == $acts[0])
 	elseif ($code) {
 		$sql = "UPDATE ".$tabname[$id]." SET active = 1 WHERE code='".$code."'";
 	}
+	$sql.=" AND entity = ".$conf->entity;
 
 	$result = $db->query($sql);
 	if (!$result)
@@ -346,6 +354,7 @@ if ($action == $acts[1])
 	elseif ($code) {
 		$sql = "UPDATE ".$tabname[$id]." SET active = 0 WHERE code='".$code."'";
 	}
+	$sql.=" AND entity = ".$conf->entity;
 
 	$result = $db->query($sql);
 	if (!$result)
@@ -389,13 +398,7 @@ if ($id)
 {
 	// Complete requete recherche valeurs avec critere de tri
 	$sql=$tabsql[$id];
-
-	if ($search_country_id > 0)
-	{
-		if (preg_match('/ WHERE /',$sql)) $sql.= " AND ";
-		else $sql.=" WHERE ";
-		$sql.= " c.rowid = ".$search_country_id;
-	}
+	$sql.= " WHERE a.entity = ".$conf->entity;
 
 	if ($sortfield)
 	{
@@ -416,7 +419,6 @@ if ($id)
 	}
 	$sql.=$tabsqlsort[$id];
 	$sql.=$db->plimit($listlimit+1,$offset);
-	//print $sql;
 
 	$fieldlist=explode(',',$tabfield[$id]);
 

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

@@ -455,6 +455,7 @@ if (! $error && $action == 'writebookkeeping') {
 					// No subledger_account value for the bank line but add a specific label_operation
 					$bookkeeping->subledger_account = '';
 					$bookkeeping->label_operation = $reflabel;
+					$bookkeeping->entity = $conf->entity;
 
 					$totaldebit += $bookkeeping->debit;
 					$totalcredit += $bookkeeping->credit;
@@ -561,8 +562,8 @@ if (! $error && $action == 'writebookkeeping') {
 								$bookkeeping->label_compte = '';
 							}
 						}
-
 						$bookkeeping->label_operation = $reflabel;
+						$bookkeeping->entity = $conf->entity;
 
 						$totaldebit += $bookkeeping->debit;
 						$totalcredit += $bookkeeping->credit;
@@ -608,8 +609,8 @@ if (! $error && $action == 'writebookkeeping') {
 						$bookkeeping->fk_user_author = $user->id;
 						$bookkeeping->date_create = $now;
 						$bookkeeping->label_compte = '';
-
 						$bookkeeping->label_operation = $reflabel;
+						$bookkeeping->entity = $conf->entity;
 
 						$totaldebit += $bookkeeping->debit;
 						$totalcredit += $bookkeeping->credit;

+ 3 - 0
htdocs/accountancy/journal/expensereportsjournal.php

@@ -216,6 +216,7 @@ if ($action == 'writebookkeeping') {
 					$bookkeeping->code_journal = $journal;
 					$bookkeeping->journal_label = $journal_label;
 					$bookkeeping->fk_user_author = $user->id;
+					$bookkeeping->entity = $conf->entity;
 
 					$totaldebit += $bookkeeping->debit;
 					$totalcredit += $bookkeeping->credit;
@@ -265,6 +266,7 @@ if ($action == 'writebookkeeping') {
 						$bookkeeping->code_journal = $journal;
 						$bookkeeping->journal_label = $journal_label;
 						$bookkeeping->fk_user_author = $user->id;
+						$bookkeeping->entity = $conf->entity;
 
 						$totaldebit += $bookkeeping->debit;
 						$totalcredit += $bookkeeping->credit;
@@ -320,6 +322,7 @@ if ($action == 'writebookkeeping') {
 					$bookkeeping->code_journal = $journal;
 					$bookkeeping->journal_label = $journal_label;
 					$bookkeeping->fk_user_author = $user->id;
+					$bookkeeping->entity = $conf->entity;
 
 					$totaldebit += $bookkeeping->debit;
 					$totalcredit += $bookkeeping->credit;

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

@@ -318,6 +318,7 @@ if ($action == 'writebookkeeping') {
 					$bookkeeping->code_journal = $journal;
 					$bookkeeping->journal_label = $journal_label;
 					$bookkeeping->fk_user_author = $user->id;
+					$bookkeeping->entity = $conf->entity;
 
 					$totaldebit += $bookkeeping->debit;
 					$totalcredit += $bookkeeping->credit;
@@ -371,6 +372,7 @@ if ($action == 'writebookkeeping') {
 						$bookkeeping->code_journal = $journal;
 						$bookkeeping->journal_label = $journal_label;
 						$bookkeeping->fk_user_author = $user->id;
+						$bookkeeping->entity = $conf->entity;
 
 						$totaldebit += $bookkeeping->debit;
 						$totalcredit += $bookkeeping->credit;
@@ -430,6 +432,7 @@ if ($action == 'writebookkeeping') {
 						$bookkeeping->code_journal = $journal;
 						$bookkeeping->journal_label = $journal_label;
 						$bookkeeping->fk_user_author = $user->id;
+						$bookkeeping->entity = $conf->entity;
 
 						$totaldebit += $bookkeeping->debit;
 						$totalcredit += $bookkeeping->credit;
@@ -482,6 +485,7 @@ if ($action == 'writebookkeeping') {
 					$bookkeeping->code_journal = $journal;
 					$bookkeeping->journal_label = $journal_label;
 					$bookkeeping->fk_user_author = $user->id;
+					$bookkeeping->entity = $conf->entity;
 
 					$totaldebit += $bookkeeping->debit;
 					$totalcredit += $bookkeeping->credit;

+ 4 - 0
htdocs/accountancy/journal/sellsjournal.php

@@ -121,6 +121,7 @@ if ($in_bookkeeping == 'notyet')
 //	$sql .= " AND fd.rowid NOT IN (SELECT fk_docdet FROM " . MAIN_DB_PREFIX . "accounting_bookkeeping as ab WHERE ab.doc_type='customer_invoice')";		// Useless, we save one line for all products with same account
 }
 $sql .= " ORDER BY f.datef";
+//print $sql;
 
 dol_syslog('accountancy/journal/sellsjournal.php', LOG_DEBUG);
 $result = $db->query($sql);
@@ -319,6 +320,7 @@ if ($action == 'writebookkeeping') {
 					$bookkeeping->code_journal = $journal;
 					$bookkeeping->journal_label = $journal_label;
 					$bookkeeping->fk_user_author = $user->id;
+					$bookkeeping->entity = $conf->entity;
 
 					$totaldebit += $bookkeeping->debit;
 					$totalcredit += $bookkeeping->credit;
@@ -372,6 +374,7 @@ if ($action == 'writebookkeeping') {
 						$bookkeeping->code_journal = $journal;
 						$bookkeeping->journal_label = $journal_label;
 						$bookkeeping->fk_user_author = $user->id;
+						$bookkeeping->entity = $conf->entity;
 
 						$totaldebit += $bookkeeping->debit;
 						$totalcredit += $bookkeeping->credit;
@@ -430,6 +433,7 @@ if ($action == 'writebookkeeping') {
 						$bookkeeping->code_journal = $journal;
 						$bookkeeping->journal_label = $journal_label;
 						$bookkeeping->fk_user_author = $user->id;
+						$bookkeeping->entity = $conf->entity;
 
 						$totaldebit += $bookkeeping->debit;
 						$totalcredit += $bookkeeping->credit;

+ 1 - 1
htdocs/adherents/card.php

@@ -1822,7 +1822,7 @@ else
 
 		// Presend form
 		$modelmail='member';
-		$defaulttopic='SendMemberRef';
+		$defaulttopic='CardContent';
 		$diroutput = $conf->adherent->dir_output;
 		$trackid = 'mem'.$object->id;
 

+ 303 - 10
htdocs/adherents/class/adherent.class.php

@@ -1248,9 +1248,9 @@ class Adherent extends CommonObject
 	 *	Insert subscription into database and eventually add links to banks, mailman, etc...
 	 *
 	 *	@param	int	        $date        		Date of effect of subscription
-	 *	@param	double		$montant     		Amount of subscription (0 accepted for some members)
+	 *	@param	double		$amount     		Amount of subscription (0 accepted for some members)
 	 *	@param	int			$accountid			Id bank account
-	 *	@param	string		$operation			Type operation (if Id bank account provided)
+	 *	@param	string		$operation			Type of payment (if Id bank account provided). Example: 'CB', ...
 	 *	@param	string		$label				Label operation (if Id bank account provided)
 	 *	@param	string		$num_chq			Numero cheque (if Id bank account provided)
 	 *	@param	string		$emetteur_nom		Name of cheque writer
@@ -1258,7 +1258,7 @@ class Adherent extends CommonObject
 	 *	@param	int     	$datesubend			Date end subscription
 	 *	@return int         					rowid of record added, <0 if KO
 	 */
-	function subscription($date, $montant, $accountid=0, $operation='', $label='', $num_chq='', $emetteur_nom='', $emetteur_banque='', $datesubend=0)
+	function subscription($date, $amount, $accountid=0, $operation='', $label='', $num_chq='', $emetteur_nom='', $emetteur_banque='', $datesubend=0)
 	{
 		global $conf,$langs,$user;
 
@@ -1267,7 +1267,7 @@ class Adherent extends CommonObject
 		$error=0;
 
 		// Clean parameters
-		if (! $montant) $montant=0;
+		if (! $amount) $amount=0;
 
 		$this->db->begin();
 
@@ -1287,8 +1287,9 @@ class Adherent extends CommonObject
 		$subscription->fk_adherent=$this->id;
 		$subscription->dateh=$date;		// Date of new subscription
 		$subscription->datef=$datefin;	// End data of new subscription
-		$subscription->amount=$montant;
-		$subscription->note=$label;
+		$subscription->amount=$amount;
+		$subscription->note=$label;		// deprecated
+		$subscription->note_public=$label;
 
 		$rowid=$subscription->create($user);
 		if ($rowid > 0)
@@ -1300,7 +1301,7 @@ class Adherent extends CommonObject
 			{
 				// Change properties of object (used by triggers)
 				$this->last_subscription_date=dol_now();
-				$this->last_subscription_amount=$montant;
+				$this->last_subscription_amount=$amount;
 				$this->last_subscription_date_start=$date;
 				$this->last_subscription_date_end=$datefin;
 			}
@@ -1319,11 +1320,303 @@ class Adherent extends CommonObject
 		else
 		{
 			$this->error=$subscription->error;
+			$this->errors=$subscription->errors;
 			$this->db->rollback();
 			return -1;
 		}
 	}
 
+
+	/**
+	 *	Do complementary actions after subscription recording.
+	 *
+	 *	@param	int			$subscriptionid		Id of created subscription
+	 *  @param	string		$option				Which action ('bankdirect', 'invoiceonly', ...)
+	 *	@param	int			$accountid			Id bank account
+	 *	@param	int			$datesubscription	Date of subscription
+	 *	@param	int			$paymentdate		Date of payment
+	 *	@param	string		$operation			Code of type of operation (if Id bank account provided). Example 'CB', ...
+	 *	@param	string		$label				Label operation (if Id bank account provided)
+	 *	@param	double		$amount     		Amount of subscription (0 accepted for some members)
+	 *	@param	string		$num_chq			Numero cheque (if Id bank account provided)
+	 *	@param	string		$emetteur_nom		Name of cheque writer
+	 *	@param	string		$emetteur_banque	Name of bank of cheque
+	 *  @param	string		$autocreatethirdparty	Auto create new thirdparty if member not linked to a thirdparty.
+	 *	@return int         					<0 if KO, >0 if OK
+	 */
+	function subscriptionComplementaryActions($subscriptionid, $option, $accountid, $datesubscription, $paymentdate, $operation, $label, $amount, $num_chq, $emetteur_nom='', $emetteur_banque='', $autocreatethirdparty=0)
+	{
+		global $conf, $langs, $user, $mysoc;
+
+		$error = 0;
+
+		// Insert into bank account directlty (if option choosed for) + link to llx_subscription if option is 'bankdirect'
+		if ($option == 'bankdirect' && $accountid)
+		{
+			require_once DOL_DOCUMENT_ROOT.'/compta/bank/class/account.class.php';
+
+			$acct=new Account($this->db);
+			$result=$acct->fetch($accountid);
+
+			$dateop=$paymentdate;
+
+			$insertid=$acct->addline($dateop, $operation, $label, $amount, $num_chq, '', $user, $emetteur_nom, $emetteur_banque);
+			if ($insertid > 0)
+			{
+				$inserturlid=$acct->add_url_line($insertid, $this->id, DOL_URL_ROOT.'/adherents/card.php?rowid=', $this->getFullname($langs), 'member');
+				if ($inserturlid > 0)
+				{
+					// Update table subscription
+					$sql ="UPDATE ".MAIN_DB_PREFIX."subscription SET fk_bank=".$insertid;
+					$sql.=" WHERE rowid=".$subscriptionid;
+
+					dol_syslog("subscription::subscription", LOG_DEBUG);
+					$resql = $this->db->query($sql);
+					if (! $resql)
+					{
+						$error++;
+						$this->error=$this->db->lasterror();
+						$this->errors[]=$this->error;
+					}
+				}
+				else
+				{
+					$error++;
+					$this->error=$acct->error;
+					$this->errors=$acct->errors;
+				}
+			}
+			else
+			{
+				$error++;
+				$this->error=$acct->error;
+				$this->errors=$acct->errors;
+			}
+		}
+
+		// If option choosed, we create invoice
+		if (($option == 'bankviainvoice' && $accountid) || $option == 'invoiceonly')
+		{
+			require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
+			require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/paymentterm.class.php';
+
+			$invoice=new Facture($this->db);
+			$customer=new Societe($this->db);
+
+			if (! $error)
+			{
+				if (! ($this->fk_soc > 0))
+				{
+					if ($autocreatethirdparty)
+					{
+						// Create a linked thirdparty to member
+						$companyalias='';
+						$fullname = $this->getFullName($langs);
+
+						if ($this->morphy == 'mor')
+						{
+							$companyname=$this->societe;
+							if (! empty($fullname)) $companyalias=$fullname;
+						}
+						else
+						{
+							$companyname=$fullname;
+							if (! empty($this->societe)) $companyalias=$this->societe;
+						}
+
+						$result=$customer->create_from_member($this, $companyname, $companyalias);
+						if ($result < 0)
+						{
+							$this->error = $company->error;
+							$this->errors = $company->errors;
+							$error++;
+						}
+						else
+						{
+							$this->fk_soc = $result;
+						}
+					}
+					else
+					{
+						 $langs->load("errors");
+						 $this->error=$langs->trans("ErrorMemberNotLinkedToAThirpartyLinkOrCreateFirst");
+						 $this->errors[]=$this->error;
+						 $error++;
+					}
+				}
+			}
+			if (! $error)
+			{
+				$result=$customer->fetch($this->fk_soc);
+				if ($result <= 0)
+				{
+					$this->error=$customer->error;
+					$this->errors=$customer->errors;
+					$error++;
+				}
+			}
+
+			if (! $error)
+			{
+				// Create draft invoice
+				$invoice->type=Facture::TYPE_STANDARD;
+				$invoice->cond_reglement_id=$customer->cond_reglement_id;
+				if (empty($invoice->cond_reglement_id))
+				{
+					$paymenttermstatic=new PaymentTerm($this->db);
+					$invoice->cond_reglement_id=$paymenttermstatic->getDefaultId();
+					if (empty($invoice->cond_reglement_id))
+					{
+						$error++;
+						$this->error='ErrorNoPaymentTermRECEPFound';
+						$this->errors[]=$this->error;
+					}
+				}
+				$invoice->socid=$this->fk_soc;
+				$invoice->date=$datesubscription;
+
+				// Possibility to add external linked objects with hooks
+				$invoice->linked_objects['subscription'] = $subscriptionid;
+				if (! empty($_POST['other_linked_objects']) && is_array($_POST['other_linked_objects']))
+				{
+					$invoice->linked_objects = array_merge($invoice->linked_objects, $_POST['other_linked_objects']);
+				}
+
+				$result=$invoice->create($user);
+				if ($result <= 0)
+				{
+					$this->error=$invoice->error;
+					$this->errors=$invoice->errors;
+					$error++;
+				}
+			}
+
+			if (! $error)
+			{
+				// Add line to draft invoice
+				$idprodsubscription=0;
+				if (! empty($conf->global->ADHERENT_PRODUCT_ID_FOR_SUBSCRIPTIONS) && (! empty($conf->product->enabled) || ! empty($conf->service->enabled))) $idprodsubscription = $conf->global->ADHERENT_PRODUCT_ID_FOR_SUBSCRIPTIONS;
+
+				$vattouse=0;
+				if (isset($conf->global->ADHERENT_VAT_FOR_SUBSCRIPTIONS) && $conf->global->ADHERENT_VAT_FOR_SUBSCRIPTIONS == 'defaultforfoundationcountry')
+				{
+					$vattouse=get_default_tva($mysoc, $mysoc, $idprodsubscription);
+				}
+				//print xx".$vattouse." - ".$mysoc." - ".$customer;exit;
+				$result=$invoice->addline($label,0,1,$vattouse,0,0,$idprodsubscription,0,$datesubscription,$datesubend,0,0,'','TTC',$amount,1);
+				if ($result <= 0)
+				{
+					$this->error=$invoice->error;
+					$this->errors=$invoice->errors;
+					$error++;
+				}
+			}
+
+			if (! $error)
+			{
+				// Validate invoice
+				$result=$invoice->validate($user);
+				if ($result <= 0)
+				{
+					$this->error=$invoice->error;
+					$this->errors=$invoice->errors;
+					$error++;
+				}
+			}
+
+			// Add payment onto invoice
+			if (! $error && $option == 'bankviainvoice' && $accountid)
+			{
+				require_once DOL_DOCUMENT_ROOT.'/compta/paiement/class/paiement.class.php';
+				require_once DOL_DOCUMENT_ROOT.'/compta/bank/class/account.class.php';
+				require_once DOL_DOCUMENT_ROOT.'/core/lib/functions.lib.php';
+
+				$amounts = array();
+				$amounts[$invoice->id] = price2num($amount);
+
+				$paiement = new Paiement($this->db);
+				$paiement->datepaye     = $paymentdate;
+				$paiement->amounts      = $amounts;
+				$paiement->paiementid   = dol_getIdFromCode($this->db,$operation,'c_paiement','code','id',1);
+				$paiement->num_paiement = $num_chq;
+				$paiement->note         = $label;
+				$paiement->note_public  = $label;
+
+				if (! $error)
+				{
+					// Create payment line for invoice
+					$paiement_id = $paiement->create($user);
+					if (! $paiement_id > 0)
+					{
+						$this->error=$paiement->error;
+						$this->errors=$paiement->errors;
+						$error++;
+					}
+				}
+
+				if (! $error)
+				{
+					// Add transaction into bank account
+					$bank_line_id=$paiement->addPaymentToBank($user,'payment','(SubscriptionPayment)',$accountid,$emetteur_nom,$emetteur_banque);
+					if (! ($bank_line_id > 0))
+					{
+						$this->error=$paiement->error;
+						$this->errors=$paiement->errors;
+						$error++;
+					}
+				}
+
+				if (! $error)
+				{
+					// Update fk_bank into subscription table
+					$sql = 'UPDATE '.MAIN_DB_PREFIX.'subscription SET fk_bank='.$bank_line_id;
+					$sql.= ' WHERE rowid='.$subscriptionid;
+
+					$result = $this->db->query($sql);
+					if (! $result)
+					{
+						$error++;
+					}
+				}
+
+				if (! $error)
+				{
+					// Set invoice as paid
+					$invoice->set_paid($user);
+				}
+
+				if (! $error)
+				{
+					// Define output language
+					$outputlangs = $langs;
+					$newlang = '';
+					if ($conf->global->MAIN_MULTILANGS && empty($newlang) && ! empty($_REQUEST['lang_id']))
+						$newlang = $_REQUEST['lang_id'];
+					if ($conf->global->MAIN_MULTILANGS && empty($newlang))
+						$newlang = $customer->default_lang;
+					if (! empty($newlang)) {
+							$outputlangs = new Translate("", $conf);
+							$outputlangs->setDefaultLang($newlang);
+					}
+					// Generate PDF (whatever is option MAIN_DISABLE_PDF_AUTOUPDATE) so we can include it into email
+					//if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE))
+
+					$invoice->generateDocument($invoice->modelpdf, $outputlangs, $hidedetails, $hidedesc, $hideref);
+				}
+			}
+		}
+
+		if ($error)
+		{
+			return -1;
+		}
+		else
+		{
+			return 1;
+		}
+	}
+
+
 	/**
 	 *		Function that validate a member
 	 *
@@ -2155,9 +2448,9 @@ class Adherent extends CommonObject
 	/**
 	 * Function used to replace a thirdparty id with another one.
 	 *
-	 * @param DoliDB $db Database handler
-	 * @param int $origin_id Old thirdparty id
-	 * @param int $dest_id New thirdparty id
+	 * @param DoliDB 	$db 			Database handler
+	 * @param int 		$origin_id 		Old thirdparty id
+	 * @param int 		$dest_id 		New thirdparty id
 	 * @return bool
 	 */
 	public static function replaceThirdparty($db, $origin_id, $dest_id)

+ 6 - 2
htdocs/adherents/class/subscription.class.php

@@ -77,15 +77,17 @@ class Subscription extends CommonObject
 			$this->error=$langs->trans("ErrorBadValueForDate");
 			return -1;
 		}
+		if (empty($this->datec)) $this->datec = $now;
+
 
 		$this->db->begin();
 
 		$sql = "INSERT INTO ".MAIN_DB_PREFIX."subscription (fk_adherent, datec, dateadh, datef, subscription, note)";
-        $sql.= " VALUES (".$this->fk_adherent.", '".$this->db->idate($now)."',";
+        $sql.= " VALUES (".$this->fk_adherent.", '".$this->db->idate($this->datec)."',";
 		$sql.= " '".$this->db->idate($this->dateh)."',";
 		$sql.= " '".$this->db->idate($this->datef)."',";
 		$sql.= " ".$this->amount.",";
-		$sql.= " '".$this->db->escape($this->note)."')";
+		$sql.= " '".$this->db->escape($this->note_public?$this->note_public:$this->note)."')";
 
 		$resql = $this->db->query($sql);
 		if (! $resql) {
@@ -324,6 +326,8 @@ class Subscription extends CommonObject
 		global $langs;
 
 		$result='';
+
+		$langs->load("members");
         $label=$langs->trans("ShowSubscription").': '.$this->ref;
 
         $linkstart = '<a href="'.DOL_URL_ROOT.'/adherents/subscription/card.php?rowid='.$this->id.'" title="'.dol_escape_htmltag($label, 1).'" class="classfortooltip">';

+ 28 - 247
htdocs/adherents/subscription.php

@@ -118,7 +118,7 @@ if ($action == 'confirm_create_thirdparty' && $confirm == 'yes' && $user->rights
 {
 	if ($result > 0)
 	{
-		// Creation user
+		// Creation of thirdparty
 		$company = new Societe($db);
 		$result=$company->create_from_member($object, GETPOST('companyname', 'alpha'), GETPOST('companyalias', 'alpha'));
 
@@ -203,8 +203,8 @@ if ($user->rights->adherent->cotisation->creer && $action == 'subscription' && !
 
     $langs->load("banks");
 
-    $result=$object->fetch($rowid);
-    $result=$adht->fetch($object->typeid);
+    $result = $object->fetch($rowid);
+    $result = $adht->fetch($object->typeid);
 
     // Subscription informations
     $datesubscription=0;
@@ -222,7 +222,7 @@ if ($user->rights->adherent->cotisation->creer && $action == 'subscription' && !
     {
         $paymentdate=dol_mktime(0, 0, 0, $_POST["paymentmonth"], $_POST["paymentday"], $_POST["paymentyear"]);
     }
-    $subscription=price2num(GETPOST("subscription",'alpha'));	// Amount of subscription
+    $amount=price2num(GETPOST("subscription",'alpha'));	// Amount of subscription
     $label=$_POST["label"];
 
     // Payment informations
@@ -233,6 +233,7 @@ if ($user->rights->adherent->cotisation->creer && $action == 'subscription' && !
     $emetteur_banque=$_POST["chqbank"];
     $option=$_POST["paymentsave"];
     if (empty($option)) $option='none';
+    $sendalsoemail=GETPOST("sendmail",'alpha');
 
     // Check parameters
     if (! $datesubscription)
@@ -263,8 +264,6 @@ if ($user->rights->adherent->cotisation->creer && $action == 'subscription' && !
         $action='addsubscription';
     }
 
-    $amount = price2num(GETPOST("subscription",'alpha'));
-
     // Check if a payment is mandatory or not
     if (! $error && $adht->subscription)	// Member type need subscriptions
     {
@@ -284,7 +283,7 @@ if ($user->rights->adherent->cotisation->creer && $action == 'subscription' && !
                 {
                     if (! $_POST["label"])     $errmsg=$langs->trans("ErrorFieldRequired",$langs->transnoentities("Label"));
                     if ($_POST["paymentsave"] != 'invoiceonly' && ! $_POST["operation"]) $errmsg=$langs->trans("ErrorFieldRequired",$langs->transnoentities("PaymentMode"));
-                    if ($_POST["paymentsave"] != 'invoiceonly' && ! $_POST["accountid"]) $errmsg=$langs->trans("ErrorFieldRequired",$langs->transnoentities("FinancialAccount"));
+                    if ($_POST["paymentsave"] != 'invoiceonly' && ! ($_POST["accountid"] > 0)) $errmsg=$langs->trans("ErrorFieldRequired",$langs->transnoentities("FinancialAccount"));
                 }
                 else
                 {
@@ -292,19 +291,22 @@ if ($user->rights->adherent->cotisation->creer && $action == 'subscription' && !
                 }
                 if ($errmsg)
                 {
+                	$error++;
         			setEventMessages($errmsg, null, 'errors');
+        			$error++;
                 	$action='addsubscription';
                 }
             }
         }
     }
 
+    // Record the subscription then complementary actions
     if (! $error && $action=='subscription')
     {
         $db->begin();
 
         // Create subscription
-        $crowid=$object->subscription($datesubscription, $subscription, $accountid, $operation, $label, $num_chq, $emetteur_nom, $emetteur_banque, $datesubend);
+        $crowid=$object->subscription($datesubscription, $amount, $accountid, $operation, $label, $num_chq, $emetteur_nom, $emetteur_banque, $datesubend);
         if ($crowid <= 0)
         {
             $error++;
@@ -314,233 +316,12 @@ if ($user->rights->adherent->cotisation->creer && $action == 'subscription' && !
 
         if (! $error)
         {
-            // Insert into bank account directlty (if option choosed for) + link to llx_subscription if option is 'bankdirect'
-            if ($option == 'bankdirect' && $accountid)
-            {
-                require_once DOL_DOCUMENT_ROOT.'/compta/bank/class/account.class.php';
-
-                $acct=new Account($db);
-                $result=$acct->fetch($accountid);
-
-                $dateop=$paymentdate;
-
-                $insertid=$acct->addline($dateop, $operation, $label, $subscription, $num_chq, '', $user, $emetteur_nom, $emetteur_banque);
-                if ($insertid > 0)
-                {
-                    $inserturlid=$acct->add_url_line($insertid, $object->id, DOL_URL_ROOT.'/adherents/card.php?rowid=', $object->getFullname($langs), 'member');
-                    if ($inserturlid > 0)
-                    {
-                        // Update table subscription
-                        $sql ="UPDATE ".MAIN_DB_PREFIX."subscription SET fk_bank=".$insertid;
-                        $sql.=" WHERE rowid=".$crowid;
-
-                        dol_syslog("subscription::subscription", LOG_DEBUG);
-                        $resql = $db->query($sql);
-                        if (! $resql)
-                        {
-                            $error++;
-                            $errmsg=$db->lasterror();
-        					setEventMessages($errmsg, null, 'errors');
-                        }
-                    }
-                    else
-					{
-                        $error++;
-                        $errmsg=$acct->error;
-                        $errmsgs=$acct->errors;
-        				setEventMessages($errmsg, $errmsgs, 'errors');
-					}
-                }
-                else
-				{
-                    $error++;
-                    $errmsg=$acct->error;
-                    $errmsgs=$acct->errors;
-        			setEventMessages($errmsg, $errmsgs, 'errors');
-				}
-            }
-
-            // If option choosed, we create invoice
-            if (($option == 'bankviainvoice' && $accountid) || $option == 'invoiceonly')
-            {
-                require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
-                require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/paymentterm.class.php';
-
-                $invoice=new Facture($db);
-                $customer=new Societe($db);
-
-                if (! $error)
-                {
-                	if (! ($object->fk_soc > 0))
-                	{
-                		$langs->load("errors");
-                		$errmsg=$langs->trans("ErrorMemberNotLinkedToAThirpartyLinkOrCreateFirst");
-        				setEventMessages($errmsg, null, 'errors');
-                		$error++;
-                	}
-                }
-                if (! $error)
-                {
-	                $result=$customer->fetch($object->fk_soc);
-	                if ($result <= 0)
-	                {
-	                    $errmsg=$customer->error;
-	                    $errmsgs=$acct->errors;
-        				setEventMessages($errmsg, $errmsgs, 'errors');
-	                    $error++;
-	                }
-                }
-
-                if (! $error)
-                {
-	                // Create draft invoice
-	                $invoice->type= Facture::TYPE_STANDARD;
-	                $invoice->cond_reglement_id=$customer->cond_reglement_id;
-	                if (empty($invoice->cond_reglement_id))
-	                {
-	                    $paymenttermstatic=new PaymentTerm($db);
-	                    $invoice->cond_reglement_id=$paymenttermstatic->getDefaultId();
-	                    if (empty($invoice->cond_reglement_id))
-	                    {
-	                        $error++;
-	                        $errmsg='ErrorNoPaymentTermRECEPFound';
-        					setEventMessages($errmsg, null, 'errors');
-	                    }
-	                }
-	                $invoice->socid=$object->fk_soc;
-	                $invoice->date=$datesubscription;
-
-	                // Possibility to add external linked objects with hooks
-	                $invoice->linked_objects['subscription'] = $crowid;
-	                if (! empty($_POST['other_linked_objects']) && is_array($_POST['other_linked_objects']))
-	                {
-	                    $invoice->linked_objects = array_merge($invoice->linked_objects, $_POST['other_linked_objects']);
-	                }
-
-	                $result=$invoice->create($user);
-	                if ($result <= 0)
-	                {
-	                    $errmsg=$invoice->error;
-	                    $errmsgs=$invoice->errors;
-        				setEventMessages($errmsg, $errmsgs, 'errors');
-	                    $error++;
-	                }
-                }
-
-                if (! $error)
-                {
-	                // Add line to draft invoice
-	                $idprodsubscription=0;
-			        if (! empty($conf->global->ADHERENT_PRODUCT_ID_FOR_SUBSCRIPTIONS) && (! empty($conf->product->enabled) || ! empty($conf->service->enabled))) $idprodsubscription = $conf->global->ADHERENT_PRODUCT_ID_FOR_SUBSCRIPTIONS;
-
-	                $vattouse=0;
-	                if (isset($conf->global->ADHERENT_VAT_FOR_SUBSCRIPTIONS) && $conf->global->ADHERENT_VAT_FOR_SUBSCRIPTIONS == 'defaultforfoundationcountry')
-	                {
-	                	$vattouse=get_default_tva($mysoc, $mysoc, $idprodsubscription);
-	                }
-	                //print xx".$vattouse." - ".$mysoc." - ".$customer;exit;
-	                $result=$invoice->addline($label,0,1,$vattouse,0,0,$idprodsubscription,0,$datesubscription,$datesubend,0,0,'','TTC',$subscription,1);
-	                if ($result <= 0)
-	                {
-	                    $errmsg=$invoice->error;
-        				setEventMessages($errmsg, null, 'errors');
-	                    $error++;
-	                }
-                }
-
-                if (! $error)
-                {
-	                // Validate invoice
-	                $result=$invoice->validate($user);
-   	                if ($result <= 0)
-	                {
-	                    $errmsg=$invoice->error;
-	                    $errmsgs=$invoice->errors;
-        				setEventMessages($errmsg, $errmsgs, 'errors');
-	                    $error++;
-	                }
-                }
-
-                // Add payment onto invoice
-                if ($option == 'bankviainvoice' && $accountid)
-                {
-                    require_once DOL_DOCUMENT_ROOT.'/compta/paiement/class/paiement.class.php';
-                    require_once DOL_DOCUMENT_ROOT.'/compta/bank/class/account.class.php';
-                    require_once DOL_DOCUMENT_ROOT.'/core/lib/functions.lib.php';
-
-                    $amounts[$invoice->id] = price2num($subscription);
-                    $paiement = new Paiement($db);
-                    $paiement->datepaye     = $paymentdate;
-                    $paiement->amounts      = $amounts;
-                    $paiement->paiementid   = dol_getIdFromCode($db,$operation,'c_paiement','code','id',1);
-                    $paiement->num_paiement = $num_chq;
-                    $paiement->note         = $label;
-
-                    if (! $error)
-                    {
-	                    // Create payment line for invoice
-                    	$paiement_id = $paiement->create($user);
-                        if (! $paiement_id > 0)
-                        {
-                            $errmsg=$paiement->error;
-                            $errmsgs=$paiement->errors;
-        					setEventMessages($errmsg, $errmsgs, 'errors');
-                            $error++;
-                        }
-                    }
-
-                    if (! $error)
-                    {
-                    	// Add transaction into bank account
-                        $bank_line_id=$paiement->addPaymentToBank($user,'payment','(SubscriptionPayment)',$accountid,$emetteur_nom,$emetteur_banque);
-                        if (! ($bank_line_id > 0))
-                        {
-                            $errmsg=$paiement->error;
-                            $errmsgs=$paiement->errors;
-	                        setEventMessages($paiement->error, $paiement->errors, 'errors');
-                            $error++;
-                        }
-                    }
-
-                    if (! $error)
-                    {
-                        // Update fk_bank into subscription table
-                        $sql = 'UPDATE '.MAIN_DB_PREFIX.'subscription SET fk_bank='.$bank_line_id;
-                        $sql.= ' WHERE rowid='.$crowid;
-
-	                    $result = $db->query($sql);
-                        if (! $result)
-                        {
-                            $error++;
-                        }
-                    }
-
-                    if (! $error)
-                    {
-                        // Set invoice as paid
-                    	$invoice->set_paid($user);
-                    }
-
-                    if (! $error)
-                    {
-						// Define output language
-						$outputlangs = $langs;
-						$newlang = '';
-						if ($conf->global->MAIN_MULTILANGS && empty($newlang) && ! empty($_REQUEST['lang_id']))
-							$newlang = $_REQUEST['lang_id'];
-						if ($conf->global->MAIN_MULTILANGS && empty($newlang))
-							$newlang = $customer->default_lang;
-						if (! empty($newlang)) {
-							$outputlangs = new Translate("", $conf);
-							$outputlangs->setDefaultLang($newlang);
-						}
-                    	// Generate PDF (whatever is option MAIN_DISABLE_PDF_AUTOUPDATE) so we can include it into email
-						//if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE))
-
-	                    $invoice->generateDocument($invoice->modelpdf, $outputlangs, $hidedetails, $hidedesc, $hideref);
-                    }
-                }
-            }
+        	$result = $object->subscriptionComplementaryActions($crowid, $option, $accountid, $datesubscription, $paymentdate, $operation, $label, $amount, $num_chq, $emetteur_nom, $emetteur_banque);
+			if ($result < 0)
+			{
+				$error++;
+				setEventMessages($object->error, $object->errors, 'errors');
+			}
         }
 
         if (! $error)
@@ -557,7 +338,7 @@ if ($user->rights->adherent->cotisation->creer && $action == 'subscription' && !
         if (! $error)
         {
             // Send confirmation Email
-            if ($object->email && $_POST["sendmail"])
+            if ($object->email && $sendalsoemail)
             {
                 $subjecttosend=$object->makeSubstitution($conf->global->ADHERENT_MAIL_COTIS_SUBJECT);
                 $texttosend=$object->makeSubstitution($adht->getMailOnSubscription());
@@ -569,7 +350,11 @@ if ($user->rights->adherent->cotisation->creer && $action == 'subscription' && !
         			setEventMessages($errmsg, null, 'errors');
                 }
             }
+        }
 
+        // Clean some POST vars
+        if (! $error)
+        {
             $_POST["subscription"]='';
             $_POST["accountid"]='';
             $_POST["operation"]='';
@@ -933,7 +718,7 @@ if ($rowid > 0)
 
         print load_fiche_titre($langs->trans("NewCotisation"));
 
-        // Define default choice to select
+        // Define default choice for complementary actions
         $bankdirect=0;        // 1 means option by default is write to bank direct with no invoice
         $invoiceonly=0;		  // 1 means option by default is invoice only
         $bankviainvoice=0;    // 1 means option by default is write to bank via invoice
@@ -944,11 +729,11 @@ if ($rowid > 0)
         	if (GETPOST('paymentsave') == 'bankviainvoice') $bankviainvoice=1;
         }
         else
-       {
+        {
         	if (! empty($conf->global->ADHERENT_BANK_USE) && $conf->global->ADHERENT_BANK_USE == 'bankviainvoice' && ! empty($conf->banque->enabled) && ! empty($conf->societe->enabled) && ! empty($conf->facture->enabled)) $bankviainvoice=1;
-       		else if (! empty($conf->global->ADHERENT_BANK_USE) && $conf->global->ADHERENT_BANK_USE == 'bankdirect' && ! empty($conf->banque->enabled)) $bankdirect=1;
+        	else if (! empty($conf->global->ADHERENT_BANK_USE) && $conf->global->ADHERENT_BANK_USE == 'bankdirect' && ! empty($conf->banque->enabled)) $bankdirect=1;
         	else if (! empty($conf->global->ADHERENT_BANK_USE) && $conf->global->ADHERENT_BANK_USE == 'invoiceonly' && ! empty($conf->banque->enabled) && ! empty($conf->societe->enabled) && ! empty($conf->facture->enabled)) $invoiceonly=1;
-       }
+        }
 
         print "\n\n<!-- Form add subscription -->\n";
 
@@ -1047,15 +832,11 @@ if ($rowid > 0)
         }
         if (! $datefrom)
         {
-            if ($object->datefin > 0)
+        	$datefrom=$object->datevalid;
+        	if ($object->datefin > 0)
             {
                 $datefrom=dol_time_plus_duree($object->datefin,1,'d');
             }
-            else
-			{
-                //$datefrom=dol_now();
-				$datefrom=$object->datevalid;
-            }
         }
         print $form->select_date($datefrom,'','','','',"subscription",1,1,1);
         print "</td></tr>";
@@ -1207,7 +988,7 @@ if ($rowid > 0)
             $subjecttosend=$object->makeSubstitution($conf->global->ADHERENT_MAIL_COTIS_SUBJECT);
             $texttosend=$object->makeSubstitution($adht->getMailOnSubscription());
 
-            $tmp='<input name="sendmail" type="checkbox"'.(GETPOST('sendmail')?GETPOST('sendmail'):(! empty($conf->global->ADHERENT_DEFAULT_SENDINFOBYMAIL)?' checked':'')).'>';
+            $tmp='<input name="sendmail" type="checkbox"'.(GETPOST('sendmail','alpha')?' checked':(! empty($conf->global->ADHERENT_DEFAULT_SENDINFOBYMAIL)?' checked':'')).'>';
             $helpcontent='';
             $helpcontent.='<b>'.$langs->trans("MailFrom").'</b>: '.$conf->global->ADHERENT_MAIL_FROM.'<br>'."\n";
             $helpcontent.='<b>'.$langs->trans("MailRecipient").'</b>: '.$object->email.'<br>'."\n";

+ 2 - 0
htdocs/admin/agenda_extsites.php

@@ -48,9 +48,11 @@ $MAXAGENDA=$conf->global->AGENDA_EXT_NB;
 // List of aviable colors
 $colorlist=array('BECEDD','DDBECE','BFDDBE','F598B4','F68654','CBF654','A4A4A5');
 
+
 /*
  * Actions
  */
+
 if ($actionsave)
 {
     $db->begin();

+ 18 - 7
htdocs/admin/company.php

@@ -313,10 +313,9 @@ if ($action == 'edit' || $action == 'updateedit')
 	print '<form enctype="multipart/form-data" method="POST" action="'.$_SERVER["PHP_SELF"].'" name="form_index">';
 	print '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
 	print '<input type="hidden" name="action" value="update">';
-	$var=true;
 
 	print '<table class="noborder" width="100%">';
-	print '<tr class="liste_titre"><th class="titlefield">'.$langs->trans("CompanyInfo").'</th><th>'.$langs->trans("Value").'</th></tr>'."\n";
+	print '<tr class="liste_titre"><th class="titlefield wordbreak">'.$langs->trans("CompanyInfo").'</th><th>'.$langs->trans("Value").'</th></tr>'."\n";
 
 	// Name
 
@@ -411,7 +410,6 @@ if ($action == 'edit' || $action == 'updateedit')
 	// IDs of the company (country-specific)
 	print '<table class="noborder" width="100%">';
 	print '<tr class="liste_titre"><td>'.$langs->trans("CompanyIds").'</td><td>'.$langs->trans("Value").'</td></tr>';
-	$var=true;
 
 	$langs->load("companies");
 
@@ -697,11 +695,12 @@ else
 	//print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?action=edit">'.$langs->trans("Modify").'</a>';
 	//print '</div><br>';
 
+	print '<div class="div-table-responsive-no-min">';
 	print '<table class="noborder" width="100%">';
 	print '<tr class="liste_titre"><td>'.$langs->trans("CompanyInfo").'</td><td>'.$langs->trans("Value").'</td></tr>';
 
 
-	print '<tr class="oddeven"><td class="titlefield">'.$langs->trans("CompanyName").'</td><td>';
+	print '<tr class="oddeven"><td class="titlefield wordbreak">'.$langs->trans("CompanyName").'</td><td>';
 	if (! empty($conf->global->MAIN_INFO_SOCIETE_NOM)) print $conf->global->MAIN_INFO_SOCIETE_NOM;
 	else print img_warning().' <font class="error">'.$langs->trans("ErrorFieldRequired",$langs->transnoentitiesnoconv("CompanyName")).'</font>';
 	print '</td></tr>';
@@ -791,7 +790,7 @@ else
 	print '<tr class="oddeven"><td class="tdtop">'.$langs->trans("Note").'</td><td>' . (! empty($conf->global->MAIN_INFO_SOCIETE_NOTE) ? nl2br($conf->global->MAIN_INFO_SOCIETE_NOTE) : '') . '</td></tr>';
 
 	print '</table>';
-
+	print "</div>";
 
 	print '<br>';
 
@@ -799,8 +798,10 @@ else
 	// IDs of the company (country-specific)
 	print '<form name="formsoc" method="post">';
 	print '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
+
+	print '<div class="div-table-responsive-no-min">';
 	print '<table class="noborder" width="100%">';
-	print '<tr class="liste_titre"><td class="titlefield">'.$langs->trans("CompanyIds").'</td><td>'.$langs->trans("Value").'</td></tr>';
+	print '<tr class="liste_titre"><td class="titlefield wordbreak">'.$langs->trans("CompanyIds").'</td><td>'.$langs->trans("Value").'</td></tr>';
 
 	// Managing Director(s)
 
@@ -956,12 +957,16 @@ else
 	print '<tr class="oddeven"><td class="tdtop">'.$langs->trans("CompanyObject").'</td><td>' . (! empty($conf->global->MAIN_INFO_SOCIETE_OBJECT) ? nl2br($conf->global->MAIN_INFO_SOCIETE_OBJECT) : '') . '</td></tr>';
 
 	print '</table>';
+	print "</div>";
+
 	print '</form>';
 
 	/*
 	 *  fiscal year beginning
 	 */
 	print '<br>';
+
+	print '<div class="div-table-responsive-no-min">';
 	print '<table class="noborder" width="100%">';
 	print '<tr class="liste_titre">';
 	print '<td class="titlefield">'.$langs->trans("FiscalYearInformation").'</td><td>'.$langs->trans("Value").'</td>';
@@ -973,11 +978,13 @@ else
 	print dol_print_date(dol_mktime(12,0,0,$monthstart,1,2000,1),'%B','gm') . '</td></tr>';
 
 	print "</table>";
+	print "</div>";
 
 	/*
 	 *  tax options
 	 */
 	print '<br>';
+	print '<div class="div-table-responsive-no-min">';
 	print '<table class="noborder" width="100%">';
 	print '<tr class="liste_titre">';
 	print '<td class="titlefield">'.$langs->trans("VATManagement").'</td><td>'.$langs->trans("Description").'</td>';
@@ -1005,7 +1012,7 @@ else
 	print "</td></tr>\n";
 
 	print "</table>";
-
+	print "</div>";
 
 	/*
 	 *  Local Taxes
@@ -1014,6 +1021,7 @@ else
 	{
 		// Local Tax 1
 		print '<br>';
+		print '<div class="div-table-responsive-no-min">';
 		print '<table class="noborder" width="100%">';
 		print '<tr class="liste_titre">';
 		print '<td class="titlefield">'.$langs->transcountry("LocalTax1Management",$mysoc->country_code).'</td><td>'.$langs->trans("Description").'</td>';
@@ -1061,11 +1069,13 @@ else
 		print "</td></tr>\n";
 
 		print "</table>";
+		print "</div>";
 	}
 	if ($mysoc->useLocalTax(2))    // True if we found at least on vat with a setup adding a localtax 1
 	{
 		// Local Tax 2
 		print '<br>';
+		print '<div class="div-table-responsive-no-min">';
 		print '<table class="noborder" width="100%">';
 		print '<tr class="liste_titre">';
 		print '<td class="titlefield">'.$langs->transcountry("LocalTax2Management",$mysoc->country_code).'</td><td>'.$langs->trans("Description").'</td>';
@@ -1113,6 +1123,7 @@ else
 		print "</td></tr>\n";
 
 		print "</table>";
+		print "</div>";
 	}
 
 

+ 0 - 17
htdocs/admin/pdf.php

@@ -611,18 +611,6 @@ else	// Show
 	print '<td>'.$langs->trans("Value").'</td>'."\n";
 	print "</tr>\n";
 
-	if (! empty($dolibarr_pdf_force_fpdf))
-	{
-
-		print '<tr class="oddeven">'."\n";
-		print '<td>dolibarr_pdf_force_fpdf</td>'."\n";
-		print '<td>';
-		print $dolibarr_pdf_force_fpdf;
-		print '</td>';
-		print '</tr>';
-	}
-
-
 	print '<tr class="oddeven">'."\n";
 	print '<td>'.$langs->trans("LibraryToBuildPDF").'</td>'."\n";
 	print '<td>';
@@ -663,11 +651,6 @@ else	// Show
 	print "</table>\n";
 	print '</div>';
 
-	if (! empty($dolibarr_pdf_force_fpdf))
-	{
-		print info_admin($langs->trans("WarningUsingFPDF")).'<br>';
-	}
-
     print '<div class="tabsAction">';
     print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?action=edit">'.$langs->trans("Modify").'</a>';
     print '</div>';

+ 24 - 10
htdocs/admin/system/dbtable.php

@@ -75,7 +75,7 @@ else
 		}
 	}
 
-	if ($base == 1)
+	if ($base == 1)	// mysql
 	{
 		$link=array();
 		$cons = explode(";", $row[14]);
@@ -97,11 +97,19 @@ else
 
 		//  var_dump($link);
 
-		print '<table>';
-		print '<tr class="liste_titre"><td>'.$langs->trans("Fields").'</td><td>'.$langs->trans("Type").'</td><td>'.$langs->trans("Index").'</td>';
-		print '<td>'.$langs->trans("FieldsLinked").'</td></tr>';
-
-		$sql = "DESCRIBE ".$table;
+		print '<table class="noborder">';
+		print '<tr class="liste_titre">';
+		print '<td>'.$langs->trans("Fields").'</td><td>'.$langs->trans("Type").'</td><td>'.$langs->trans("Index").'</td>';
+		print '<td></td>';
+		print '<td></td>';
+		print '<td></td>';
+		print '<td></td>';
+		print '<td>'.$langs->trans("FieldsLinked").'</td>';
+		print '</tr>';
+
+		//$sql = "DESCRIBE ".$table;
+		$sql = "SHOW FULL COLUMNS IN ".$db->escape($table);
+		
 		$resql = $db->query($sql);
 		if ($resql)
 		{
@@ -111,12 +119,18 @@ else
 			{
 				$row = $db->fetch_row($resql);
 				print '<tr class="oddeven">';
-				print "<td>$row[0]</td>";
-				print "<td>$row[1]</td>";
-				print "<td>$row[3]</td>";
+				print "<td>".$row[0]."</td>";
+				print "<td>".$row[1]."</td>";
+				print "<td>".$row[3]."</td>";
+				print "<td>".(empty($row[4])?'':$row[4])."</td>";
+				print "<td>".(empty($row[5])?'':$row[5])."</td>";
+				print "<td>".(empty($row[6])?'':$row[6])."</td>";
+				print "<td>".(empty($row[7])?'':$row[7])."</td>";
+
 				print "<td>".(isset($link[$row[0]][0])?$link[$row[0]][0]:'').".";
 				print (isset($link[$row[0]][1])?$link[$row[0]][1]:'')."</td>";
-
+				
+				print '<!-- ALTER ALTER TABLE '.$table.' MODIFY '.$row[0].' '.$row[1].' COLLATE utf8_unicode_ci; -->';
 				print '</tr>';
 				$i++;
 			}

+ 7 - 6
htdocs/admin/system/dolibarr.php

@@ -116,7 +116,7 @@ if (function_exists('curl_init'))
     }
     else
     {
-        print $langs->trans("LastStableVersion").' : <a href="'.$_SERVER["PHP_SELF"].'?action=getlastversion" class="button">' .$langs->trans("Check").'</a>';
+        print $langs->trans("LastStableVersion").' : <a href="'.$_SERVER["PHP_SELF"].'?action=getlastversion" class="butAction">' .$langs->trans("Check").'</a>';
     }
 }
 
@@ -325,13 +325,14 @@ $configfileparameters=array(
 		'?dolibarr_font_DOL_DEFAULT_TTF_BOLD' => 'dolibarr_font_DOL_DEFAULT_TTF_BOLD',
 		'separator4' => '',
 		'dolibarr_main_prod' => 'Production mode (Hide all error messages)',
+		'dolibarr_main_restrict_os_commands' => 'Restrict CLI commands for backups',
+		'dolibarr_main_restrict_ip' => 'Restrict access to some IPs only',
 		'?dolibarr_mailing_limit_sendbyweb' => 'Limit nb of email sent by page',
 		'?dolibarr_mailing_limit_sendbycli' => 'Limit nb of email sent by cli',
-        '?dolibarr_strict_mode' => 'Strict mode is on/off',
-		'?dolibarr_pdf_force_fpdf' => 'Force fpdf usage to generate PDF'
+		'?dolibarr_strict_mode' => 'Strict mode is on/off',
+		'?dolibarr_nocsrfcheck' => 'Disable CSRF security checks'
 );
 
-$var=true;
 print '<div class="div-table-responsive-no-min">';
 print '<table class="noborder" width="100%">';
 print '<tr class="liste_titre">';
@@ -441,8 +442,8 @@ if ($resql)
 		$obj = $db->fetch_object($resql);
 
 		print '<tr class="oddeven">';
-		print '<td class="tdoverflow">'.$obj->name.'</td>'."\n";
-		print '<td class="tdoverflow">'.$obj->value.'</td>'."\n";
+		print '<td class="tdoverflowmax300">'.$obj->name.'</td>'."\n";
+		print '<td class="tdoverflowmax300">'.dol_escape_htmltag($obj->value).'</td>'."\n";
 		if (empty($conf->multicompany->enabled) || !$user->entity) print '<td align="center" width="80px">'.$obj->entity.'</td>'."\n";	// If superadmin or multicompany disabled
 		print "</tr>\n";
 

+ 1 - 0
htdocs/admin/taxes.php

@@ -32,6 +32,7 @@ if (! empty($conf->accounting->enabled)) require_once DOL_DOCUMENT_ROOT . '/core
 $langs->load('admin');
 $langs->load('objects');
 $langs->load("companies");
+$langs->load("products");
 
 if (!$user->admin) accessforbidden();
 

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

@@ -474,7 +474,7 @@ if (is_array($blocks))
 		   	print '<td class="nowrap">'.$block->ref_object.'</td>';
 
 		   	// Link to source object
-		   	print '<td>'.$object_link.'</td>';
+		   	print '<td><!-- object_link -->'.$object_link.'</td>';
 
 		   	// Amount
 		   	print '<td align="right">'.price($block->amounts).'</td>';
@@ -501,7 +501,7 @@ if (is_array($blocks))
 
 		   	print '</td>';
 
-		   	// Status note
+		   	// Note
 		   	print '<td class="center">';
 		   	if (! $checkresult[$block->id] || ($loweridinerror && $block->id >= $loweridinerror))	// If error
 		   	{

+ 1 - 1
htdocs/blockedlog/ajax/block-info.php

@@ -87,7 +87,7 @@ function formatObject($objtoshow, $prefix)
 			{
 				$s.='<tr><td>'.($prefix?$prefix.' > ':'').$key.'</td>';
 				$s.='<td>';
-				if (in_array($key, array('date','datef')))
+				if (in_array($key, array('date','datef','dateh','datec','datem','datep')))
 				{
 					$s.=dol_print_date($val, 'dayhour');
 				}

+ 49 - 8
htdocs/blockedlog/class/blockedlog.class.php

@@ -239,6 +239,17 @@ class BlockedLog
 				$this->error++;
 			}
 		}
+		else if($this->element === 'subscription') {
+			require_once DOL_DOCUMENT_ROOT.'/adherents/class/subscription.class.php';
+
+			$object = new Subscription($this->db);
+			if ($object->fetch($this->fk_object)>0) {
+				return $object->getNomUrl(1);
+			}
+			else{
+				$this->error++;
+			}
+		}
 		else if ($this->action == 'MODULE_SET')
 		{
 			return '<i class="opacitymedium">System to track events into unalterable logs were enabled</i>';
@@ -313,6 +324,10 @@ class BlockedLog
 		{
 			$this->date_object = $object->datepaid?$object->datepaid:$object->datep;
 		}
+		elseif ($object->element=='subscription')
+		{
+			$this->date_object = $object->dateh;
+		}
 		else {
 			$this->date_object = $object->date;
 		}
@@ -323,7 +338,10 @@ class BlockedLog
 		// id of object
 		$this->fk_object = $object->id;
 
+
+		// Set object_data
 		$this->object_data=new stdClass();
+		$arrayoffieldstoexclude = array('table_element','fields','ref_previous','ref_next','origin','origin_id','oldcopy','picto','error','modelpdf','table_element_line','linkedObjectsIds','linkedObjects','fk_delivery_address');
 
 		// Add thirdparty info
 		if (empty($object->thirdparty) && method_exists($object, 'fetch_thirdparty')) $object->fetch_thirdparty();
@@ -333,7 +351,7 @@ class BlockedLog
 
 			foreach($object->thirdparty as $key=>$value)
 			{
-				if (in_array($key, array('fields'))) continue;	// Discard some properties
+				if (in_array($key, $arrayoffieldstoexclude)) continue;	// Discard some properties
 				if (! in_array($key, array(
 				'name','name_alias','ref_ext','address','zip','town','state_code','country_code','idprof1','idprof2','idprof3','idprof4','idprof5','idprof6','phone','fax','email','barcode',
 				'tva_intra', 'localtax1_assuj', 'localtax1_value', 'localtax2_assuj', 'localtax2_value', 'managers', 'capital', 'typent_code', 'forme_juridique_code', 'code_client', 'code_fournisseur'
@@ -349,7 +367,7 @@ class BlockedLog
 
 			foreach($mysoc as $key=>$value)
 			{
-				if (in_array($key, array('fields'))) continue;	// Discard some properties
+				if (in_array($key, $arrayoffieldstoexclude)) continue;	// Discard some properties
 				if (! in_array($key, array(
 				'name','name_alias','ref_ext','address','zip','town','state_code','country_code','idprof1','idprof2','idprof3','idprof4','idprof5','idprof6','phone','fax','email','barcode',
 				'tva_intra', 'localtax1_assuj', 'localtax1_value', 'localtax2_assuj', 'localtax2_value', 'managers', 'capital', 'typent_code', 'forme_juridique_code', 'code_client', 'code_fournisseur'
@@ -366,12 +384,11 @@ class BlockedLog
 		}
 
 		// Field specific to object
-
 		if ($this->element == 'facture')
 		{
 			foreach($object as $key=>$value)
 			{
-				if (in_array($key, array('fields'))) continue;	// Discard some properties
+				if (in_array($key, $arrayoffieldstoexclude)) continue;	// Discard some properties
 				if (! in_array($key, array(
 				'ref','facnumber','ref_client','ref_supplier','date','datef','type','total_ht','total_tva','total_ttc','localtax1','localtax2','revenuestamp','datepointoftax','note_public','lines'
 				))) continue;									// Discard if not into a dedicated list
@@ -402,7 +419,7 @@ class BlockedLog
 		{
 			foreach($object as $key=>$value)
 			{
-				if (in_array($key, array('fields'))) continue;	// Discard some properties
+				if (in_array($key, $arrayoffieldstoexclude)) continue;	// Discard some properties
 				if (! in_array($key, array(
 				'ref','facnumber','ref_client','ref_supplier','date','datef','type','total_ht','total_tva','total_ttc','localtax1','localtax2','revenuestamp','datepointoftax','note_public'
 				))) continue;									// Discard if not into a dedicated list
@@ -498,7 +515,7 @@ class BlockedLog
 					$paymentpart->thirdparty = new stdClass();
 					foreach($tmpobject->thirdparty as $key=>$value)
 					{
-						if (in_array($key, array('fields'))) continue;	// Discard some properties
+						if (in_array($key, $arrayoffieldstoexclude)) continue;	// Discard some properties
 						if (! in_array($key, array(
 						'name','name_alias','ref_ext','address','zip','town','state_code','country_code','idprof1','idprof2','idprof3','idprof4','idprof5','idprof6','phone','fax','email','barcode',
 						'tva_intra', 'localtax1_assuj', 'localtax1_value', 'localtax2_assuj', 'localtax2_value', 'managers', 'capital', 'typent_code', 'forme_juridique_code', 'code_client', 'code_fournisseur'
@@ -515,7 +532,7 @@ class BlockedLog
 				{
 					foreach($tmpobject as $key=>$value)
 					{
-						if (in_array($key, array('fields'))) continue;	// Discard some properties
+						if (in_array($key, $arrayoffieldstoexclude)) continue;	// Discard some properties
 						if (! in_array($key, array(
 						'ref','facnumber','ref_client','ref_supplier','date','datef','type','total_ht','total_tva','total_ttc','localtax1','localtax2','revenuestamp','datepointoftax','note_public'
 						))) continue;									// Discard if not into a dedicated list
@@ -542,6 +559,29 @@ class BlockedLog
 
 			if (! empty($object->newref)) $this->object_data->ref = $object->newref;
 		}
+		elseif($this->element == 'subscription')
+		{
+			foreach($object as $key=>$value)
+			{
+				if (in_array($key, $arrayoffieldstoexclude)) continue;	// Discard some properties
+				if (! in_array($key, array(
+					'id','datec','dateh','datef','fk_adherent','amount','import_key','statut','note'
+				))) continue;									// Discard if not into a dedicated list
+				if (!is_object($value)) $this->object_data->{$key} = $value;
+			}
+
+			if (! empty($object->newref)) $this->object_data->ref = $object->newref;
+		}
+		else 	// Generic case
+		{
+			foreach($object as $key=>$value)
+			{
+				if (in_array($key, $arrayoffieldstoexclude)) continue;	// Discard some properties
+				if (!is_object($value)) $this->object_data->{$key} = $value;
+			}
+
+			if (! empty($object->newref)) $this->object_data->ref = $object->newref;
+		}
 
 		return 1;
 	}
@@ -667,11 +707,12 @@ class BlockedLog
 			return -2;
 		}
 
-		if (empty($this->action) || empty($this->fk_user) || empty($this->user_fullname)) {
+		if (empty($this->action)) {
 			$this->error=$langs->trans("BadParameterWhenCallingCreateOfBlockedLog");
 			dol_syslog($this->error, LOG_WARNING);
 			return -3;
 		}
+		if (empty($this->fk_user)) $this->user_fullname='(Anonymous)';
 
 		$this->date_creation = dol_now();
 

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

@@ -1044,7 +1044,7 @@ if ($id > 0)
 		}
 
 		// Title
-		print '<tr><td'.(empty($conf->global->AGENDA_USE_EVENT_TYPE)?' class="fieldrequired"':'').'>'.$langs->trans("Title").'</td><td colspan="3"><input type="text" name="label" class="soixantepercent" value="'.$object->label.'"></td></tr>';
+		print '<tr><td class="fieldrequired">'.$langs->trans("Title").'</td><td colspan="3"><input type="text" name="label" class="soixantepercent" value="'.$object->label.'"></td></tr>';
 
         // Full day event
         print '<tr><td>'.$langs->trans("EventOnFullDay").'</td><td colspan="3"><input type="checkbox" id="fullday" name="fullday" '.($object->fulldayevent?' checked':'').'></td></tr>';

+ 12 - 5
htdocs/comm/action/class/actioncomm.class.php

@@ -212,7 +212,7 @@ class ActionComm extends CommonObject
         $now=dol_now();
 
         // Check parameters
-        if (empty($this->userownerid))
+        if (! isset($this->userownerid) || $this->userownerid === '')	// $this->userownerid may be 0 (anonymous event) of > 0
         {
             dol_syslog("You tried to create an event but mandatory property ownerid was not defined", LOG_WARNING);
         	$this->errors[]='ErrorPropertyUserowneridNotDefined';
@@ -1236,8 +1236,12 @@ class ActionComm extends CommonObject
 
 		$result='';
 
-		// Set label of typ
-		$labeltype = ($langs->transnoentities("Action".$this->type_code) != "Action".$this->type_code)?$langs->transnoentities("Action".$this->type_code):$this->type_label;
+		// Set label of type
+		$labeltype = '';
+		if ($this->type_code)
+		{
+			$labeltype = ($langs->transnoentities("Action".$this->type_code) != "Action".$this->type_code)?$langs->transnoentities("Action".$this->type_code):$this->type_label;
+		}
 		if (empty($conf->global->AGENDA_USE_EVENT_TYPE))
 		{
 		    if ($this->type_code != 'AC_OTH_AUTO') $labeltype = $langs->trans('ActionAC_MANUAL');
@@ -1289,7 +1293,7 @@ class ActionComm extends CommonObject
 		$linkstart.=$linkclose.'>';
 		$linkend='</a>';
 
-		//print 'rrr'.$this->libelle.'-'.$withpicto;
+		//print 'rrr'.$this->libelle.'rrr'.$this->label.'rrr'.$withpicto;
 
         if ($withpicto == 2)
         {
@@ -1309,7 +1313,10 @@ class ActionComm extends CommonObject
         {
             if (! empty($conf->global->AGENDA_USE_EVENT_TYPE))	// Add code into ()
             {
-                $libelle.=(($this->type_code && $libelle!=$langs->transnoentities("Action".$this->type_code) && $langs->transnoentities("Action".$this->type_code)!="Action".$this->type_code)?' ('.$langs->transnoentities("Action".$this->type_code).')':'');
+            	if ($labeltype)
+            	{
+                	$libelle.=(preg_match('/'.preg_quote($labeltype,'/').'/', $libelle)?'':' ('.$langs->transnoentities("Action".$this->type_code).')');
+            	}
             }
         }
 

+ 104 - 35
htdocs/comm/action/index.php

@@ -589,6 +589,7 @@ if ($resql)
         $event->type_color=$obj->type_color;
 
         $event->libelle=$obj->label;
+        $event->label=$obj->label;
         $event->percentage=$obj->percent;
         $event->authorid=$obj->fk_user_author;		// user id of creator
         $event->userownerid=$obj->fk_user_action;	// user id of owner
@@ -601,7 +602,9 @@ if ($resql)
         $event->elementtype=$obj->elementtype;
 
         $event->societe->id=$obj->fk_soc;
+        $event->thirdparty_id=$obj->fk_soc;
         $event->contact->id=$obj->fk_contact;
+        $event->contact_id=$obj->fk_contact;
 
         // Defined date_start_in_calendar and date_end_in_calendar property
         // They are date start and end of action but modified to not be outside calendar view.
@@ -1176,19 +1179,72 @@ else    // View by day
     $timestamp=dol_mktime(12,0,0,$month,$day,$year);
     $arraytimestamp=dol_getdate($timestamp);
 
-    print '<div class="div-table-responsive-no-min">';		// You can use div-table-responsive-no-min if you dont need reserved height for your table
-    echo '<table width="100%" class="noborder nocellnopadd cal_pannel cal_month">';
-    echo ' <tr class="liste_titre">';
-    echo '  <td align="center">'.$langs->trans("Day".$arraytimestamp['wday'])."</td>\n";
-    echo " </tr>\n";
-    echo " <tr>\n";
-    echo '  <td class="'.$style.'" width="14%" valign="top">';
-    $maxnbofchar=80;
-    show_day_events($db, $day, $month, $year, $month, $style, $eventarray, 0, $maxnbofchar, $newparam, 1, 300);
-    echo "</td>\n";
-    echo " </tr>\n";
+    //echo '<table class="tagtable centpercent noborder nocellnopadd cal_pannel cal_month">';
+    echo '<table class="tagtable centpercent noborder nocellnopadd cal_pannel cal_month noborderbottom" style="margin-bottom: 5px !important;">';
+
+    echo ' <tr class="tagtr liste_titre">';
+    echo '  <td class="tagtd width100"></td>';
+    echo '  <td class="tagtd center">'.$langs->trans("Day".$arraytimestamp['wday'])."</td>\n";
+    echo " </td>\n";
+
+    /*
+    echo ' <div class="tagtr">';
+    echo '  <div class="tagtd width100"></div>';
+    echo '  <div class="tagtd center">';
+    echo show_day_events($db, $day, $month, $year, $month, $style, $eventarray, 0, $maxnbofchar, $newparam, 1, 300, -1);
+    echo '  </div>'."\n";
+    echo " </div>\n";
+	*/
+
     echo '</table>';
-    print '</div>';
+
+    /* WIP View per hour */
+    $useviewhour = 0;
+    if ($useviewhour)
+    {
+    	print '<div class="div-table-responsive-no-min borderbottom">';		// You can use div-table-responsive-no-min if you dont need reserved height for your table
+
+    	$maxheightwin=(isset($_SESSION["dol_screenheight"]) && $_SESSION["dol_screenheight"] > 500)?($_SESSION["dol_screenheight"]-200):660;	// Also into index.php file
+
+	    echo '<div style="max-height: '.$maxheightwin.'px;">';
+		echo '<div class="tagtable centpercent calendarviewcontainer">';
+
+	    $maxnbofchar=80;
+
+	    $tmp = explode('-', $conf->global->MAIN_DEFAULT_WORKING_HOURS);
+	    $minhour = round($tmp[0],0);
+	    $maxhour = round($tmp[1],0);
+	    if ($minhour > 23) $minhour = 23;
+	    if ($maxhour < 1)  $maxhour = 1;
+	    if ($maxhour <= $minhour) { $maxhour = $minhour + 1; }
+
+	    $i = 0;
+	    $j = 0;
+		while ($i < 24)
+		{
+		    echo ' <div class="tagtr calendarviewcontainertr">'."\n";
+		    echo '  <div class="tagtd width100 tdtop">'.dol_print_date($i*3600, 'hour', 'gmt').'</div>';
+		    echo '  <div class="tagtd '.$style.' tdtop">';
+		    echo "  </div>\n";
+		    echo " </div>\n";
+		    $i++;
+		    $j++;
+		}
+
+		echo '</div></div>';
+
+		show_day_events($db, $day, $month, $year, $month, $style, $eventarray, 0, $maxnbofchar, $newparam, 1, 300, 1);
+
+		print '</div>';
+    }
+    else
+    {
+    	print '<div class="div-table-responsive-no-min">';		// You can use div-table-responsive-no-min if you dont need reserved height for your table
+
+    	show_day_events($db, $day, $month, $year, $month, $style, $eventarray, 0, $maxnbofchar, $newparam, 1, 300, 0);
+
+    	print '</div>';
+    }
 }
 
 print "\n".'</form>';
@@ -1213,9 +1269,10 @@ $db->close();
  * @param   string	$newparam        Parameters on current URL
  * @param   int		$showinfo        Add extended information (used by day and week view)
  * @param   int		$minheight       Minimum height for each event. 60px by default.
+ * @param	string	$nonew			 0=Add "new entry button", 1=No "new entry button", -1=Only "new entry button"
  * @return	void
  */
-function show_day_events($db, $day, $month, $year, $monthshown, $style, &$eventarray, $maxprint=0, $maxnbofchar=16, $newparam='', $showinfo=0, $minheight=60)
+function show_day_events($db, $day, $month, $year, $monthshown, $style, &$eventarray, $maxprint=0, $maxnbofchar=16, $newparam='', $showinfo=0, $minheight=60, $nonew=0)
 {
     global $user, $conf, $langs;
     global $action, $filter, $filtert, $status, $actioncode;	// Filters used into search form
@@ -1230,26 +1287,35 @@ function show_day_events($db, $day, $month, $year, $monthshown, $style, &$eventa
     $curtime = dol_mktime(0, 0, 0, $month, $day, $year);
     print '<div id="dayevent_'.$dateint.'" class="dayevent tagtable centpercent nobordernopadding">'."\n";
 
-    print '<div class="tagtr"><div class="nowrap float">';
-    print '<a style="color: #666" href="'.DOL_URL_ROOT.'/comm/action/index.php?';
-    print 'action=show_day&day='.str_pad($day, 2, "0", STR_PAD_LEFT).'&month='.str_pad($month, 2, "0", STR_PAD_LEFT).'&year='.$year;
-    print $newparam;
-    print '">';
-    if ($showinfo) print dol_print_date($curtime,'daytextshort');
-    else print dol_print_date($curtime,'%d');
-    print '</a>';
-    print '</div><div class="floatright nowrap">';
-    if ($user->rights->agenda->myactions->create || $user->rights->agenda->allactions->create)
+    if ($nonew <= 0)
     {
-    	$newparam.='&month='.str_pad($month, 2, "0", STR_PAD_LEFT).'&year='.$year;
+	    print '<div class="tagtr"><div class="nowrap float">';
+	    print '<a style="color: #666" href="'.DOL_URL_ROOT.'/comm/action/index.php?';
+	    print 'action=show_day&day='.str_pad($day, 2, "0", STR_PAD_LEFT).'&month='.str_pad($month, 2, "0", STR_PAD_LEFT).'&year='.$year;
+	    print $newparam;
+	    print '">';
+	    if ($showinfo) print dol_print_date($curtime,'daytextshort');
+	    else print dol_print_date($curtime,'%d');
+	    print '</a>';
+	    print '</div><div class="floatright nowrap">';
+	    if ($user->rights->agenda->myactions->create || $user->rights->agenda->allactions->create)
+	    {
+	    	$newparam.='&month='.str_pad($month, 2, "0", STR_PAD_LEFT).'&year='.$year;
+
+	        //$param='month='.$monthshown.'&year='.$year;
+	        $hourminsec='100000';
+	        print '<a href="'.DOL_URL_ROOT.'/comm/action/card.php?action=create&datep='.sprintf("%04d%02d%02d",$year,$month,$day).$hourminsec.'&backtopage='.urlencode($_SERVER["PHP_SELF"].($newparam?'?'.$newparam:'')).'">';
+	        print img_picto($langs->trans("NewAction"),'edit_add.png');
+	        print '</a>';
+	    }
+	    print '</div></div>'."\n";
+    }
 
-        //$param='month='.$monthshown.'&year='.$year;
-        $hourminsec='100000';
-        print '<a href="'.DOL_URL_ROOT.'/comm/action/card.php?action=create&datep='.sprintf("%04d%02d%02d",$year,$month,$day).$hourminsec.'&backtopage='.urlencode($_SERVER["PHP_SELF"].($newparam?'?'.$newparam:'')).'">';
-        print img_picto($langs->trans("NewAction"),'edit_add.png');
-        print '</a>';
+    if ($nonew < 0)
+    {
+    	print '</div>';
+    	return;
     }
-    print '</div></div>'."\n";
 
     // Line with td contains all div of each events
     print '<div class="tagtr">';
@@ -1390,6 +1456,7 @@ function show_day_events($db, $day, $month, $year, $monthshown, $style, &$eventa
                     //print ' position: absolute; top: 40px; width: 50%;';
                     //print '"';
                     print '>';
+
                     //var_dump($event->userassigned);
                     //var_dump($event->transparency);
                     print '<table class="centpercent cal_event'.(empty($event->transparency)?' cal_event_notbusy':' cal_event_busy').'" style="'.$h;
@@ -1475,10 +1542,12 @@ function show_day_events($db, $day, $month, $year, $monthshown, $style, &$eventa
                         if ($event->type_code == 'ICALEVENT') print $titletoshow;
                         else
                         {
-                            $savlabel=$event->libelle;
-                            $event->libelle=$titletoshow;
-                            print $event->getNomUrl(0,$maxnbofchar,'cal_event','',0,1);
-                            $event->libelle=$savlabel;
+                        	$savlabel=$event->label?$event->label:$event->libelle;
+                        	$event->label=$titletoshow;
+                        	$event->libelle=$titletoshow;
+                        	print $event->getNomUrl(0,$maxnbofchar,'cal_event','',0,1);
+                        	$event->label=$savlabel;
+                        	$event->libelle=$savlabel;
                         }
 
                         // Loop on each assigned user
@@ -1495,7 +1564,7 @@ function show_day_events($db, $day, $month, $year, $monthshown, $style, &$eventa
                                 $cacheusers[$tmpid]=$newuser;
                             }
 
-                            $listofusertoshow.=$cacheusers[$tmpid]->getNomUrl(-3, '', 0, 0, 0, 0, '', 'valigntextbottom');
+                            $listofusertoshow.=$cacheusers[$tmpid]->getNomUrl(-3, '', 0, 0, 0, 0, '', 'paddingright valigntextbottom');
                         }
                         print $listofusertoshow;
 

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

@@ -430,12 +430,12 @@ if ($resql)
 	if (! empty($arrayfields['c.libelle']['checked']))	print '<td class="liste_titre"></td>';
 	if (! empty($arrayfields['a.label']['checked']))	print '<td class="liste_titre"><input type="text" class="maxwidth75" name="search_title" value="'.$search_title.'"></td>';
 	if (! empty($arrayfields['a.datep']['checked']))	{
-		print '<td class="liste_titre" align="center">';
+		print '<td class="liste_titre nowraponall" align="center">';
 		print $form->select_date($datestart, 'datestart', 0, 0, 1, '', 1, 0, 1);
 		print '</td>';
 	}
 	if (! empty($arrayfields['a.datep2']['checked']))	{
-		print '<td class="liste_titre" align="center">';
+		print '<td class="liste_titre nowraponall" align="center">';
 		print $form->select_date($dateend, 'dateend', 0, 0, 1, '', 1, 0, 1);
 		print '</td>';
 	}
@@ -517,8 +517,8 @@ if ($resql)
 
 		print '<tr class="oddeven">';
 
+		// Ref
 		if (! empty($arrayfields['a.id']['checked'])) {
-			// Ref
 			print '<td>';
 			print $actionstatic->getNomUrl(1,-1);
 			print '</td>';

+ 12 - 10
htdocs/compta/facture/class/facture.class.php

@@ -239,7 +239,7 @@ class Facture extends CommonInvoice
 	 * 	@param	int		$forceduedate	1=Do not recalculate due date from payment condition but force it with value
 	 *	@return	int						<0 if KO, >0 if OK
 	 */
-	function create($user,$notrigger=0,$forceduedate=0)
+	function create(User $user, $notrigger=0, $forceduedate=0)
 	{
 		global $langs,$conf,$mysoc,$hookmanager;
 		$error=0;
@@ -265,13 +265,13 @@ class Facture extends CommonInvoice
 			$this->multicurrency_tx = 1;
 		}
 
-		dol_syslog(get_class($this)."::create user=".$user->id);
+		dol_syslog(get_class($this)."::create user=".$user->id." date=".$this->date);
 
 		// Check parameters
-		if (empty($this->date) || empty($user->id))
+		if (empty($this->date))
 		{
-			$this->error="ErrorBadParameter";
-			dol_syslog(get_class($this)."::create Try to create an invoice with an empty parameter (user, date, ...)", LOG_ERR);
+			$this->error="Try to create an invoice with an empty parameter (date)";
+			dol_syslog(get_class($this)."::create ".$this->error, LOG_ERR);
 			return -3;
 		}
 		$soc = new Societe($this->db);
@@ -2242,7 +2242,7 @@ class Facture extends CommonInvoice
 
 			// Validate
 			$sql = 'UPDATE '.MAIN_DB_PREFIX.'facture';
-			$sql.= " SET facnumber='".$num."', fk_statut = ".self::STATUS_VALIDATED.", fk_user_valid = ".$user->id.", date_valid = '".$this->db->idate($now)."'";
+			$sql.= " SET facnumber='".$num."', fk_statut = ".self::STATUS_VALIDATED.", fk_user_valid = ".($user->id > 0 ? $user->id : "null").", date_valid = '".$this->db->idate($now)."'";
 			if (! empty($conf->global->FAC_FORCE_DATE_VALIDATION))	// If option enabled, we force invoice date
 			{
 				$sql.= ", datef='".$this->db->idate($this->date)."'";
@@ -2365,9 +2365,12 @@ class Facture extends CommonInvoice
     					$final = ($this->lines[$i]->situation_percent == 100);
     					$i++;
     				}
-    				if ($final) {
-    					$this->setFinal($user);
-    				}
+
+    				if (empty($final)) $this->situation_final = 0;
+    				else $this->situation_final = 1;
+
+				$this->setFinal($user);
+
                 }
 			}
 		}
@@ -4070,7 +4073,6 @@ class Facture extends CommonInvoice
 
 		$this->db->begin();
 
-		$this->situation_final = 1;
 		$sql = 'UPDATE ' . MAIN_DB_PREFIX . 'facture SET situation_final = ' . $this->situation_final . ' where rowid = ' . $this->id;
 
 		dol_syslog(__METHOD__, LOG_DEBUG);

+ 1 - 1
htdocs/compta/facture/fiche-rec.php

@@ -1189,7 +1189,7 @@ if ($action == 'create')
 			$disableedit=1;
 			$disablemove=1;
 			$disableremove=1;
-			$ret = $object->printObjectLines('', $mysoc, $object->thirdparty, $lineid, 0);      // No date selector for template invoice
+			$object->printObjectLines('', $mysoc, $object->thirdparty, $lineid, 0);      // No date selector for template invoice
 		}
 
 		print "</table>\n";

+ 4 - 4
htdocs/compta/facture/list.php

@@ -701,19 +701,19 @@ if ($resql)
 	// Date invoice
 	if (! empty($arrayfields['f.date']['checked']))
 	{
-		print '<td class="liste_titre" align="center">';
+		print '<td class="liste_titre nowraponall" align="center">';
 		if (! empty($conf->global->MAIN_LIST_FILTER_ON_DAY)) print '<input class="flat" type="text" size="1" maxlength="2" name="day" value="'.dol_escape_htmltag($day).'">';
 		print '<input class="flat" type="text" size="1" maxlength="2" name="month" value="'.dol_escape_htmltag($month).'">';
-		$formother->select_year($year?$year:-1,'year',1, 20, 5);
+		$formother->select_year($year?$year:-1,'year',1, 20, 5, 0, 0, '', 'width75');
 		print '</td>';
 	}
 	// Date due
 	if (! empty($arrayfields['f.date_lim_reglement']['checked']))
 	{
-		print '<td class="liste_titre" align="center">';
+		print '<td class="liste_titre nowraponall" align="center">';
 		if (! empty($conf->global->MAIN_LIST_FILTER_ON_DAY)) print '<input class="flat" type="text" size="1" maxlength="2" name="day_lim" value="'.dol_escape_htmltag($day_lim).'">';
 		print '<input class="flat" type="text" size="1" maxlength="2" name="month_lim" value="'.dol_escape_htmltag($month_lim).'">';
-		$formother->select_year($year_lim?$year_lim:-1,'year_lim',1, 20, 5);
+		$formother->select_year($year_lim?$year_lim:-1,'year_lim',1, 20, 5, 0, 0, '', 'width75');
 		print '<br><input type="checkbox" name="option" value="late"'.($option == 'late'?' checked':'').'> '.$langs->trans("Late");
 		print '</td>';
 	}

+ 15 - 15
htdocs/compta/localtax/class/localtax.class.php

@@ -132,7 +132,7 @@ class Localtax extends CommonObject
      *	@param		int		$notrigger		0=no, 1=yes (no update trigger)
      *	@return		int						<0 if KO, >0 if OK
      */
-    function update($user=null, $notrigger=0)
+    function update(User $user, $notrigger=0)
     {
     	global $conf, $langs;
 
@@ -149,8 +149,8 @@ class Localtax extends CommonObject
 		$this->db->begin();
 
 		// Update request
-        $sql = "UPDATE ".MAIN_DB_PREFIX."localtax SET";
-        $sql.= " localtaxtype=".$this->ltt.",";
+		$sql = "UPDATE ".MAIN_DB_PREFIX."localtax SET";
+		$sql.= " localtaxtype=".$this->ltt.",";
 		$sql.= " tms='".$this->db->idate($this->tms)."',";
 		$sql.= " datep='".$this->db->idate($this->datep)."',";
 		$sql.= " datev='".$this->db->idate($this->datev)."',";
@@ -160,7 +160,7 @@ class Localtax extends CommonObject
 		$sql.= " fk_bank=".$this->fk_bank.",";
 		$sql.= " fk_user_creat=".$this->fk_user_creat.",";
 		$sql.= " fk_user_modif=".$this->fk_user_modif;
-        $sql.= " WHERE rowid=".$this->id;
+		$sql.= " WHERE rowid=".$this->id;
 
         dol_syslog(get_class($this)."::update", LOG_DEBUG);
         $resql = $this->db->query($sql);
@@ -255,12 +255,12 @@ class Localtax extends CommonObject
     }
 
 
- 	/**
- 	 *	Delete object in database
- 	 *
- 	 *	@param		User	$user		User that delete
- 	 *	@return		int					<0 if KO, >0 if OK
- 	 */
+	/**
+	 *	Delete object in database
+	 *
+	 *	@param		User	$user		User that delete
+	 *	@return		int					<0 if KO, >0 if OK
+	 */
 	function delete($user)
 	{
 		// Call trigger
@@ -285,11 +285,11 @@ class Localtax extends CommonObject
 
 
 	/**
-     *  Initialise an instance with random values.
-     *  Used to build previews or test instances.
-     *	id must be 0 if object instance is a specimen.
-     *
-     *  @return	void
+	 *  Initialise an instance with random values.
+	 *  Used to build previews or test instances.
+	 *	id must be 0 if object instance is a specimen.
+	 *
+	 *  @return	void
 	 */
 	function initAsSpecimen()
 	{

+ 2 - 2
htdocs/compta/paiement.php

@@ -88,11 +88,11 @@ if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'e
 
 if (empty($reshook))
 {
-	if ($action == 'add_paiement' || ($action == 'confirm_paiement' && $confirm=='yes'))
+	if ($action == 'add_paiement' || ($action == 'confirm_paiement' && $confirm == 'yes'))
 	{
 	    $error = 0;
 
-	    $datepaye = dol_mktime(12, 0, 0, GETPOST('remonth'), GETPOST('reday'), GETPOST('reyear'));
+	    $datepaye = dol_mktime(12, 0, 0, GETPOST('remonth','int'), GETPOST('reday','int'), GETPOST('reyear','int'));
 	    $paiement_id = 0;
 	    $totalpayment = 0;
 		$multicurrency_totalpayment = 0;

+ 2 - 1
htdocs/compta/paiement/class/paiement.class.php

@@ -209,9 +209,10 @@ class Paiement extends CommonObject
 			$total = $totalamount_converted; // Maybe use price2num with MT for the converted value
 			$mtotal = $totalamount;
 		}
+		$note = ($this->note_public?$this->note_public:$this->note);
 
 		$sql = "INSERT INTO ".MAIN_DB_PREFIX."paiement (entity, ref, datec, datep, amount, multicurrency_amount, fk_paiement, num_paiement, note, fk_user_creat)";
-		$sql.= " VALUES (".$conf->entity.", '".$this->ref."', '". $this->db->idate($now)."', '".$this->db->idate($this->datepaye)."', '".$total."', '".$mtotal."', ".$this->paiementid.", '".$this->num_paiement."', '".$this->db->escape($this->note)."', ".$user->id.")";
+		$sql.= " VALUES (".$conf->entity.", '".$this->ref."', '". $this->db->idate($now)."', '".$this->db->idate($this->datepaye)."', '".$total."', '".$mtotal."', ".$this->paiementid.", '".$this->num_paiement."', '".$this->db->escape($note)."', ".$user->id.")";
 
 		dol_syslog(get_class($this)."::Create insert paiement", LOG_DEBUG);
 		$resql = $this->db->query($sql);

+ 2 - 2
htdocs/compta/paiement/avalider.php → htdocs/compta/paiement/tovalidate.php

@@ -17,9 +17,9 @@
  */
 
 /**
- * 	\file       htdocs/compta/paiement/avalider.php
+ * 	\file       htdocs/compta/paiement/tovalidate.php
  * 	\ingroup    compta
- * 	\brief      Page liste des paiements a valider des factures clients
+ * 	\brief      Page list payment to validate. Visible in menu when option BILL_ADD_PAYMENT_VALIDATION is on.
  */
 
 require '../../main.inc.php';

+ 1 - 1
htdocs/compta/prelevement/factures.php

@@ -205,7 +205,7 @@ if ($result)
   	print_liste_field_titre("Bill",$_SERVER["PHP_SELF"],"p.ref",'',$param,'',$sortfield,$sortorder);
   	print_liste_field_titre("ThirdParty",$_SERVER["PHP_SELF"],"s.nom",'',$param,'',$sortfield,$sortorder);
   	print_liste_field_titre("AmountInvoice",$_SERVER["PHP_SELF"],"f.total_ttc","",$param,'align="right"',$sortfield,$sortorder);
-  	print_liste_field_titre("AmountRequested",$_SERVER["PHP_SELF"],"pl.amount_requested","",$param,'align="right"',$sortfield,$sortorder);
+  	print_liste_field_titre("AmountRequested",$_SERVER["PHP_SELF"],"pl.amount","",$param,'align="right"',$sortfield,$sortorder);
   	print_liste_field_titre("StatusDebitCredit",$_SERVER["PHP_SELF"],"","",$param,'align="center"',$sortfield,$sortorder);
 	print_liste_field_titre('');
 	print "</tr>\n";

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

@@ -255,7 +255,7 @@ if ($modecompta == 'BOOKKEEPING')
 	$sql.= " WHERE f.numero_compte = aa.account_number";
 	//$sql.= " AND fk_statut in (1,2)";
 	$sql.= " AND ".$predefinedgroupwhere;
-	$sql.= " AND aa.fk_pcg_version = '".$charofaccountstring."'";
+	$sql.= " AND f.entity = ".$conf->entity;
 	if (! empty($date_start) && ! empty($date_end))
 		$sql.= " AND f.doc_date >= '".$db->idate($date_start)."' AND f.doc_date <= '".$db->idate($date_end)."'";
 	$sql.= " GROUP BY pcg_type, pcg_subtype, name, socid";

+ 0 - 1
htdocs/compta/resultat/index.php

@@ -828,7 +828,6 @@ if (! empty($conf->accounting->enabled) && ($modecompta == 'BOOKKEEPING'))
 	if (! empty($date_start) && ! empty($date_end))
 		$sql.= " AND b.doc_date >= '".$db->idate($date_start)."' AND b.doc_date <= '".$db->idate($date_end)."'";
 	$sql.= " GROUP BY b.doc_ref, b.numero_compte, b.subledger_account, b.subledger_label, pcg_type, dm";
-
 	//print $sql;
 
 	dol_syslog("get bookkeeping record");

+ 12 - 12
htdocs/compta/stats/index.php

@@ -142,9 +142,7 @@ else if ($modecompta=="BOOKKEEPING")
 	$calcmode.='<br>('.$langs->trans("SeeReportInInputOutputMode",'<a href="'.$_SERVER["PHP_SELF"].'?year_start='.$year_start.'&modecompta=RECETTES-DEPENSES">','</a>').')';
 	$period=$form->select_date($date_start,'date_start',0,0,0,'',1,0,1).' - '.$form->select_date($date_end,'date_end',0,0,0,'',1,0,1);
 	$periodlink=($year_start?"<a href='".$_SERVER["PHP_SELF"]."?year_start=".($year_start-1)."&modecompta=".$modecompta."'>".img_previous()."</a> <a href='".$_SERVER["PHP_SELF"]."?year_start=".($year_start+1)."&modecompta=".$modecompta."'>".img_next()."</a>":"");
-	$description=$langs->trans("RulesCADue");
-	if (! empty($conf->global->FACTURE_DEPOSITS_ARE_JUST_PAYMENTS)) $description.= $langs->trans("DepositsAreNotIncluded");
-	else  $description.= $langs->trans("DepositsAreIncluded");
+	$description=$langs->trans("RulesCATotalSaleJournal");
 	$builddate=dol_now();
 	//$exportlink=$langs->trans("NotYetAvailable");
 }
@@ -187,15 +185,14 @@ if ($socid) $sql.= " AND f.fk_soc = ".$socid;
 else if ($modecompta=="BOOKKEEPING")
 {
 	$sql  = "SELECT date_format(b.doc_date,'%Y-%m') as dm, sum(b.credit) as amount_ttc";
-	$sql.= " FROM ".MAIN_DB_PREFIX."accounting_bookkeeping as b";
-	$sql.= " WHERE b.numero_compte IN (SELECT a.account_number" ;
-	$sql.= " FROM ".MAIN_DB_PREFIX."accounting_account as a";
-	$sql.= " WHERE a.fk_accounting_category = 1 ) " ; // todo sql with accounting category, but we need to define category in turnover
+	$sql.= " FROM ".MAIN_DB_PREFIX."accounting_bookkeeping as b, ".MAIN_DB_PREFIX."accounting_journal as aj";
+	$sql.= " WHERE b.entity = ".$conf->entity;
+	$sql.= " AND b.code_journal = aj.code AND aj.nature = 2" ; // @TODO currently count amount in sale journal, but we need to define a category group for turnover
 }
 
-
 $sql.= " GROUP BY dm";
 $sql.= " ORDER BY dm";
+//print $sql;
 
 $result = $db->query($sql);
 if ($result)
@@ -221,7 +218,7 @@ else {
 }
 
 // On ajoute les paiements anciennes version, non lies par paiement_facture (very old versions)
-if ($modecompta != 'CREANCES-DETTES')
+if ($modecompta == 'RECETTES-DEPENSES')
 {
 	$sql = "SELECT date_format(p.datep,'%Y-%m') as dm, sum(p.amount) as amount_ttc";
 	$sql.= " FROM ".MAIN_DB_PREFIX."bank as b";
@@ -269,10 +266,11 @@ for ($annee = $year_start ; $annee <= $year_end ; $annee++)
 {
 	if ($modecompta == 'CREANCES-DETTES') print '<td align="center" width="10%" colspan="3">';
 	else print '<td align="center" width="10%" colspan="2" class="borderrightlight">';
-	print '<a href="casoc.php?year='.$annee.'">';
+	if ($modecompta != 'BOOKKEEPING') print '<a href="casoc.php?year='.$annee.'">';
 	print $annee;
     if ($conf->global->SOCIETE_FISCAL_MONTH_START > 1) print '-'.($annee+1);
-	print '</a></td>';
+    if ($modecompta != 'BOOKKEEPING') print '</a>';
+    print '</td>';
 	if ($annee != $year_end) print '<td width="15">&nbsp;</td>';
 }
 print '</tr>';
@@ -336,7 +334,9 @@ for ($mois = 1+$nb_mois_decalage ; $mois <= 12+$nb_mois_decalage ; $mois++)
 			if ($cum[$case])
 			{
 				$now_show_delta=1;  // On a trouve le premier mois de la premiere annee generant du chiffre.
-				print '<a href="casoc.php?year='.$annee_decalage.'&month='.$mois_modulo.($modecompta?'&modecompta='.$modecompta:'').'">'.price($cum[$case],1).'</a>';
+				if ($modecompta != 'BOOKKEEPING') print '<a href="casoc.php?year='.$annee_decalage.'&month='.$mois_modulo.($modecompta?'&modecompta='.$modecompta:'').'">';
+				print price($cum[$case], 1);
+				if ($modecompta != 'BOOKKEEPING') print '</a>';
 			}
 			else
 			{

+ 33 - 18
htdocs/core/actions_linkedfiles.inc.php

@@ -176,11 +176,11 @@ elseif ($action == 'confirm_updateline' && GETPOST('save','alpha') && GETPOST('l
 }
 elseif ($action == 'renamefile' && GETPOST('renamefilesave','alpha'))
 {
-    // For documents pages, upload_dir contains already path to file from module dir, so we clean path into urlfile.
-    if (! empty($upload_dir))
-    {
-        $filenamefrom=dol_sanitizeFileName(GETPOST('renamefilefrom','alpha'), '_', 0);	// Do not remove accents
-        $filenameto=dol_sanitizeFileName(GETPOST('renamefileto','alpha'), '_', 0);		// Do not remove accents
+	// For documents pages, upload_dir contains already path to file from module dir, so we clean path into urlfile.
+	if (! empty($upload_dir))
+	{
+		$filenamefrom=dol_sanitizeFileName(GETPOST('renamefilefrom','alpha'), '_', 0);	// Do not remove accents
+		$filenameto=dol_sanitizeFileName(GETPOST('renamefileto','alpha'), '_', 0);		// Do not remove accents
 
         if ($filenamefrom != $filenameto)
         {
@@ -197,23 +197,38 @@ elseif ($action == 'renamefile' && GETPOST('renamefilesave','alpha'))
 	            $srcpath = $upload_dir.'/'.$filenamefrom;
 	            $destpath = $upload_dir.'/'.$filenameto;
 
-	            $result = dol_move($srcpath, $destpath);
-	            if ($result)
+	            $reshook=$hookmanager->initHooks(array('actionlinkedfiles'));
+	            $parameters=array('filenamefrom' => $filenamefrom, 'filenameto' => $filenameto, 'upload_dir' => $upload_dir);
+	            $reshook=$hookmanager->executeHooks('renameUploadedFile', $parameters, $object);
+
+	            if (empty($reshook))
 	            {
-	            	if ($object->id)
+	            	if (! file_exists($destpath))
 	            	{
-	                	$object->addThumbs($destpath);
-	            	}
+	            		$result = dol_move($srcpath, $destpath);
+			            if ($result)
+			            {
+			            	if ($object->id)
+			            	{
+			                	$object->addThumbs($destpath);
+			            	}
 
-	                // TODO Add revert function of addThumbs to remove for old name
-	                //$object->delThumbs($srcpath);
+			                // TODO Add revert function of addThumbs to remove for old name
+			                //$object->delThumbs($srcpath);
 
-	                setEventMessages($langs->trans("FileRenamed"), null);
-	            }
-	            else
-	            {
-	                $langs->load("errors"); // key must be loaded because we can't rely on loading during output, we need var substitution to be done now.
-	                setEventMessages($langs->trans("ErrorFailToRenameFile", $filenamefrom, $filenameto), null, 'errors');
+			                setEventMessages($langs->trans("FileRenamed"), null);
+			            }
+			            else
+			            {
+			                $langs->load("errors"); // key must be loaded because we can't rely on loading during output, we need var substitution to be done now.
+			                setEventMessages($langs->trans("ErrorFailToRenameFile", $filenamefrom, $filenameto), null, 'errors');
+			            }
+	            	}
+	            	else
+	            	{
+	            		$langs->load("errors"); // key must be loaded because we can't rely on loading during output, we need var substitution to be done now.
+	            		setEventMessages($langs->trans("ErrorDestinationAlreadyExists", $filenameto), null, 'errors');
+	            	}
 	            }
 	        }
         }

+ 1 - 1
htdocs/core/boxes/box_commandes.php

@@ -136,7 +136,7 @@ class box_commandes extends ModeleBoxes
                     );
 
                     $this->info_box_contents[$line][] = array(
-                        'td' => 'class="tdoverflowmax100"',
+                        'td' => 'class="tdoverflowmax150 maxwidth150onsmartphone"',
                         'text' => $societestatic->getNomUrl(1),
                         'asis' => 1,
                     );

+ 1 - 1
htdocs/core/boxes/box_contracts.php

@@ -128,7 +128,7 @@ class box_contracts extends ModeleBoxes
                     );
 
                     $this->info_box_contents[$line][] = array(
-                        'td' => 'class="tdoverflowmax100 maxwidth100onsmartphone"',
+                        'td' => 'class="tdoverflowmax150 maxwidth150onsmartphone"',
                         'text' => $thirdpartytmp->getNomUrl(1),
                         'asis'=>1
                     );

+ 2 - 0
htdocs/core/boxes/box_graph_invoices_permonth.php

@@ -91,6 +91,8 @@ class box_graph_invoices_permonth extends ModeleBoxes
 
 		if ($user->rights->facture->lire)
 		{
+			$mesg = '';
+
 			$param_year='DOLUSERCOOKIE_box_'.$this->boxcode.'_year';
 			$param_shownb='DOLUSERCOOKIE_box_'.$this->boxcode.'_shownb';
 			$param_showtot='DOLUSERCOOKIE_box_'.$this->boxcode.'_showtot';

+ 2 - 2
htdocs/core/boxes/box_produits.php

@@ -131,13 +131,13 @@ class box_produits extends ModeleBoxes
 					$productstatic->entity = $objp->entity;
 
 					$this->info_box_contents[$line][] = array(
-                        'td' => 'class="tdoverflowmax100 maxwidth100onsmartphone"',
+                        'td' => 'class="tdoverflowmax150 maxwidth150onsmartphone"',
                         'text' => $productstatic->getNomUrl(1),
                         'asis' => 1,
                     );
 
                     $this->info_box_contents[$line][] = array(
-                        'td' => 'class="tdoverflowmax100 maxwidth100onsmartphone"',
+                        'td' => 'class="tdoverflowmax150 maxwidth150onsmartphone"',
                         'text' => $objp->label,
                     );
 

+ 1 - 1
htdocs/core/boxes/box_produits_alerte_stock.php

@@ -144,7 +144,7 @@ class box_produits_alerte_stock extends ModeleBoxes
                     );
 
                     $this->info_box_contents[$line][] = array(
-                        'td' => 'class="tdoverflowmax100 maxwidth100onsmartphone"',
+                        'td' => 'class="tdoverflowmax150 maxwidth150onsmartphone"',
                         'text' => $objp->label,
                     );
 

+ 2 - 2
htdocs/core/boxes/box_propales.php

@@ -131,13 +131,13 @@ class box_propales extends ModeleBoxes
                     );
 
                     $this->info_box_contents[$line][] = array(
-                        'td' => 'class="tdoverflowmax100"',
+                        'td' => 'class="tdoverflowmax150 maxwidth150onsmartphone"',
                         'text' => $societestatic->getNomUrl(1),
                         'asis' => 1,
                     );
 
                     $this->info_box_contents[$line][] = array(
-                        'td' => 'class="right"',
+                        'td' => 'class="right nowraponall"',
                         'text' => price($objp->total_ht, 0, $langs, 0, -1, -1, $conf->currency),
                     );
 

+ 2 - 2
htdocs/core/boxes/box_services_contracts.php

@@ -177,7 +177,7 @@ class box_services_contracts extends ModeleBoxes
 					}
 
 
-					$this->info_box_contents[$i][] = array('td' => 'class="tdoverflowmax100 maxwidth100onsmartphone"',
+					$this->info_box_contents[$i][] = array('td' => 'class="tdoverflowmax150 maxwidth150onsmartphone"',
                     'text' => $s,
 					'asis' => 1
                     );
@@ -187,7 +187,7 @@ class box_services_contracts extends ModeleBoxes
 					'asis' => 1
                     );
 
-					$this->info_box_contents[$i][] = array('td' => 'class="tdoverflowmax100 maxwidth100onsmartphone"',
+					$this->info_box_contents[$i][] = array('td' => 'class="tdoverflowmax150 maxwidth150onsmartphone"',
                     'text' => $thirdpartytmp->getNomUrl(1),
 					'asis' => 1
                     );

+ 1 - 1
htdocs/core/boxes/box_services_expired.php

@@ -126,7 +126,7 @@ class box_services_expired extends ModeleBoxes
     				'asis' => 1
     				);
 
-    				$this->info_box_contents[$i][] = array('td' => 'class="tdoverflowmax100 maxwidth100onsmartphone" align="left"',
+    				$this->info_box_contents[$i][] = array('td' => 'class="tdoverflowmax150 maxwidth150onsmartphone" align="left"',
     				'text' => $thirdpartytmp->getNomUrl(1, 'customer'),
     				'asis' => 1
     				);

+ 1 - 1
htdocs/core/boxes/modules_boxes.php

@@ -248,7 +248,7 @@ class ModeleBoxes    // Can't be abtract as it is instantiated to build "empty"
                 $out.= '>';
                 if ($conf->use_javascript_ajax)
                 {
-                    $out.= '<table summary="" class="nobordernopadding" width="100%"><tr><td class="tdoverflowmax100 maxwidth100onsmartphone">';
+                    $out.= '<table summary="" class="nobordernopadding" width="100%"><tr><td class="tdoverflowmax150 maxwidth150onsmartphone">';
                 }
                 if (! empty($head['text']))
                 {

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

@@ -319,7 +319,7 @@ abstract class CommonDocGenerator
 
     	foreach($conf->global as $key => $val)
     	{
-    		if (preg_match('/(_pass|password|secret|_key|key$)/i', $keyfound)) $newval = '*****forbidden*****';
+    		if (preg_match('/(_pass|password|secret|_key|key$)/i', $key)) $newval = '*****forbidden*****';
     		else $newval = $val;
     		$array_other['__['.$key.']__'] = $newval;
     	}

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

@@ -2739,7 +2739,7 @@ abstract class CommonObject
 	 *	@param  string	$targettype		Object target type (if not defined, elemennt name of object)
 	 *	@param  string	$clause			'OR' or 'AND' clause used when both source id and target id are provided
 	 *  @param	int		$alsosametype	0=Return only links to object that differs from source. 1=Include also link to objects of same type.
-	 *	@return	void
+	 *	@return	int						<0 if KO, >0 if OK
 	 *  @see	add_object_linked, updateObjectLinked, deleteObjectLinked
 	 */
 	function fetchObjectLinked($sourceid=null,$sourcetype='',$targetid=null,$targettype='',$clause='OR',$alsosametype=1)
@@ -2920,10 +2920,12 @@ abstract class CommonObject
 					}
 				}
 			}
+			return 1;
 		}
 		else
 		{
 			dol_print_error($this->db);
+			return -1;
 		}
 	}
 
@@ -3582,7 +3584,7 @@ abstract class CommonObject
 	 *	Return HTML table for object lines
 	 *	TODO Move this into an output class file (htmlline.class.php)
 	 *	If lines are into a template, title must also be into a template
-	 *	But for the moment we don't know if it'st possible as we keep a method available on overloaded objects.
+	 *	But for the moment we don't know if it's possible as we keep a method available on overloaded objects.
 	 *
 	 *	@param	string		$action				Action code
 	 *	@param  string		$seller            	Object of seller third party
@@ -4518,6 +4520,7 @@ abstract class CommonObject
 		}
 		else
 		{
+			global $extrafields;
 			dol_syslog("Warning: fetch_optionals was called with param optionsArray defined when you should pass null now", LOG_WARNING);
 		}
 
@@ -4691,7 +4694,8 @@ abstract class CommonObject
 			   			if ($this->array_options[$key] != '' && is_array($extrafields->attributes[$this->table_element]['param'][$attributeKey]['options']))
 			   			{
 			   				// If there is an encryption choice, we use it to crypt data before insert
-			   				$algo=reset(array_keys($extrafields->attributes[$this->table_element]['param'][$attributeKey]['options']));
+			   				$tmparrays = array_keys($extrafields->attributes[$this->table_element]['param'][$attributeKey]['options']);
+			   				$algo=reset($tmparrays);
 			   				if ($algo != '')
 			   				{
 			   					//global $action;		// $action may be 'create', 'update', 'update_extras'...

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

@@ -235,6 +235,7 @@ class ExtraFields
 				$lengthdb='11';
 			} elseif ($type=='html') {
 				$typedb='text';
+				$lengthdb=$length;
 			} elseif($type=='password') {
 				$typedb='varchar';
 				$lengthdb='128';

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

@@ -3421,7 +3421,8 @@ class Form
 			}
 			else
 			{
-				print $langs->trans("NoActiveBankAccountDefined");
+				if ($statut == 0) print $langs->trans("NoActiveBankAccountDefined");
+				else print $langs->trans("NoBankAccountFound");
 			}
 		}
 		else {

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

@@ -194,6 +194,7 @@ class FormActions
             $projectid = $object->fk_project;
             if ($typeelement == 'project') $projectid = $object->id;
 
+            $buttontoaddnewevent='';
 			if (! empty($conf->agenda->enabled))
 			{
 				$buttontoaddnewevent = '<a href="'.DOL_URL_ROOT.'/comm/action/card.php?action=create&datep='.dol_print_date(dol_now(),'dayhourlog').'&origin='.$typeelement.'&originid='.$object->id.($object->socid>0?'&socid='.$object->socid:'').($projectid>0?'&projectid='.$projectid:'').'&backtopage='.urlencode($urlbacktopage).'">';

+ 3 - 2
htdocs/core/class/html.formcompany.class.php

@@ -545,9 +545,10 @@ class FormCompany
 	 * 	@param	array		$limitto		Disable answers that are not id in this array list
 	 *  @param	int			$forceid		This is to force another object id than object->id
      *  @param	string		$moreparam		String with more param to add into url when noajax search is used.
+     *  @param	string		$morecss		More CSS on select component
 	 * 	@return int 						The selected third party ID
 	 */
-	function selectCompaniesForNewContact($object, $var_id, $selected='', $htmlname='newcompany', $limitto='', $forceid=0, $moreparam='')
+	function selectCompaniesForNewContact($object, $var_id, $selected='', $htmlname='newcompany', $limitto='', $forceid=0, $moreparam='', $morecss='')
 	{
 		global $conf, $langs;
 
@@ -649,7 +650,7 @@ class FormCompany
 			$resql = $this->db->query($sql);
 			if ($resql)
 			{
-				print '<select class="flat" id="'.$htmlname.'" name="'.$htmlname.'"';
+				print '<select class="flat'.($morecss?' '.$morecss:'').'" id="'.$htmlname.'" name="'.$htmlname.'"';
 				if ($conf->use_javascript_ajax)
 				{
 					$javaScript = "window.location='".$_SERVER['PHP_SELF']."?".$var_id."=".($forceid>0?$forceid:$object->id).$moreparam."&".$htmlname."=' + form.".$htmlname.".options[form.".$htmlname.".selectedIndex].value;";

+ 3 - 2
htdocs/core/class/html.formother.class.php

@@ -863,11 +863,12 @@ class FormOther
      *  @param	int			$offset			Offset
      *  @param	int			$invert			Invert
      *  @param	string		$option			Option
+     *  @param	string		$morecss		More CSS
      *  @return	string
      */
-    function select_year($selected='',$htmlname='yearid',$useempty=0, $min_year=10, $max_year=5, $offset=0, $invert=0, $option='')
+    function select_year($selected='',$htmlname='yearid',$useempty=0, $min_year=10, $max_year=5, $offset=0, $invert=0, $option='', $morecss='')
     {
-        print $this->selectyear($selected,$htmlname,$useempty,$min_year,$max_year,$offset,$invert,$option);
+        print $this->selectyear($selected,$htmlname,$useempty,$min_year,$max_year,$offset,$invert,$option,$morecss);
     }
 
     /**

+ 3 - 4
htdocs/core/class/html.formwebsite.class.php

@@ -164,7 +164,7 @@ class FormWebsite
      *
      *  @param  string	$htmlname          	Name of select zone
      *  @param	string	$selected			Selected value
-     *  @param  int		$useempty          	1=Add an empty value in list, 2=Add an empty value in list only if there is more than 2 entries.
+     *  @param  int		$useempty          	1=Add an empty value in list
      *  @param  string  $moreattrib         More attributes on HTML select tag
      * 	@return	void
      */
@@ -177,9 +177,9 @@ class FormWebsite
     	$arrayofsamples=array('corporatehome'=>'CorporateHomePage', 'empty'=>'EmptyPage');
 
     	$out = '';
-
     	$out .= '<select id="select'.$htmlname.'" class="flat selectTypeOfContainer" name="'.$htmlname.'"'.($moreattrib?' '.$moreattrib:'').'>';
-    	if ($useempty == 1 || ($useempty == 2 && $num > 1))
+
+    	if ($useempty == 1 || $useempty == 2)
     	{
     		$out .= '<option value="-1">&nbsp;</option>';
     	}
@@ -196,7 +196,6 @@ class FormWebsite
     		}
     		$out .= $langs->trans($val);
     		$out .= '</option>';
-    		$i++;
     	}
     	$out .= "</select>";
 

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

@@ -67,7 +67,7 @@ class Utils
 			// Delete temporary files
 			if ($dolibarr_main_data_root)
 			{
-				$filesarray=dol_dir_list($dolibarr_main_data_root, "directories", 1, '^temp$', '', '', '', 2, 0, '', 1);	// Do not follow symlinks
+				$filesarray=dol_dir_list($dolibarr_main_data_root, "directories", 1, '^temp$', '', 'name', SORT_ASC, 2, 0, '', 1);	// Do not follow symlinks
 				if ($choice == 'tempfilesold')
 				{
 					$now = dol_now();
@@ -81,10 +81,10 @@ class Utils
 
 		if ($choice=='allfiles')
 		{
-			// Delete all files (except install.lock)
+			// Delete all files (except install.lock, do not follow symbolic links)
 			if ($dolibarr_main_data_root)
 			{
-				$filesarray=dol_dir_list($dolibarr_main_data_root,"all",0,'','install\.lock$');
+				$filesarray=dol_dir_list($dolibarr_main_data_root, "all", 0, '', 'install\.lock$', 'name', SORT_ASC, 0, 0, '', 1);
 			}
 		}
 
@@ -93,7 +93,7 @@ class Utils
 			// Define files log
 			if ($dolibarr_main_data_root)
 			{
-				$filesarray=dol_dir_list($dolibarr_main_data_root, "files", 0, '.*\.log[\.0-9]*$', 'install\.lock$');
+				$filesarray=dol_dir_list($dolibarr_main_data_root, "files", 0, '.*\.log[\.0-9]*$', 'install\.lock$', 'name', SORT_ASC, 0, 0, '', 1);
 			}
 
 			$filelog='';

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

@@ -1288,9 +1288,10 @@ function complete_elementList_with_modules(&$elementList)
 
                             $modules[$i] = $objMod;
                             $filename[$i]= $modName;
-                            $orders[$i]  = $objMod->family."_".$j;   // Tri par famille puis numero module
+                            $orders[$i]  = $objMod->family."_".$j;   // Sort on family then module number
+                            $dirmod[$i] = $dir;
                             //print "x".$modName." ".$orders[$i]."\n<br>";
-                            $dirmod[$i] = $dirroot;
+
                             if (! empty($objMod->module_parts['contactelement']))
                             {
                             	$elementList[$objMod->name] = $langs->trans($objMod->name);

+ 18 - 8
htdocs/core/lib/functions.lib.php

@@ -1077,11 +1077,12 @@ function dol_syslog($message, $level = LOG_INFO, $ident = 0, $suffixinfilename='
  * 	@param	string	$picto				Add a picto on tab title
  *	@param	int		$pictoisfullpath	If 1, image path is a full path. If you set this to 1, you can use url returned by dol_buildpath('/mymodyle/img/myimg.png',1) for $picto.
  *  @param	string	$morehtmlright		Add more html content on right of tabs title
+ *  @param	string	$morecss			More Css
  * 	@return	void
  */
-function dol_fiche_head($links=array(), $active='0', $title='', $notab=0, $picto='', $pictoisfullpath=0, $morehtmlright='')
+function dol_fiche_head($links=array(), $active='0', $title='', $notab=0, $picto='', $pictoisfullpath=0, $morehtmlright='', $morecss='')
 {
-	print dol_get_fiche_head($links, $active, $title, $notab, $picto, $pictoisfullpath, $morehtmlright);
+	print dol_get_fiche_head($links, $active, $title, $notab, $picto, $pictoisfullpath, $morehtmlright, $morecss);
 }
 
 /**
@@ -1094,9 +1095,10 @@ function dol_fiche_head($links=array(), $active='0', $title='', $notab=0, $picto
  * 	@param	string	$picto				Add a picto on tab title
  *	@param	int		$pictoisfullpath	If 1, image path is a full path. If you set this to 1, you can use url returned by dol_buildpath('/mymodyle/img/myimg.png',1) for $picto.
  *  @param	string	$morehtmlright		Add more html content on right of tabs title
+ *  @param	string	$morecss			More Css
  * 	@return	string
  */
-function dol_get_fiche_head($links=array(), $active='', $title='', $notab=0, $picto='', $pictoisfullpath=0, $morehtmlright='')
+function dol_get_fiche_head($links=array(), $active='', $title='', $notab=0, $picto='', $pictoisfullpath=0, $morehtmlright='', $morecss='')
 {
 	global $conf, $langs, $hookmanager;
 
@@ -1161,7 +1163,7 @@ function dol_get_fiche_head($links=array(), $active='', $title='', $notab=0, $pi
 			{
 				if (!empty($links[$i][0]))
 				{
-					$out.='<a class="tabimage" href="'.$links[$i][0].'">'.$links[$i][1].'</a>'."\n";
+					$out.='<a class="tabimage'.($morecss?' '.$morecss:'').'" href="'.$links[$i][0].'">'.$links[$i][1].'</a>'."\n";
 				}
 				else
 				{
@@ -1173,13 +1175,13 @@ function dol_get_fiche_head($links=array(), $active='', $title='', $notab=0, $pi
 				//print "x $i $active ".$links[$i][2]." z";
 				if ($isactive)
 				{
-					$out.='<a'.(! empty($links[$i][2])?' id="'.$links[$i][2].'"':'').' class="tabactive tab inline-block" href="'.$links[$i][0].'">';
+					$out.='<a'.(! empty($links[$i][2])?' id="'.$links[$i][2].'"':'').' class="tabactive tab inline-block'.($morecss?' '.$morecss:'').'" href="'.$links[$i][0].'">';
 					$out.=$links[$i][1];
 					$out.='</a>'."\n";
 				}
 				else
 				{
-					$out.='<a'.(! empty($links[$i][2])?' id="'.$links[$i][2].'"':'').' class="tabunactive tab inline-block" href="'.$links[$i][0].'">';
+					$out.='<a'.(! empty($links[$i][2])?' id="'.$links[$i][2].'"':'').' class="tabunactive tab inline-block'.($morecss?' '.$morecss:'').'" href="'.$links[$i][0].'">';
 					$out.=$links[$i][1];
 					$out.='</a>'."\n";
 				}
@@ -1198,14 +1200,14 @@ function dol_get_fiche_head($links=array(), $active='', $title='', $notab=0, $pi
 			if (isset($links[$i][2]) && $links[$i][2] == 'image')
 			{
 				if (!empty($links[$i][0]))
-					$outmore.='<a class="tabimage" href="'.$links[$i][0].'">'.$links[$i][1].'</a>'."\n";
+					$outmore.='<a class="tabimage'.($morecss?' '.$morecss:'').'" href="'.$links[$i][0].'">'.$links[$i][1].'</a>'."\n";
 				else
 					$outmore.='<span class="tabspan">'.$links[$i][1].'</span>'."\n";
 
 			}
 			else if (! empty($links[$i][1]))
 			{
-				$outmore.='<a'.(! empty($links[$i][2])?' id="'.$links[$i][2].'"':'').' class="wordwrap inline-block" href="'.$links[$i][0].'">';
+				$outmore.='<a'.(! empty($links[$i][2])?' id="'.$links[$i][2].'"':'').' class="wordwrap inline-block'.($morecss?' '.$morecss:'').'" href="'.$links[$i][0].'">';
 				$outmore.=preg_replace('/([a-z])\/([a-z])/i', '\\1 / \\2', $links[$i][1]);	// Replace x/y with x / y to allow wrap on long composed texts.
 				$outmore.='</a>'."\n";
 			}
@@ -1489,6 +1491,14 @@ function dol_banner_tab($object, $paramid, $morehtml='', $shownav=1, $fieldid='r
 		if ($object->frequency == 0) $morehtmlstatus.=$object->getLibStatut(2);
 		else $morehtmlstatus.=$object->getLibStatut(5);
 	}
+	elseif ($object->element == 'project_task')
+	{
+		$object->fk_statut = 1;
+		if ($object->progress > 0) $object->fk_statut = 2;
+		if ($object->progress >= 100) $object->fk_statut = 3;
+		$tmptxt=$object->getLibStatut(5);
+		$morehtmlstatus.=$tmptxt;		// No status on task
+	}
 	else { // Generic case
 		$tmptxt=$object->getLibStatut(6);
 		if (empty($tmptxt) || $tmptxt == $object->getLibStatut(3) || $conf->browser->layout=='phone') $tmptxt=$object->getLibStatut(5);

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

@@ -177,6 +177,7 @@ function redirectToContainer($containerref, $containeraliasalt='',$containerid=0
 	global $db, $website;
 
 	$newurl = '';
+	$result=0;
 
 	// We make redirect using the alternative alias, we must find the real $containerref
 	if ($containeraliasalt)

+ 1 - 1
htdocs/core/menus/standard/eldy.lib.php

@@ -818,7 +818,7 @@ function print_left_eldy_menu($db,$menu_array_before,$menu_array_after,&$tabMenu
 
 				if (! empty($conf->global->BILL_ADD_PAYMENT_VALIDATION))
 				{
-					$newmenu->add("/compta/paiement/avalider.php?leftmenu=customers_bills_tovalid",$langs->trans("MenuToValid"),2,$user->rights->facture->lire,'',$mainmenu,'customer_bills_tovalid');
+					$newmenu->add("/compta/paiement/tovalidate.php?leftmenu=customers_bills_tovalid",$langs->trans("MenuToValid"),2,$user->rights->facture->lire,'',$mainmenu,'customer_bills_tovalid');
 				}
 				$newmenu->add("/compta/paiement/rapport.php?leftmenu=customers_bills_reports",$langs->trans("Reportings"),2,$user->rights->facture->lire,'',$mainmenu,'customers_bills_reports');
 

+ 4 - 4
htdocs/core/tpl/contacts.tpl.php

@@ -91,7 +91,7 @@ if ($permission) {
 	<?php if ($withproject) print '<input type="hidden" name="withproject" value="'.$withproject.'">'; ?>
 		<div class="nowrap tagtd"><?php echo img_object('','user').' '.$langs->trans("Users"); ?></div>
 		<div class="tagtd"><?php echo $conf->global->MAIN_INFO_SOCIETE_NOM; ?></div>
-		<div class="tagtd maxwidthonsmartphone"><?php echo $form->select_dolusers($user->id, 'userid', 0, (! empty($userAlreadySelected)?$userAlreadySelected:null), 0, null, null, 0, 56); ?></div>
+		<div class="tagtd maxwidthonsmartphone"><?php echo $form->select_dolusers($user->id, 'userid', 0, (! empty($userAlreadySelected)?$userAlreadySelected:null), 0, null, null, 0, 56, '', 0, '', 'minwidth200imp'); ?></div>
 		<div class="tagtd maxwidthonsmartphone">
 		<?php
 		$tmpobject=$object;
@@ -126,16 +126,16 @@ if ($permission) {
 			    echo img_object('', 'company', 'class="hideonsmartphone"');
 			}
 			?>
-			<?php $selectedCompany = $formcompany->selectCompaniesForNewContact($object, 'id', $selectedCompany, 'newcompany', '', 0); ?>
+			<?php $selectedCompany = $formcompany->selectCompaniesForNewContact($object, 'id', $selectedCompany, 'newcompany', '', 0, '', 'minwidth300imp'); ?>
 		</div>
 		<div class="tagtd maxwidthonsmartphone noborderbottom">
-			<?php $nbofcontacts=$form->select_contacts($selectedCompany, '', 'contactid', 0, '', '', 0, 'minwidth200'); ?>
+			<?php $nbofcontacts=$form->select_contacts($selectedCompany, '', 'contactid', 0, '', '', 0, 'minwidth100imp'); ?>
 		</div>
 		<div class="tagtd maxwidthonsmartphone noborderbottom">
 			<?php
 			$tmpobject=$object;
 			if ($object->element == 'shipping' && is_object($objectsrc)) $tmpobject=$objectsrc;
-			$formcompany->selectTypeContact($tmpobject, '', 'type','external'); ?>
+			$formcompany->selectTypeContact($tmpobject, '', 'type','external', 'position', 0, 'minwidth100imp'); ?>
 		</div>
 		<div class="tagtd noborderbottom">&nbsp;</div>
 		<div class="tagtd center noborderbottom">

+ 46 - 5
htdocs/core/triggers/interface_50_modAgenda_ActionsAuto.class.php

@@ -655,20 +655,53 @@ class InterfaceActionsAuto extends DolibarrTriggers
 
             $object->sendtoid=0;
 		}
-        elseif ($action == 'MEMBER_SUBSCRIPTION')
+        elseif ($action == 'MEMBER_SUBSCRIPTION_CREATE')
         {
             $langs->load("agenda");
             $langs->load("other");
             $langs->load("members");
 
-            if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("MemberSubscriptionAddedInDolibarr",$object->getFullName($langs));
-            $object->actionmsg=$langs->transnoentities("MemberSubscriptionAddedInDolibarr",$object->getFullName($langs));
+            if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("MemberSubscriptionAddedInDolibarr",$object->ref,$object->getFullName($langs));
+            $object->actionmsg=$langs->transnoentities("MemberSubscriptionAddedInDolibarr",$object->ref,$object->getFullName($langs));
             $object->actionmsg.="\n".$langs->transnoentities("Member").': '.$object->getFullName($langs);
             $object->actionmsg.="\n".$langs->transnoentities("Type").': '.$object->type;
             $object->actionmsg.="\n".$langs->transnoentities("Amount").': '.$object->last_subscription_amount;
             $object->actionmsg.="\n".$langs->transnoentities("Period").': '.dol_print_date($object->last_subscription_date_start,'day').' - '.dol_print_date($object->last_subscription_date_end,'day');
 
 			$object->sendtoid=0;
+			if ($object->fk_soc > 0) $object->socid=$object->fk_soc;
+        }
+        elseif ($action == 'MEMBER_SUBSCRIPTION_MODIFY')
+        {
+        	$langs->load("agenda");
+        	$langs->load("other");
+        	$langs->load("members");
+
+        	if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("MemberSubscriptionModifiedInDolibarr",$object->ref,$object->getFullName($langs));
+        	$object->actionmsg=$langs->transnoentities("MemberSubscriptionModifiedInDolibarr",$object->ref,$object->getFullName($langs));
+        	$object->actionmsg.="\n".$langs->transnoentities("Member").': '.$object->getFullName($langs);
+        	$object->actionmsg.="\n".$langs->transnoentities("Type").': '.$object->type;
+        	$object->actionmsg.="\n".$langs->transnoentities("Amount").': '.$object->last_subscription_amount;
+        	$object->actionmsg.="\n".$langs->transnoentities("Period").': '.dol_print_date($object->last_subscription_date_start,'day').' - '.dol_print_date($object->last_subscription_date_end,'day');
+
+        	$object->sendtoid=0;
+        	if ($object->fk_soc > 0) $object->socid=$object->fk_soc;
+        }
+        elseif ($action == 'MEMBER_SUBSCRIPTION_DELETE')
+        {
+        	$langs->load("agenda");
+        	$langs->load("other");
+        	$langs->load("members");
+
+        	if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("MemberSubscriptionDeletedInDolibarr",$object->ref,$object->getFullName($langs));
+        	$object->actionmsg=$langs->transnoentities("MemberSubscriptionDeletedInDolibarr",$object->ref,$object->getFullName($langs));
+        	$object->actionmsg.="\n".$langs->transnoentities("Member").': '.$object->getFullName($langs);
+        	$object->actionmsg.="\n".$langs->transnoentities("Type").': '.$object->type;
+        	$object->actionmsg.="\n".$langs->transnoentities("Amount").': '.$object->last_subscription_amount;
+        	$object->actionmsg.="\n".$langs->transnoentities("Period").': '.dol_print_date($object->last_subscription_date_start,'day').' - '.dol_print_date($object->last_subscription_date_end,'day');
+
+        	$object->sendtoid=0;
+        	if ($object->fk_soc > 0) $object->socid=$object->fk_soc;
         }
         elseif ($action == 'MEMBER_RESILIATE')
         {
@@ -816,6 +849,14 @@ class InterfaceActionsAuto extends DolibarrTriggers
         $projectid = isset($object->fk_project)?$object->fk_project:0;
         if ($object->element == 'project') $projectid = $object->id;
 
+        $elementid = $object->id;
+        $elementtype = $object->element;
+        if ($object->element == 'subscription')
+        {
+        	$elementid = $object->fk_adherent;
+        	$elementtype = 'member';
+        }
+
 		// Insertion action
 		require_once DOL_DOCUMENT_ROOT.'/comm/action/class/actioncomm.class.php';
 		$actioncomm = new ActionComm($this->db);
@@ -845,8 +886,8 @@ class InterfaceActionsAuto extends DolibarrTriggers
 		$actioncomm->email_subject = $object->email_subject;
 		$actioncomm->errors_to   = $object->errors_to;
 
-		$actioncomm->fk_element  = $object->id;
-		$actioncomm->elementtype = $object->element;
+		$actioncomm->fk_element  = $elementid;
+		$actioncomm->elementtype = $elementtype;
 
 		$ret=$actioncomm->create($user);       // User creating action
 

+ 4 - 2
htdocs/core/triggers/interface_50_modBlockedlog_ActionsBlockedLog.class.php

@@ -69,14 +69,16 @@ class InterfaceActionsBlockedLog extends DolibarrTriggers
 		$amounts = 0;
 		if ($action==='BILL_VALIDATE' || $action==='BILL_DELETE' || $action === 'BILL_SENTBYMAIL'
 			|| $action==='BILL_SUPPLIER_VALIDATE' || $action==='BILL_SUPPLIER_DELETE' || $action === 'BILL_SUPPLIER_SENTBYMAIL'
-			|| $action==='MEMBER_SUBCRIPTION_CREATE' || $action==='MEMBER_SUBCRIPTION_MODIFY' || $action==='MEMBER_SUBCRIPTION_DELETE'
+			|| $action==='MEMBER_SUBSCRIPTION_CREATE' || $action==='MEMBER_SUBSCRIPTION_MODIFY' || $action==='MEMBER_SUBSCRIPTION_DELETE'
 			|| $action==='DON_VALIDATE' || $action==='DON_MODIFY' || $action==='DON_DELETE'
 			|| (in_array($object->element, array('facture','suplier_invoice')) && $action === 'DOC_DOWNLOAD') || (in_array($object->element, array('facture','suplier_invoice')) && $action === 'DOC_PREVIEW')
 		)
 		{
 			$qualified++;
 
-			if ($action==='DON_VALIDATE') $amounts = (double) $object->amount;
+			if (in_array($action, array(
+				'MEMBER_SUBSCRIPTION_CREATE','MEMBER_SUBSCRIPTION_MODIFY','MEMBER_SUBSCRIPTION_DELETE',
+				'DON_VALIDATE','DON_MODIFY','DON_DELETE'))) $amounts = (double) $object->amount;
 			else $amounts = (double) $object->total_ttc;
 		}
 		/*if ($action === 'BILL_PAYED' || $action==='BILL_UNPAYED'

+ 4 - 4
htdocs/expedition/class/expedition.class.php

@@ -398,7 +398,7 @@ class Expedition extends CommonObject
 
 		if (($lineId = $expeditionline->insert()) < 0)
 		{
-			$this->error[]=$expeditionline->error;
+			$this->errors[]=$expeditionline->error;
 		}
 		return $lineId;
 	}
@@ -2383,9 +2383,9 @@ class ExpeditionLigne extends CommonObjectLine
 		$error=0;
 
 		// Check parameters
-		if (empty($this->fk_expedition) || empty($this->fk_origin_line) || empty($this->qty))
+		if (empty($this->fk_expedition) || empty($this->fk_origin_line) || ! is_numeric($this->qty))
 		{
-			$this->errors[] = 'ErrorMandatoryParametersNotProvided';
+			$this->error = 'ErrorMandatoryParametersNotProvided';
 			return -1;
 		}
 		// Clean parameters
@@ -2425,7 +2425,6 @@ class ExpeditionLigne extends CommonObjectLine
 				$result=$this->call_trigger('LINESHIPPING_INSERT',$user);
 				if ($result < 0)
 				{
-					$this->errors[]=$this->error;
 					$error++;
 				}
 				// End call triggers
@@ -2441,6 +2440,7 @@ class ExpeditionLigne extends CommonObjectLine
 				dol_syslog(get_class($this)."::delete ".$errmsg, LOG_ERR);
 				$this->error.=($this->error?', '.$errmsg:$errmsg);
 			}
+			
 			$this->db->rollback();
 			return -1*$error;
 		}

+ 14 - 14
htdocs/index.php

@@ -339,14 +339,14 @@ if (empty($user->societe_id))
 	    }
     }
 
-    $boxstat.='<a class="boxstatsindicator thumbstat nobold nounderline"></a>';
-    $boxstat.='<a class="boxstatsindicator thumbstat nobold nounderline"></a>';
-    $boxstat.='<a class="boxstatsindicator thumbstat nobold nounderline"></a>';
-    $boxstat.='<a class="boxstatsindicator thumbstat nobold nounderline"></a>';
-    $boxstat.='<a class="boxstatsindicator thumbstat nobold nounderline"></a>';
-    $boxstat.='<a class="boxstatsindicator thumbstat nobold nounderline"></a>';
-    $boxstat.='<a class="boxstatsindicator thumbstat nobold nounderline"></a>';
-    $boxstat.='<a class="boxstatsindicator thumbstat nobold nounderline"></a>';
+    $boxstat.='<a class="boxstatsindicator thumbstat nobold nounderline"><div class="boxstatsempty"></div></a>';
+    $boxstat.='<a class="boxstatsindicator thumbstat nobold nounderline"><div class="boxstatsempty"></div></a>';
+    $boxstat.='<a class="boxstatsindicator thumbstat nobold nounderline"><div class="boxstatsempty"></div></a>';
+    $boxstat.='<a class="boxstatsindicator thumbstat nobold nounderline"><div class="boxstatsempty"></div></a>';
+    $boxstat.='<a class="boxstatsindicator thumbstat nobold nounderline"><div class="boxstatsempty"></div></a>';
+    $boxstat.='<a class="boxstatsindicator thumbstat nobold nounderline"><div class="boxstatsempty"></div></a>';
+    $boxstat.='<a class="boxstatsindicator thumbstat nobold nounderline"><div class="boxstatsempty"></div></a>';
+    $boxstat.='<a class="boxstatsindicator thumbstat nobold nounderline"><div class="boxstatsempty"></div></a>';
 
     $boxstat.='</td></tr>';
     $boxstat.='</table>';
@@ -583,12 +583,12 @@ if (! empty($valid_dashboardlines))
         $boxwork .="\n";
     }
 
-    $boxwork .='<div class="boxstatsindicator thumbstat150 nobold nounderline"></div>';
-    $boxwork .='<div class="boxstatsindicator thumbstat150 nobold nounderline"></div>';
-    $boxwork .='<div class="boxstatsindicator thumbstat150 nobold nounderline"></div>';
-    $boxwork .='<div class="boxstatsindicator thumbstat150 nobold nounderline"></div>';
-    $boxwork .='<div class="boxstatsindicator thumbstat150 nobold nounderline"></div>';
-    $boxwork .='<div class="boxstatsindicator thumbstat150 nobold nounderline"></div>';
+    $boxwork .='<div class="boxstatsindicator thumbstat150 nobold nounderline"><div class="boxstats150empty"></div></div>';
+    $boxwork .='<div class="boxstatsindicator thumbstat150 nobold nounderline"><div class="boxstats150empty"></div></div>';
+    $boxwork .='<div class="boxstatsindicator thumbstat150 nobold nounderline"><div class="boxstats150empty"></div></div>';
+    $boxwork .='<div class="boxstatsindicator thumbstat150 nobold nounderline"><div class="boxstats150empty"></div></div>';
+    $boxwork .='<div class="boxstatsindicator thumbstat150 nobold nounderline"><div class="boxstats150empty"></div></div>';
+    $boxwork .='<div class="boxstatsindicator thumbstat150 nobold nounderline"><div class="boxstats150empty"></div></div>';
     $boxwork .='</td></tr>';
 }
 else

+ 3 - 1
htdocs/install/mysql/data/llx_c_action_trigger.sql

@@ -74,7 +74,9 @@ insert into llx_c_action_trigger (code,label,description,elementtype,rang) value
 insert into llx_c_action_trigger (code,label,description,elementtype,rang) values ('SHIPPING_SENTBYMAIL','Shipping sent by mail','Executed when a shipping is sent by mail','shipping',21);
 insert into llx_c_action_trigger (code,label,description,elementtype,rang) values ('MEMBER_VALIDATE','Member validated','Executed when a member is validated','member',22);
 insert into llx_c_action_trigger (code,label,description,elementtype,rang) values ('MEMBER_SENTBYMAIL','Mails sent from member card','Executed when you send email from member card','member',23);
-insert into llx_c_action_trigger (code,label,description,elementtype,rang) values ('MEMBER_SUBSCRIPTION','Member subscribed','Executed when a member is subscribed','member',24);
+insert into llx_c_action_trigger (code,label,description,elementtype,rang) values ('MEMBER_SUBSCRIPTION_CREATE','Member subscribtion recorded','Executed when a member subscribtion is deleted','member',24);
+insert into llx_c_action_trigger (code,label,description,elementtype,rang) values ('MEMBER_SUBSCRIPTION_MODIFY','Member subscribtion modified','Executed when a member subscribtion is modified','member',24);
+insert into llx_c_action_trigger (code,label,description,elementtype,rang) values ('MEMBER_SUBSCRIPTION_DELETE','Member subscribtion deleted','Executed when a member subscribtion is deleted','member',24);
 insert into llx_c_action_trigger (code,label,description,elementtype,rang) values ('MEMBER_RESILIATE','Member resiliated','Executed when a member is resiliated','member',25);
 insert into llx_c_action_trigger (code,label,description,elementtype,rang) values ('MEMBER_DELETE','Member deleted','Executed when a member is deleted','member',26);
 insert into llx_c_action_trigger (code,label,description,elementtype,rang) values ('FICHINTER_VALIDATE','Intervention validated','Executed when a intervention is validated','ficheinter',30);

+ 6 - 1
htdocs/install/mysql/migration/6.0.0-7.0.0.sql

@@ -94,6 +94,11 @@ ALTER TABLE llx_website_page ADD COLUMN type_container varchar(16) NOT NULL DEFA
 
 -- For 7.0
 
+delete from llx_c_action_trigger where code = 'MEMBER_SUBSCRIPTION';
+insert into llx_c_action_trigger (code,label,description,elementtype,rang) values ('MEMBER_SUBSCRIPTION_CREATE','Member subscribtion recorded','Executed when a member subscribtion is deleted','member',24);
+insert into llx_c_action_trigger (code,label,description,elementtype,rang) values ('MEMBER_SUBSCRIPTION_MODIFY','Member subscribtion modified','Executed when a member subscribtion is modified','member',24);
+insert into llx_c_action_trigger (code,label,description,elementtype,rang) values ('MEMBER_SUBSCRIPTION_DELETE','Member subscribtion deleted','Executed when a member subscribtion is deleted','member',24);
+
 ALTER TABLE llx_product_attribute_value DROP INDEX unique_ref;
 ALTER TABLE llx_product_attribute_value ADD UNIQUE INDEX uk_product_attribute_value (fk_product_attribute, ref);
 
@@ -437,7 +442,7 @@ CREATE TABLE llx_expensereport_rules (
     fk_usergroup integer DEFAULT NULL,
     fk_c_type_fees integer NOT NULL,
     code_expense_rules_type varchar(50) NOT NULL,
-    is_for_all tinyint DEFAULT '0',
+    is_for_all tinyint DEFAULT 0,
     entity integer DEFAULT 1
 )ENGINE=innodb;
 

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

@@ -29,6 +29,6 @@ CREATE TABLE llx_expensereport_rules (
   fk_usergroup				integer DEFAULT NULL,
   fk_c_type_fees			integer NOT NULL,
   code_expense_rules_type	varchar(50) NOT NULL,
-  is_for_all				tinyint DEFAULT '0',
+  is_for_all				tinyint DEFAULT 0,
   entity					integer DEFAULT 1
 ) ENGINE=InnoDB;

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

@@ -420,7 +420,6 @@ ExtrafieldParamHelpsellist=List of values comes from a table<br>Syntax : table_n
 ExtrafieldParamHelpchkbxlst=List of values comes from a table<br>Syntax : table_name:label_field:id_field::filter<br>Example : c_typent:libelle:id::filter<br><br>filter can be a simple test (eg active=1) to display only active value<br>You can also use $ID$ in filter witch is the current id of current object<br>To do a SELECT in filter use $SEL$<br>if you want to filter on extrafields use syntax  extra.fieldcode=... (where field code is the code of extrafield)<br><br>In order to have the list depending on another complementary attribute list :<br>c_typent:libelle:id:options_<i>parent_list_code</i>|parent_column:filter <br><br>In order to have the list depending on another list:<br>c_typent:libelle:id:<i>parent_list_code</i>|parent_column:filter
 ExtrafieldParamHelplink=Parameters must be ObjectName:Classpath<br>Syntax : ObjectName:Classpath<br>Examples :<br>Societe:societe/class/societe.class.php<br>Contact:contact/class/contact.class.php
 LibraryToBuildPDF=Library used for PDF generation
-WarningUsingFPDF=Warning: Your <b>conf.php</b> contains directive <b>dolibarr_pdf_force_fpdf=1</b>. This means you use the FPDF library to generate PDF files. This library is old and does not support a lot of features (Unicode, image transparency, cyrillic, arab and asiatic languages, ...), so you may experience errors during PDF generation.<br>To solve this and have a full support of PDF generation, please download <a href="http://www.tcpdf.org/" target="_blank">TCPDF library</a>, then comment or remove the line <b>$dolibarr_pdf_force_fpdf=1</b>, and add instead <b>$dolibarr_lib_TCPDF_PATH='path_to_TCPDF_dir'</b>   
 LocalTaxDesc=Some countries apply 2 or 3 taxes on each invoice line. If this is the case, choose type for second and third tax and its rate. Possible type are:<br>1 : local tax apply on products and services without vat (localtax is calculated on amount without tax)<br>2 : local tax apply on products and services including vat (localtax is calculated on amount + main tax)<br>3 : local tax apply on products without vat (localtax is calculated on amount without tax)<br>4 : local tax apply on products including vat (localtax is calculated on amount + main vat)<br>5 : local tax apply on services without vat (localtax is calculated on amount without tax)<br>6 : local tax apply on services including vat (localtax is calculated on amount + tax)
 SMS=SMS
 LinkToTestClickToDial=Enter a phone number to call to show a link to test the ClickToDial url for user <strong>%s</strong>

+ 3 - 1
htdocs/langs/en_US/agenda.lang

@@ -53,7 +53,9 @@ MemberValidatedInDolibarr=Member %s validated
 MemberModifiedInDolibarr=Member %s modified
 MemberResiliatedInDolibarr=Member %s terminated
 MemberDeletedInDolibarr=Member %s deleted
-MemberSubscriptionAddedInDolibarr=Subscription for member %s added
+MemberSubscriptionAddedInDolibarr=Subscription %s for member %s added
+MemberSubscriptionModifiedInDolibarr=Subscription %s for member %s modified
+MemberSubscriptionDeletedInDolibarr=Subscription %s for member %s deleted
 ShipmentValidatedInDolibarr=Shipment %s validated
 ShipmentClassifyClosedInDolibarr=Shipment %s classified billed
 ShipmentUnClassifyCloseddInDolibarr=Shipment %s classified reopened

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

@@ -157,6 +157,7 @@ RulesResultDue=- It includes outstanding invoices, expenses, VAT, donations whet
 RulesResultInOut=- It includes the real payments made on invoices, expenses, VAT and salaries. <br>- It is based on the payment dates of the invoices, expenses, VAT and salaries. The donation date for donation.
 RulesCADue=- It includes the client's due invoices whether they are paid or not. <br>- It is based on the validation date of these invoices.<br>
 RulesCAIn=- It includes all the effective payments of invoices received from clients.<br>- It is based on the payment date of these invoices<br>
+RulesCATotalSaleJournal=It includes all credit lines from the Sale journal.
 RulesAmountOnInOutBookkeepingRecord=It includes record in your Ledger with accounting accounts that has the group "EXPENSE" or "INCOME"
 RulesResultBookkeepingPredefined=It includes record in your Ledger with accounting accounts that has the group "EXPENSE" or "INCOME"
 RulesResultBookkeepingPersonalized=It show record in your Ledger with accounting accounts <b>grouped by personalized groups</b>

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

@@ -430,6 +430,9 @@ ActionsOnCompany=Events about this third party
 ActionsOnMember=Events about this member
 ActionsOnProduct=Events about this product
 NActionsLate=%s late
+ToDo=To do
+Completed=Completed
+Running=In progress
 RequestAlreadyDone=Request already recorded
 Filter=Filter
 FilterOnInto=Search criteria '<strong>%s</strong>' into fields %s 
@@ -707,6 +710,8 @@ WarningYouAreInMaintenanceMode=Warning, you are in a maintenance mode, so only l
 CoreErrorTitle=System error
 CoreErrorMessage=Sorry, an error occurred. Contact your system administrator to check the logs or disable $dolibarr_main_prod=1 to get more information.
 CreditCard=Credit card
+ValidatePayment=Validate payment
+CreditOrDebitCard=Credit or debit card
 FieldsWithAreMandatory=Fields with <b>%s</b> are mandatory
 FieldsWithIsForPublic=Fields with <b>%s</b> are shown on public list of members. If you don't want this, check off the "public" box.
 AccordingToGeoIPDatabase=(according to GeoIP convertion)

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

@@ -80,8 +80,8 @@ LinkedObject=Linked object
 NbOfActiveNotifications=Number of notifications (nb of recipient emails)
 PredefinedMailTest=__(Hello)__\nThis is a test mail sent to __EMAIL__.\nThe two lines are separated by a carriage return.\n\n__USER_SIGNATURE__
 PredefinedMailTestHtml=__(Hello)__\nThis is a <b>test</b> mail (the word test must be in bold).<br>The two lines are separated by a carriage return.<br><br>__USER_SIGNATURE__
-PredefinedMailContentSendInvoice=__(Hello)__\n\nYou will find here the invoice __REF__\n\n__ONLINE_PAYMENT_URL__\n\n__(Sincerely)__\n\n__USER_SIGNATURE__
-PredefinedMailContentSendInvoiceReminder=__(Hello)__\n\nWe would like to warn you that the invoice  __REF__ seems to not be payed. So this is the invoice in attachment again, as a reminder.\n\n__ONLINE_PAYMENT_URL__\n\n__(Sincerely)__\n\n__USER_SIGNATURE__
+PredefinedMailContentSendInvoice=__(Hello)__\n\nYou will find here the invoice __REF__\n\nThis is the link to make your online payment if this invoice is not already payed:\n__ONLINE_PAYMENT_URL__\n\n__(Sincerely)__\n\n__USER_SIGNATURE__
+PredefinedMailContentSendInvoiceReminder=__(Hello)__\n\nWe would like to warn you that the invoice  __REF__ seems to not be payed. So this is the invoice in attachment again, as a reminder.\n\nThis is the link to make your online payment:\n__ONLINE_PAYMENT_URL__\n\n__(Sincerely)__\n\n__USER_SIGNATURE__
 PredefinedMailContentSendProposal=__(Hello)__\n\nYou will find here the commercial proposal __PREF__\n\n\n__(Sincerely)__\n\n__USER_SIGNATURE__
 PredefinedMailContentSendSupplierProposal=__(Hello)__\n\nYou will find here the price request __REF__\n\n\n__(Sincerely)__\n\n__USER_SIGNATURE__
 PredefinedMailContentSendOrder=__(Hello)__\n\nYou will find here the order __REF__\n\n\n__(Sincerely)__\n\n__USER_SIGNATURE__

+ 3 - 1
htdocs/langs/en_US/paypal.lang

@@ -30,4 +30,6 @@ ErrorCode=Error Code
 ErrorSeverityCode=Error Severity Code
 OnlinePaymentSystem=Online payment system
 PaypalLiveEnabled=Paypal live enabled (otherwise test/sandbox mode)
-PaypalImportPayment=Import Paypal payments
+PaypalImportPayment=Import Paypal payments
+PostActionAfterPayment=Post actions after payments
+ARollbackWasPerformedOnPostActions=A rollback was performed on all Post actions. You must complete post actions manually if they are necessary.

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

@@ -38,4 +38,5 @@ STRIPE_TEST_PUBLISHABLE_KEY=Publishable test key
 STRIPE_LIVE_SECRET_KEY=Secret live key
 STRIPE_LIVE_PUBLISHABLE_KEY=Publishable live key
 StripeLiveEnabled=Stripe live enabled (otherwise test/sandbox mode)
-StripeImportPayment=Import Stripe payments
+StripeImportPayment=Import Stripe payments
+ExampleOfTestCreditCard=Example of credit card for test: %s (valid), %s (error CVC), %s (expired), %s (charge fails)

+ 2 - 2
htdocs/langs/fr_FR/accountancy.lang

@@ -224,8 +224,8 @@ GeneralLedgerSomeRecordWasNotRecorded=Certaines des opérations n'ont pu être e
 NoNewRecordSaved=Plus d'enregistrements à journaliser
 ListOfProductsWithoutAccountingAccount=Liste des produits non liés à un compte comptable
 ChangeBinding=Changer les liens
-Accounted=Comptabilisé dans le grand livre
-NotYetAccounted=Pas encore comptabilisé dans le grand livre
+Accounted=Comptabilisé
+NotYetAccounted=Pas encore comptabilisé
 
 ## Admin
 ApplyMassCategories=Application en masse des catégories

+ 2 - 2
htdocs/langs/fr_FR/other.lang

@@ -78,8 +78,8 @@ LinkedObject=Objet lié
 NbOfActiveNotifications=Nombre de notifications (nb de destinataires emails)
 PredefinedMailTest=__(Hello)__,\nCeci est un mail de test envoyé à __EMAIL__.\nLes deux lignes sont séparées par un saut de ligne.\n\n__USER_SIGNATURE__
 PredefinedMailTestHtml=__(Hello)__\nCeci est un message de <b>test</b> (le mot test doit être en gras).<br>Les 2 lignes sont séparées par un retour à la ligne.<br><br>__SIGNATURE__
-PredefinedMailContentSendInvoice=__(Hello)__\n\nVeuillez trouver, ci-joint, la facture __REF__\n\n__ONLINE_PAYMENT_URL__\n\n__(Sincerely)__\n\n__USER_SIGNATURE__
-PredefinedMailContentSendInvoiceReminder=__(Hello)__\n\nNous voulons porter à votre connaissance le fait que la facture __REF__ semble non payée. Aussi, voici la facture à nouveau en pièce jointe pour rappel.\n\n__ONLINE_PAYMENT_URL__\n\n__(Sincerely)__\n\n__USER_SIGNATURE__
+PredefinedMailContentSendInvoice=__(Hello)__\n\nVeuillez trouver, ci-joint, la facture __REF__\n\nVoici le lien pour un paiement en ligne au cas ou celle-ci n'aurait pas encore été payé:\n\n__ONLINE_PAYMENT_URL__\n\n__(Sincerely)__\n\n__USER_SIGNATURE__
+PredefinedMailContentSendInvoiceReminder=__(Hello)__\n\nNous voulons porter à votre connaissance le fait que la facture __REF__ semble non payée. Aussi, voici la facture à nouveau en pièce jointe pour rappel.\n\nVoici le lien pour un paiement en ligne:\n__ONLINE_PAYMENT_URL__\n\n__(Sincerely)__\n\n__USER_SIGNATURE__
 PredefinedMailContentSendProposal=__(Hello)__\n\nVeuillez trouver, ci-joint, la proposition commerciale __PREF__\n\n\n__(Sincerely)__\n\n__USER_SIGNATURE__
 PredefinedMailContentSendSupplierProposal=__(Hello)__\n\nVeuillez trouver, ci-joint, une demande de prix avec la référence __REF__\n\n\n__(Sincerely)__\n\n__USER_SIGNATURE__
 PredefinedMailContentSendOrder=__(Hello)__\n\nVeuillez trouver, ci-joint, la commande __REF__\n\n\n__(Sincerely)__\n\n__USER_SIGNATURE__

+ 11 - 0
htdocs/paybox/admin/paybox.php

@@ -55,6 +55,8 @@ if ($action == 'setvalue' && $user->admin)
 	$result=dolibarr_set_const($db, "PAYBOX_PBX_IDENTIFIANT",GETPOST('PAYBOX_PBX_IDENTIFIANT','alpha'),'chaine',0,'',$conf->entity);
 	if (! $result > 0) $error++;
     $result=dolibarr_set_const($db, "ONLINE_PAYMENT_CREDITOR",GETPOST('ONLINE_PAYMENT_CREDITOR','alpha'),'chaine',0,'',$conf->entity);
+    if (! $result > 0) $error++;
+    $result=dolibarr_set_const($db, "PAYBOX_BANK_ACCOUNT_FOR_PAYMENTS",GETPOST('PAYBOX_BANK_ACCOUNT_FOR_PAYMENTS','int'),'chaine',0,'',$conf->entity);
     if (! $result > 0) $error++;
 	$result=dolibarr_set_const($db, "ONLINE_PAYMENT_CSS_URL",GETPOST('ONLINE_PAYMENT_CSS_URL','alpha'),'chaine',0,'',$conf->entity);
 	if (! $result > 0) $error++;
@@ -183,6 +185,15 @@ print '<br>'.$langs->trans("Example").': '.$mysoc->name;
 print '</td></tr>';
 
 
+if (! empty($conf->banque->enabled))
+{
+	print '<tr class="oddeven"><td>';
+	print $langs->trans("BankAccount").'</td><td>';
+	print $form->select_comptes($conf->global->PAYBOX_BANK_ACCOUNT_FOR_PAYMENTS, 'PAYBOX_BANK_ACCOUNT_FOR_PAYMENTS', 0, '', 1);
+	print '</td></tr>';
+}
+
+
 print '<tr class="oddeven"><td>';
 print $langs->trans("CSSUrlForPaymentForm").'</td><td>';
 print '<input size="64" type="text" name="ONLINE_PAYMENT_CSS_URL" value="'.$conf->global->ONLINE_PAYMENT_CSS_URL.'">';

+ 9 - 0
htdocs/paypal/admin/paypal.php

@@ -55,6 +55,8 @@ if ($action == 'setvalue' && $user->admin)
     if (! $result > 0) $error++;
     $result=dolibarr_set_const($db, "ONLINE_PAYMENT_CREDITOR",GETPOST('ONLINE_PAYMENT_CREDITOR','alpha'),'chaine',0,'',$conf->entity);
     if (! $result > 0) $error++;
+    $result=dolibarr_set_const($db, "PAYPAL_BANK_ACCOUNT_FOR_PAYMENTS",GETPOST('PAYPAL_BANK_ACCOUNT_FOR_PAYMENTS','int'),'chaine',0,'',$conf->entity);
+    if (! $result > 0) $error++;
     $result=dolibarr_set_const($db, "PAYPAL_API_INTEGRAL_OR_PAYPALONLY",GETPOST('PAYPAL_API_INTEGRAL_OR_PAYPALONLY','alpha'),'chaine',0,'',$conf->entity);
     if (! $result > 0) $error++;
     $result=dolibarr_set_const($db, "ONLINE_PAYMENT_CSS_URL",GETPOST('ONLINE_PAYMENT_CSS_URL','alpha'),'chaine',0,'',$conf->entity);
@@ -210,6 +212,13 @@ print '<input size="64" type="text" name="ONLINE_PAYMENT_CREDITOR" value="'.$con
 print ' &nbsp; '.$langs->trans("Example").': '.$mysoc->name;
 print '</td></tr>';
 
+if (! empty($conf->banque->enabled))
+{
+	print '<tr class="oddeven"><td>';
+	print $langs->trans("BankAccount").'</td><td>';
+	print $form->select_comptes($conf->global->PAYPAL_BANK_ACCOUNT_FOR_PAYMENTS, 'PAYPAL_BANK_ACCOUNT_FOR_PAYMENTS', 0, '', 1);
+	print '</td></tr>';
+}
 
 print '<tr class="oddeven"><td>';
 print $langs->trans("CSSUrlForPaymentForm").'</td><td>';

+ 87 - 29
htdocs/paypal/lib/paypal.lib.php

@@ -192,7 +192,7 @@ function getPaypalPaymentUrl($mode,$type,$ref='',$amount='9.99',$freetag='your_f
  * @param  	string	$returnURL			Url to use if payment is OK
  * @param   string	$cancelURL			Url to use if payment is KO
  * @param   string	$tag				Full tag
- * @return	void
+ * @return	string						No return (a redirect is done) if OK, or Error message if KO
  */
 function print_paypal_redirect($paymentAmount,$currencyCodeType,$paymentType,$returnURL,$cancelURL,$tag)
 {
@@ -272,11 +272,20 @@ function print_paypal_redirect($paymentAmount,$currencyCodeType,$paymentType,$re
         $ErrorLongMsg = urldecode($resArray["L_LONGMESSAGE0"]);
         $ErrorSeverityCode = urldecode($resArray["L_SEVERITYCODE0"]);
 
-        echo $langs->trans('SetExpressCheckoutAPICallFailed') . "<br>\n";
-        echo $langs->trans('DetailedErrorMessage') . ": " . $ErrorLongMsg."<br>\n";
-        echo $langs->trans('ShortErrorMessage') . ": " . $ErrorShortMsg."<br>\n";
-        echo $langs->trans('ErrorCode') . ": " . $ErrorCode."<br>\n";
-        echo $langs->trans('ErrorSeverityCode') . ": " . $ErrorSeverityCode."<br>\n";
+        if ($ErrorCode == 10729)
+        {
+        	$mesg.= "PayPal can't accept payments for this thirdparty. An address is defined but is not complete (missing State).<br>Ask system administrator to fix address or to setup Paypal module to accept payments even on not complete addresses (remove option PAYPAL_REQUIRE_VALID_SHIPPING_ADDRESS).<br>\n";
+        }
+        else
+        {
+        	$mesg = $langs->trans('SetExpressCheckoutAPICallFailed') . "<br>\n";
+        	$mesg.= $langs->trans('DetailedErrorMessage') . ": " . $ErrorLongMsg."<br>\n";
+        	$mesg.= $langs->trans('ShortErrorMessage') . ": " . $ErrorShortMsg."<br>\n";
+        	$mesg.= $langs->trans('ErrorCode') . ": " . $ErrorCode."<br>\n";
+        	$mesg.= $langs->trans('ErrorSeverityCode') . ": " . $ErrorSeverityCode."<br>\n";
+        }
+
+        return $mesg;
     }
 
 }
@@ -300,6 +309,7 @@ function print_paypal_redirect($paymentAmount,$currencyCodeType,$paymentType,$re
  *      phoneNum:           the phoneNum  entered on the merchant's site
  *      email:              the buyer email
  *      desc:               Product description
+ * See https://developer.paypal.com/docs/classic/api/merchant/SetExpressCheckout_API_Operation_NVP/
  *
  * @param 	double 			$paymentAmount		Payment amount
  * @param 	string 			$currencyCodeType	Currency
@@ -307,8 +317,8 @@ function print_paypal_redirect($paymentAmount,$currencyCodeType,$paymentType,$re
  * @param 	string 			$returnURL			Return Url
  * @param 	string 			$cancelURL			Cancel Url
  * @param 	string 			$tag				Full tag
- * @param 	string 			$solutionType		Type
- * @param 	string 			$landingPage		Landing page
+ * @param 	string 			$solutionType		Type ('Mark' or 'Sole')
+ * @param 	string 			$landingPage		Landing page ('Login' or 'Billing')
  * @param	string			$shipToName			Ship to name
  * @param	string			$shipToStreet		Ship to street
  * @param	string			$shipToCity			Ship to city
@@ -327,38 +337,86 @@ function callSetExpressCheckout($paymentAmount, $currencyCodeType, $paymentType,
     // Construct the parameter string that describes the SetExpressCheckout API call in the shortcut implementation
 
     //declaring of global variables
-    global $conf, $langs;
+    global $conf, $langs, $mysoc;
     global $API_Endpoint, $API_Url, $API_version, $USE_PROXY, $PROXY_HOST, $PROXY_PORT;
     global $PAYPAL_API_USER, $PAYPAL_API_PASSWORD, $PAYPAL_API_SIGNATURE;
 
     $nvpstr = '';
-    $nvpstr = $nvpstr . "&AMT=". urlencode($paymentAmount);                // AMT deprecated by paypal -> PAYMENTREQUEST_n_AMT
-    $nvpstr = $nvpstr . "&PAYMENTACTION=" . urlencode($paymentType);       // PAYMENTACTION deprecated by paypal -> PAYMENTREQUEST_n_PAYMENTACTION
+    //$nvpstr = $nvpstr . "&VERSION=".$API_version;				// Already added by hash_call
     $nvpstr = $nvpstr . "&RETURNURL=" . urlencode($returnURL);
     $nvpstr = $nvpstr . "&CANCELURL=" . urlencode($cancelURL);
-    $nvpstr = $nvpstr . "&CURRENCYCODE=" . urlencode($currencyCodeType);    // CURRENCYCODE deprecated by paypal -> PAYMENTREQUEST_n_CURRENCYCODE
-    $nvpstr = $nvpstr . "&ADDROVERRIDE=1";
-    //$nvpstr = $nvpstr . "&ALLOWNOTE=0";
-    $nvpstr = $nvpstr . "&SHIPTONAME=" . urlencode($shipToName);            // SHIPTONAME deprecated by paypal -> PAYMENTREQUEST_n_SHIPTONAME
-    $nvpstr = $nvpstr . "&SHIPTOSTREET=" . urlencode($shipToStreet);        //
-    $nvpstr = $nvpstr . "&SHIPTOSTREET2=" . urlencode($shipToStreet2);
-    $nvpstr = $nvpstr . "&SHIPTOCITY=" . urlencode($shipToCity);
-    $nvpstr = $nvpstr . "&SHIPTOSTATE=" . urlencode($shipToState);
-    $nvpstr = $nvpstr . "&SHIPTOCOUNTRYCODE=" . urlencode($shipToCountryCode);
-    $nvpstr = $nvpstr . "&SHIPTOZIP=" . urlencode($shipToZip);
-    $nvpstr = $nvpstr . "&PHONENUM=" . urlencode($phoneNum);
+    if (! empty($conf->global->PAYPAL_ALLOW_NOTES))
+    {
+    	$nvpstr = $nvpstr . "&ALLOWNOTE=0";
+    }
+    if (empty($conf->global->PAYPAL_REQUIRE_VALID_SHIPPING_ADDRESS))
+    {
+    	$nvpstr = $nvpstr . "&NOSHIPPING=1";	// An empty or not complete shipping address will be accepted
+    }
+    else
+    {
+    	$nvpstr = $nvpstr . "&NOSHIPPING=0";	// A valid shipping address is required (full required fields mandatory)
+    }
     $nvpstr = $nvpstr . "&SOLUTIONTYPE=" . urlencode($solutionType);
     $nvpstr = $nvpstr . "&LANDINGPAGE=" . urlencode($landingPage);
-    //$nvpstr = $nvpstr . "&CUSTOMERSERVICENUMBER=" . urlencode($tag);    // Hotline phone number
-    $nvpstr = $nvpstr . "&INVNUM=" . urlencode($tag);
-    if (! empty($email)) $nvpstr = $nvpstr . "&EMAIL=" . urlencode($email);
-    if (! empty($desc))  $nvpstr = $nvpstr . "&DESC=" . urlencode($desc);        // DESC deprecated by paypal -> PAYMENTREQUEST_n_DESC
+    if (! empty($conf->global->PAYPAL_CUSTOMER_SERVICE_NUMBER))
+    {
+    	$nvpstr = $nvpstr . "&CUSTOMERSERVICENUMBER=" . urlencode($conf->global->PAYPAL_CUSTOMER_SERVICE_NUMBER);    // Hotline phone number
+    }
+
+    $paypalprefix = 'PAYMENTREQUEST_0_';
+    //$paypalprefix = '';
+	if (! empty($paypalprefix) && $paymentType == 'Sole') $paymentType='Sale';
+
+	$nvpstr = $nvpstr . "&AMT=". urlencode($paymentAmount);									// Total for all elements
+
+    $nvpstr = $nvpstr . "&".$paypalprefix."INVNUM=" . urlencode($tag);
+    $nvpstr = $nvpstr . "&".$paypalprefix."AMT=". urlencode($paymentAmount);                 // AMT deprecated by paypal -> PAYMENTREQUEST_n_AMT
+    $nvpstr = $nvpstr . "&".$paypalprefix."ITEMAMT=". urlencode($paymentAmount);             // AMT deprecated by paypal -> PAYMENTREQUEST_n_AMT
+    $nvpstr = $nvpstr . "&".$paypalprefix."PAYMENTACTION=" . urlencode($paymentType);        // PAYMENTACTION deprecated by paypal -> PAYMENTREQUEST_n_PAYMENTACTION
+    $nvpstr = $nvpstr . "&".$paypalprefix."CURRENCYCODE=" . urlencode($currencyCodeType);    // CURRENCYCODE deprecated by paypal -> PAYMENTREQUEST_n_CURRENCYCODE
+
+    $nvpstr = $nvpstr . "&".$paypalprefix."L_PAYMENTREQUEST_0_QTY0=1";
+    $nvpstr = $nvpstr . "&".$paypalprefix."L_PAYMENTREQUEST_0_AMT0=".urlencode($paymentAmount);
+    $nvpstr = $nvpstr . "&".$paypalprefix."L_PAYMENTREQUEST_0_NAME0=".urlencode($desc);
+    $nvpstr = $nvpstr . "&".$paypalprefix."L_PAYMENTREQUEST_0_NUMBER0=0";
+
+    $nvpstr = $nvpstr . "&".$paypalprefix."SHIPTONAME=" . urlencode($shipToName);            // SHIPTONAME deprecated by paypal -> PAYMENTREQUEST_n_SHIPTONAME
+    $nvpstr = $nvpstr . "&".$paypalprefix."SHIPTOSTREET=" . urlencode($shipToStreet);        //
+    $nvpstr = $nvpstr . "&".$paypalprefix."SHIPTOSTREET2=" . urlencode($shipToStreet2);
+    $nvpstr = $nvpstr . "&".$paypalprefix."SHIPTOCITY=" . urlencode($shipToCity);
+    $nvpstr = $nvpstr . "&".$paypalprefix."SHIPTOSTATE=" . urlencode($shipToState);
+    $nvpstr = $nvpstr . "&".$paypalprefix."SHIPTOCOUNTRYCODE=" . urlencode($shipToCountryCode);
+    $nvpstr = $nvpstr . "&".$paypalprefix."SHIPTOZIP=" . urlencode($shipToZip);
+    $nvpstr = $nvpstr . "&".$paypalprefix."PHONENUM=" . urlencode($phoneNum);
+    if (! empty($email)) $nvpstr = $nvpstr . "&".$paypalprefix."EMAIL=" . urlencode($email);      // EMAIL deprecated by paypal -> PAYMENTREQUEST_n_EMAIL
+    if (! empty($desc))  $nvpstr = $nvpstr . "&".$paypalprefix."DESC=" . urlencode($desc);        // DESC deprecated by paypal -> PAYMENTREQUEST_n_DESC
+
+    if (! empty($conf->global->PAYPAL_LOGOIMG) && $mysoc->logo)
+    {
+    	global $dolibarr_main_url_root;
 
+	    // Define $urlwithroot
+	    $urlwithouturlroot=preg_replace('/'.preg_quote(DOL_URL_ROOT,'/').'$/i','',trim($dolibarr_main_url_root));
+	    $urlwithroot=$urlwithouturlroot.DOL_URL_ROOT;		// This is to use external domain name found into config file
+	    //$urlwithroot=DOL_MAIN_URL_ROOT;					// This is to use same domain name than current
+
+	    $urllogo=$urlwithroot."/viewimage.php?modulepart=mycompany&file=".$mysoc->logo;
+	    $nvpstr = $nvpstr . "&LOGOIMG=" . urlencode($urllogo);
+    }
+    if (! empty($conf->global->PAYPAL_BRANDNAME))
+    {
+    	$nvpstr = $nvpstr . "&BRANDNAME=" . urlencode($conf->global->PAYPAL_BRANDNAME);    // BRANDNAME
+    }
+    if (! empty($conf->global->PAYPAL_NOTETOBUYER))
+    {
+    	$nvpstr = $nvpstr . "&NOTETOBUYER=" . urlencode($conf->global->PAYPAL_NOTETOBUYER);  // PAYPAL_NOTETOBUYER
+    }
 
 	$_SESSION["FinalPaymentAmt"] = $paymentAmount;
     $_SESSION["currencyCodeType"] = $currencyCodeType;
-    $_SESSION["PaymentType"] = $paymentType;
-    $_SESSION['ipaddress'] = $_SERVER['REMOTE_ADDR '];  // Payer ip
+    $_SESSION["PaymentType"] = $paymentType;			// 'Mark', 'Sole'
+    $_SESSION['ipaddress'] = $_SERVER['REMOTE_ADDR'];   // Payer ip
 
     //'---------------------------------------------------------------------------------------------------------------
     //' Make the API call to PayPal
@@ -534,7 +592,7 @@ function hash_call($methodName,$nvpStr)
     global $PAYPAL_API_USER, $PAYPAL_API_PASSWORD, $PAYPAL_API_SIGNATURE;
 
     // TODO problem with triggers
-    $API_version="56";
+    $API_version="98.0";
 	if (! empty($conf->global->PAYPAL_API_SANDBOX) || GETPOST('forcesandbox','alpha'))		// We can force sand box with param 'forcesandbox'
 	{
 	    $API_Endpoint = "https://api-3t.sandbox.paypal.com/nvp";

+ 24 - 4
htdocs/product/stock/mouvement.php

@@ -101,8 +101,9 @@ $arrayfields=array(
     'm.inventorycode'=>array('label'=>$langs->trans("InventoryCodeShort"), 'checked'=>1),
     'm.label'=>array('label'=>$langs->trans("LabelMovement"), 'checked'=>1),
     'origin'=>array('label'=>$langs->trans("Origin"), 'checked'=>1),
-    'm.value'=>array('label'=>$langs->trans("Qty"), 'checked'=>1),
-	//'m.datec'=>array('label'=>$langs->trans("DateCreation"), 'checked'=>0, 'position'=>500),
+	'm.value'=>array('label'=>$langs->trans("Qty"), 'checked'=>1),
+	'm.price'=>array('label'=>$langs->trans("UnitPurchaseValue"), 'checked'=>0),
+		//'m.datec'=>array('label'=>$langs->trans("DateCreation"), 'checked'=>0, 'position'=>500),
     //'m.tms'=>array('label'=>$langs->trans("DateModificationShort"), 'checked'=>0, 'position'=>500)
 );
 
@@ -417,7 +418,7 @@ if (!empty($conf->projet->enabled)) $formproject=new FormProjets($db);
 $sql = "SELECT p.rowid, p.ref as product_ref, p.label as produit, p.fk_product_type as type, p.entity,";
 $sql.= " e.ref as stock, e.rowid as entrepot_id, e.lieu,";
 $sql.= " m.rowid as mid, m.value as qty, m.datem, m.fk_user_author, m.label, m.inventorycode, m.fk_origin, m.origintype,";
-$sql.= " m.batch,";
+$sql.= " m.batch, m.price,";
 $sql.= " pl.rowid as lotid, pl.eatby, pl.sellby,";
 $sql.= " u.login, u.photo, u.lastname, u.firstname";
 // Add fields from extrafields
@@ -634,7 +635,7 @@ if ($resql)
     /*                                                                            */
     /* ************************************************************************** */
 
-    if (empty($action) && $id > 0)
+    if ((empty($action) || $action == 'list') && $id > 0)
     {
         print "<div class=\"tabsAction\">\n";
 
@@ -810,8 +811,17 @@ if ($resql)
 	    print '<input class="flat" type="text" size="4" name="search_qty" value="'.dol_escape_htmltag($search_qty).'">';
 	    print '</td>';
     }
+    if (! empty($arrayfields['m.price']['checked']))
+    {
+    	// Price
+    	print '<td class="liste_titre" align="left">';
+    	print '&nbsp; ';
+    	print '</td>';
+    }
+	
     // Extra fields
     include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_input.tpl.php';
+  
 	// Fields from hook
 	$parameters=array('arrayfields'=>$arrayfields);
 	$reshook=$hookmanager->executeHooks('printFieldListOption',$parameters);    // Note that $action and $object may have been modified by hook
@@ -849,8 +859,11 @@ if ($resql)
     if (! empty($arrayfields['m.label']['checked']))            print_liste_field_titre($arrayfields['m.label']['label'],$_SERVER["PHP_SELF"], "m.label","",$param,"",$sortfield,$sortorder);
     if (! empty($arrayfields['origin']['checked']))             print_liste_field_titre($arrayfields['origin']['label'],$_SERVER["PHP_SELF"], "","",$param,"",$sortfield,$sortorder);
     if (! empty($arrayfields['m.value']['checked']))            print_liste_field_titre($arrayfields['m.value']['label'],$_SERVER["PHP_SELF"], "m.value","",$param,'align="right"',$sortfield,$sortorder);
+    if (! empty($arrayfields['m.price']['checked']))            print_liste_field_titre($arrayfields['m.price']['label'],$_SERVER["PHP_SELF"], "m.price","",$param,'align="right"',$sortfield,$sortorder);
+    
     // Extra fields
     include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_title.tpl.php';
+
 	// Hook fields
 	$parameters=array('arrayfields'=>$arrayfields);
     $reshook=$hookmanager->executeHooks('printFieldListTitle',$parameters);    // Note that $action and $object may have been modified by hook
@@ -976,6 +989,13 @@ if ($resql)
 	        print $objp->qty;
 	        print '</td>';
         }
+        if (! empty($arrayfields['m.price']['checked']))
+        {
+        	// Price
+        	print '<td align="right">';
+        	print price($objp->price);
+        	print '</td>';
+        }
         // Action column
         print '<td class="nowrap" align="center">';
         if ($massactionbutton || $massaction)   // If we are in select mode (massactionbutton defined) or if we have already selected and sent an action ($massaction) defined

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

@@ -68,8 +68,8 @@ if (empty($conf) || ! is_object($conf))
 		print '<tr>';
 		if ($object->element == 'product')
 		{
-			print '<td width="20%" class="fieldrequired">'.$langs->trans("Warehouse").'</td>';
-			print '<td width="30%">';
+			print '<td class="fieldrequired">'.$langs->trans("Warehouse").'</td>';
+			print '<td>';
 			print $formproduct->selectWarehouses((GETPOST("dwid")?GETPOST("dwid",'int'):(GETPOST('id_entrepot')?GETPOST('id_entrepot','int'):'ifone')), 'id_entrepot', 'warehouseopen,warehouseinternal', 1, 0, 0, '', 0, 0, null, 'minwidth100');
     		print ' &nbsp; <select name="mouvement" id="mouvement">';
     		print '<option value="0">'.$langs->trans("Add").'</option>';
@@ -79,28 +79,28 @@ if (empty($conf) || ! is_object($conf))
 		}
 		if ($object->element == 'stock')
 		{
-			print '<td width="20%" class="fieldrequired" colspan="2">'.$langs->trans("Product").'</td>';
-	        print '<td width="30%">';
-	        print $form->select_produits(GETPOST('product_id'), 'product_id', (empty($conf->global->STOCK_SUPPORTS_SERVICES)?'0':''), 20, 0, -1);
+			print '<td class="fieldrequired">'.$langs->trans("Product").'</td>';
+	        print '<td>';
+	        print $form->select_produits(GETPOST('product_id'), 'product_id', (empty($conf->global->STOCK_SUPPORTS_SERVICES)?'0':''), 20, 0, -1, 2, '', 0, null, 0, 1, 0, 'maxwidth500');
     		print ' &nbsp; <select name="mouvement" id="mouvement">';
     		print '<option value="0">'.$langs->trans("Add").'</option>';
     		print '<option value="1"'.(GETPOST('mouvement')?' selected="selected"':'').'>'.$langs->trans("Delete").'</option>';
     		print '</select>';
 	        print '</td>';
 		}
-		print '<td width="20%" class="fieldrequired">'.$langs->trans("NumberOfUnit").'</td>';
-		print '<td width="30%"><input name="nbpiece" id="nbpiece" size="10" value="'.GETPOST("nbpiece").'"></td>';
+		print '<td class="fieldrequired">'.$langs->trans("NumberOfUnit").'</td>';
+		print '<td><input name="nbpiece" id="nbpiece" size="10" value="'.GETPOST("nbpiece").'"></td>';
 		print '</tr>';
 
 		// Purchase price
 		print '<tr>';
-		print '<td width="25%">'.$langs->trans("UnitPurchaseValue").'</td>';
+		print '<td>'.$langs->trans("UnitPurchaseValue").'</td>';
 		print '<td colspan="'.(!empty($conf->projet->enabled) ? '1' : '3').'"><input name="unitprice" id="unitprice" size="10" value="'.GETPOST("unitprice").'"></td>';
 		if (! empty($conf->projet->enabled))
 		{
 			print '<td>'.$langs->trans('Project').'</td>';
 			print '<td>';
-			$formproject->select_projects();
+			$formproject->select_projects(0, '', 'projectid', 0, 0, 1, 0, 0, 0, 0, '', 0, 0, 'maxwidth300');
 			print '</td>';
 		}
 		print '</tr>';
@@ -133,7 +133,7 @@ if (empty($conf) || ! is_object($conf))
 		print '<tr>';
 		print '<td>'.$langs->trans("MovementLabel").'</td>';
 		print '<td>';
-		print '<input type="text" name="label" size="60" value="'.$valformovementlabel.'">';
+		print '<input type="text" name="label" class="minwidth300" value="'.$valformovementlabel.'">';
 		print '</td>';
 		print '<td>'.$langs->trans("InventoryCode").'</td><td><input class="maxwidth100onsmartphone" name="inventorycode" id="inventorycode" value="'.(isset($_POST["inventorycode"])?GETPOST("inventorycode",'alpha'):dol_print_date(dol_now(),'%y%m%d%H%M%S')).'"></td>';
 		print '</tr>';

+ 9 - 9
htdocs/product/stock/tpl/stocktransfer.tpl.php

@@ -72,20 +72,20 @@ if (empty($conf) || ! is_object($conf))
 		print '<tr>';
 		if ($object->element == 'product')
 		{
-		    print '<td width="20%" class="fieldrequired">'.$langs->trans("WarehouseSource").'</td>';
-		    print '<td width="30%">';
+		    print '<td class="fieldrequired">'.$langs->trans("WarehouseSource").'</td>';
+		    print '<td>';
 		    print $formproduct->selectWarehouses((GETPOST("dwid")?GETPOST("dwid",'int'):(GETPOST('id_entrepot')?GETPOST('id_entrepot','int'):'ifone')), 'id_entrepot', 'warehouseopen,warehouseinternal', 1);
 		    print '</td>';
 		}
 		if ($object->element == 'stock')
 		{
-		    print '<td width="20%" class="fieldrequired">'.$langs->trans("Product").'</td>';
-		    print '<td width="30%">';
-		    print $form->select_produits(GETPOST('product_id'),'product_id',(empty($conf->global->STOCK_SUPPORTS_SERVICES)?'0':''));
+		    print '<td class="fieldrequired">'.$langs->trans("Product").'</td>';
+		    print '<td>';
+		    print $form->select_produits(GETPOST('product_id'), 'product_id', (empty($conf->global->STOCK_SUPPORTS_SERVICES)?'0':''), 20, 0, -1, 2, '', 0, null, 0, 1, 0, 'maxwidth500');
 		    print '</td>';
 		}
 
-		print '<td width="20%" class="fieldrequired">'.$langs->trans("WarehouseTarget").'</td><td width="30%">';
+		print '<td class="fieldrequired">'.$langs->trans("WarehouseTarget").'</td><td>';
 		print $formproduct->selectWarehouses(GETPOST('id_entrepot_destination'), 'id_entrepot_destination', 'warehouseopen,warehouseinternal', 1);
 		print '</td></tr>';
 		print '<tr><td class="fieldrequired">'.$langs->trans("NumberOfUnit").'</td><td colspan="3"><input type="text" name="nbpiece" size="10" value="'.dol_escape_htmltag(GETPOST("nbpiece")).'"></td>';
@@ -125,11 +125,11 @@ if (empty($conf) || ! is_object($conf))
 		// Label
 		$valformovementlabel=(GETPOST("label")?GETPOST("label"):$langs->trans("MovementTransferStock", $productref));
 		print '<tr>';
-		print '<td width="15%">'.$langs->trans("MovementLabel").'</td>';
+		print '<td>'.$langs->trans("MovementLabel").'</td>';
 		print '<td>';
-		print '<input type="text" name="label" size="60" value="'.dol_escape_htmltag($valformovementlabel).'">';
+		print '<input type="text" name="label" class="minwidth300" value="'.dol_escape_htmltag($valformovementlabel).'">';
 		print '</td>';
-		print '<td width="15%">'.$langs->trans("InventoryCode").'</td><td><input class="maxwidth100onsmartphone" name="inventorycode" id="inventorycode" value="'.(isset($_POST["inventorycode"])?GETPOST("inventorycode",'alpha'):dol_print_date(dol_now(),'%y%m%d%H%M%S')).'"></td>';
+		print '<td>'.$langs->trans("InventoryCode").'</td><td><input class="maxwidth100onsmartphone" name="inventorycode" id="inventorycode" value="'.(isset($_POST["inventorycode"])?GETPOST("inventorycode",'alpha'):dol_print_date(dol_now(),'%y%m%d%H%M%S')).'"></td>';
 		print '</tr>';
 
 		print '</table>';

+ 20 - 16
htdocs/projet/class/task.class.php

@@ -1696,7 +1696,7 @@ class Task extends CommonObject
 	 */
 	function getLibStatut($mode=0)
 	{
-		return $this->LibStatut($this->fk_statut,$mode);
+		return $this->LibStatut($this->fk_statut, $mode);
 	}
 
 	/**
@@ -1706,18 +1706,18 @@ class Task extends CommonObject
 	 *	@param	integer		$mode		0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto
 	 * 	@return	string	  				Label
 	 */
-	function LibStatut($statut,$mode=0)
+	function LibStatut($statut, $mode=0)
 	{
 		// list of Statut of the task
 		$this->statuts[0]='Draft';
-		$this->statuts[1]='Validated';
+		$this->statuts[1]='ToDo';
 		$this->statuts[2]='Running';
 		$this->statuts[3]='Finish';
 		$this->statuts[4]='Transfered';
 		$this->statuts_short[0]='Draft';
-		$this->statuts_short[1]='Validated';
+		$this->statuts_short[1]='ToDo';
 		$this->statuts_short[2]='Running';
-		$this->statuts_short[3]='Finish';
+		$this->statuts_short[3]='Completed';
 		$this->statuts_short[4]='Transfered';
 
 		global $langs;
@@ -1735,7 +1735,7 @@ class Task extends CommonObject
 			if ($statut==0) return img_picto($langs->trans($this->statuts_short[$statut]),'statut0').' '.$langs->trans($this->statuts_short[$statut]);
 			if ($statut==1) return img_picto($langs->trans($this->statuts_short[$statut]),'statut1').' '.$langs->trans($this->statuts_short[$statut]);
 			if ($statut==2) return img_picto($langs->trans($this->statuts_short[$statut]),'statut3').' '.$langs->trans($this->statuts_short[$statut]);
-			if ($statut==3) return img_picto($langs->trans($this->statuts_short[$statut]),'statut4').' '.$langs->trans($this->statuts_short[$statut]);
+			if ($statut==3) return img_picto($langs->trans($this->statuts_short[$statut]),'statut6').' '.$langs->trans($this->statuts_short[$statut]);
 			if ($statut==4) return img_picto($langs->trans($this->statuts_short[$statut]),'statut6').' '.$langs->trans($this->statuts_short[$statut]);
 			if ($statut==5) return img_picto($langs->trans($this->statuts_short[$statut]),'statut5').' '.$langs->trans($this->statuts_short[$statut]);
 		}
@@ -1744,7 +1744,7 @@ class Task extends CommonObject
 			if ($statut==0) return img_picto($langs->trans($this->statuts_short[$statut]),'statut0');
 			if ($statut==1) return img_picto($langs->trans($this->statuts_short[$statut]),'statut1');
 			if ($statut==2) return img_picto($langs->trans($this->statuts_short[$statut]),'statut3');
-			if ($statut==3) return img_picto($langs->trans($this->statuts_short[$statut]),'statut4');
+			if ($statut==3) return img_picto($langs->trans($this->statuts_short[$statut]),'statut6');
 			if ($statut==4) return img_picto($langs->trans($this->statuts_short[$statut]),'statut6');
 			if ($statut==5) return img_picto($langs->trans($this->statuts_short[$statut]),'statut5');
 		}
@@ -1753,27 +1753,31 @@ class Task extends CommonObject
 			if ($statut==0) return img_picto($langs->trans($this->statuts_short[$statut]),'statut0').' '.$langs->trans($this->statuts[$statut]);
 			if ($statut==1) return img_picto($langs->trans($this->statuts_short[$statut]),'statut1').' '.$langs->trans($this->statuts[$statut]);
 			if ($statut==2) return img_picto($langs->trans($this->statuts_short[$statut]),'statut3').' '.$langs->trans($this->statuts[$statut]);
-			if ($statut==3) return img_picto($langs->trans($this->statuts_short[$statut]),'statut4').' '.$langs->trans($this->statuts[$statut]);
+			if ($statut==3) return img_picto($langs->trans($this->statuts_short[$statut]),'statut6').' '.$langs->trans($this->statuts[$statut]);
 			if ($statut==4) return img_picto($langs->trans($this->statuts_short[$statut]),'statut6').' '.$langs->trans($this->statuts[$statut]);
 			if ($statut==5) return img_picto($langs->trans($this->statuts_short[$statut]),'statut5').' '.$langs->trans($this->statuts[$statut]);
 		}
 		if ($mode == 5)
 		{
-			if ($statut==0) return $langs->trans($this->statuts_short[$statut]).' '.img_picto($langs->trans($this->statuts_short[$statut]),'statut0');
+			/*if ($statut==0) return $langs->trans($this->statuts_short[$statut]).' '.img_picto($langs->trans($this->statuts_short[$statut]),'statut0');
 			if ($statut==1) return $langs->trans($this->statuts_short[$statut]).' '.img_picto($langs->trans($this->statuts_short[$statut]),'statut1');
 			if ($statut==2) return $langs->trans($this->statuts_short[$statut]).' '.img_picto($langs->trans($this->statuts_short[$statut]),'statut3');
-			if ($statut==3) return $langs->trans($this->statuts_short[$statut]).' '.img_picto($langs->trans($this->statuts_short[$statut]),'statut4');
+			if ($statut==3) return $langs->trans($this->statuts_short[$statut]).' '.img_picto($langs->trans($this->statuts_short[$statut]),'statut6');
 			if ($statut==4) return $langs->trans($this->statuts_short[$statut]).' '.img_picto($langs->trans($this->statuts_short[$statut]),'statut6');
 			if ($statut==5) return $langs->trans($this->statuts_short[$statut]).' '.img_picto($langs->trans($this->statuts_short[$statut]),'statut5');
+			*/
+			//return $this->progress.' %';
+			return '&nbsp;';
 		}
 		if ($mode == 6)
 		{
-			/*if ($statut==0) return $langs->trans($this->statuts_short[$statut]).' '.img_picto($langs->trans($this->statuts_short[$statut]),'statut0');
-			if ($statut==1) return $langs->trans($this->statuts_short[$statut]).' '.img_picto($langs->trans($this->statuts_short[$statut]),'statut1');
-			if ($statut==2) return $langs->trans($this->statuts_short[$statut]).' '.img_picto($langs->trans($this->statuts_short[$statut]),'statut3');
-			if ($statut==3) return $langs->trans($this->statuts_short[$statut]).' '.img_picto($langs->trans($this->statuts_short[$statut]),'statut4');
-			if ($statut==4) return $langs->trans($this->statuts_short[$statut]).' '.img_picto($langs->trans($this->statuts_short[$statut]),'statut6');
-			if ($statut==5) return $langs->trans($this->statuts_short[$statut]).' '.img_picto($langs->trans($this->statuts_short[$statut]),'statut5');*/
+			/*if ($statut==0) return $langs->trans($this->statuts[$statut]).' '.img_picto($langs->trans($this->statuts_short[$statut]),'statut0');
+			if ($statut==1) return $langs->trans($this->statuts[$statut]).' '.img_picto($langs->trans($this->statuts_short[$statut]),'statut1');
+			if ($statut==2) return $langs->trans($this->statuts[$statut]).' '.img_picto($langs->trans($this->statuts_short[$statut]),'statut3');
+			if ($statut==3) return $langs->trans($this->statuts[$statut]).' '.img_picto($langs->trans($this->statuts_short[$statut]),'statut6');
+			if ($statut==4) return $langs->trans($this->statuts[$statut]).' '.img_picto($langs->trans($this->statuts_short[$statut]),'statut6');
+			if ($statut==5) return $langs->trans($this->statuts[$statut]).' '.img_picto($langs->trans($this->statuts_short[$statut]),'statut5');
+			*/
 			//return $this->progress.' %';
 			return '&nbsp;';
 		}

+ 1 - 1
htdocs/projet/tasks/contact.php

@@ -285,7 +285,7 @@ if ($id > 0 || ! empty($ref))
 		//$arrayofuseridoftask=$object->getListContactId('internal');
 
 		$head = task_prepare_head($object);
-		dol_fiche_head($head, 'task_contact', $langs->trans("Task"), -1, 'projecttask');
+		dol_fiche_head($head, 'task_contact', $langs->trans("Task"), -1, 'projecttask', 0, '', 'reposition');
 
 
 		$param=(GETPOST('withproject')?'&withproject=1':'');

+ 1 - 1
htdocs/projet/tasks/document.php

@@ -224,7 +224,7 @@ if ($object->id > 0)
 	}
 
 	$head = task_prepare_head($object);
-	dol_fiche_head($head, 'task_document', $langs->trans("Task"), -1, 'projecttask');
+	dol_fiche_head($head, 'task_document', $langs->trans("Task"), -1, 'projecttask', 0, '', 'reposition');
 
 	// Files list constructor
 	$filearray=dol_dir_list($upload_dir,"files",0,'','(\.meta|_preview.*\.png)$',$sortfield,(strtolower($sortorder)=='desc'?SORT_DESC:SORT_ASC),1);

+ 1 - 1
htdocs/projet/tasks/note.php

@@ -202,7 +202,7 @@ if ($object->id > 0)
 	}
 
 	$head = task_prepare_head($object);
-	dol_fiche_head($head, 'task_notes', $langs->trans('Task'), -1, 'projecttask');
+	dol_fiche_head($head, 'task_notes', $langs->trans('Task'), -1, 'projecttask', 0, '', 'reposition');
 
 
 	$param=(GETPOST('withproject')?'&withproject=1':'');

+ 3 - 3
htdocs/projet/tasks/task.php

@@ -221,7 +221,7 @@ if ($id > 0 || ! empty($ref))
 			// Tabs for project
 			$tab='tasks';
 			$head=project_prepare_head($projectstatic);
-			dol_fiche_head($head, $tab, $langs->trans("Project"), -1, ($projectstatic->public?'projectpub':'project'));
+			dol_fiche_head($head, $tab, $langs->trans("Project"), -1, ($projectstatic->public?'projectpub':'project'), 0, '', '');
 
 			$param=($mode=='mine'?'&mode=mine':'');
 
@@ -352,7 +352,7 @@ if ($id > 0 || ! empty($ref))
 			print '<input type="hidden" name="withproject" value="'.$withproject.'">';
 			print '<input type="hidden" name="id" value="'.$object->id.'">';
 
-			dol_fiche_head($head, 'task_task', $langs->trans("Task"),0,'projecttask');
+			dol_fiche_head($head, 'task_task', $langs->trans("Task"), 0, 'projecttask', 0, '', '');
 
 			print '<table class="border" width="100%">';
 
@@ -437,7 +437,7 @@ if ($id > 0 || ! empty($ref))
 			$param=($withproject?'&withproject=1':'');
 			$linkback=$withproject?'<a href="'.DOL_URL_ROOT.'/projet/tasks.php?id='.$projectstatic->id.'&restore_lastsearch_values=1">'.$langs->trans("BackToList").'</a>':'';
 
-			dol_fiche_head($head, 'task_task', $langs->trans("Task"), -1, 'projecttask');
+			dol_fiche_head($head, 'task_task', $langs->trans("Task"), -1, 'projecttask', 0, '', 'reposition');
 
 			if ($action == 'delete')
 			{

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

@@ -436,7 +436,7 @@ if (($id > 0 || ! empty($ref)) || $projectidforalltimes > 0)
 	if (empty($projectidforalltimes))
 	{
 		$head=task_prepare_head($object);
-		dol_fiche_head($head, 'task_time', $langs->trans("Task"), -1, 'projecttask');
+		dol_fiche_head($head, 'task_time', $langs->trans("Task"), -1, 'projecttask', 0, '', 'reposition');
 
 		if ($action == 'deleteline')
 		{
@@ -547,6 +547,7 @@ if (($id > 0 || ! empty($ref)) || $projectidforalltimes > 0)
 			print '<input type="hidden" name="id" value="'.$object->id.'">';
 			print '<input type="hidden" name="withproject" value="'.$withproject.'">';
 
+			print '<div class="div-table-responsive-no-min">';
 			print '<table class="noborder nohover" width="100%">';
 
 			print '<tr class="liste_titre">';
@@ -603,7 +604,10 @@ if (($id > 0 || ! empty($ref)) || $projectidforalltimes > 0)
 			print '<input type="submit" name="cancel" class="button" value="'.$langs->trans("Cancel").'">';
 			print '</td></tr>';
 
-			print '</table></form>';
+			print '</table>';
+			print '</div>';
+
+			print '</form>';
 
 			print '<br>';
 		}

+ 3 - 1
htdocs/public/members/new.php

@@ -418,10 +418,12 @@ $extrafields->fetch_name_optionals_label('adherent');    // fetch optionals attr
 llxHeaderVierge($langs->trans("NewSubscription"));
 
 
-print load_fiche_titre($langs->trans("NewSubscription"));
+print load_fiche_titre($langs->trans("NewSubscription"), '', '', 0, 0, 'center');
 
+print '<div class="center subscriptionformhelptext">';
 if (! empty($conf->global->MEMBER_NEWFORM_TEXT)) print $langs->trans($conf->global->MEMBER_NEWFORM_TEXT)."<br>\n";
 else print $langs->trans("NewSubscriptionDesc",$conf->global->MAIN_INFO_SOCIETE_MAIL)."<br>\n";
+print '</div>';
 
 dol_htmloutput_errors($errmsg);
 

+ 22 - 9
htdocs/public/payment/newpayment.php

@@ -264,6 +264,7 @@ else if (! empty($conf->global->$paramcreditor)) $creditor=$conf->global->$param
  * Actions
  */
 
+// Action dopayment is called after choosing the payment mode
 if ($action == 'dopayment')
 {
 	if ($paymentmethod == 'paypal')
@@ -284,10 +285,18 @@ if ($action == 'dopayment')
 		$desc=GETPOST("desc",'alpha');
 
 		$mesg='';
-		if (empty($PAYPAL_API_PRICE) || ! is_numeric($PAYPAL_API_PRICE))   $mesg=$langs->trans("ErrorFieldRequired",$langs->transnoentitiesnoconv("Amount"));
+		if (empty($PAYPAL_API_PRICE) || ! is_numeric($PAYPAL_API_PRICE))
+		{
+			$mesg=$langs->trans("ErrorFieldRequired",$langs->transnoentitiesnoconv("Amount"));
+			$action='';
+		}
 		//elseif (empty($EMAIL))          $mesg=$langs->trans("ErrorFieldRequired",$langs->transnoentitiesnoconv("YourEMail"));
 		//elseif (! isValidEMail($EMAIL)) $mesg=$langs->trans("ErrorBadEMail",$EMAIL);
-		elseif (! $origfulltag)        $mesg=$langs->trans("ErrorFieldRequired",$langs->transnoentitiesnoconv("PaymentCode"));
+		elseif (! $origfulltag)
+		{
+			$mesg=$langs->trans("ErrorFieldRequired",$langs->transnoentitiesnoconv("PaymentCode"));
+			$action='';
+		}
 
 		//var_dump($_POST);
 		if (empty($mesg))
@@ -310,6 +319,7 @@ if ($action == 'dopayment')
 			dol_syslog("PAYPAL_API_KO: $PAYPAL_API_KO", LOG_DEBUG);
 			dol_syslog("PAYPAL_API_PRICE: $PAYPAL_API_PRICE", LOG_DEBUG);
 			dol_syslog("PAYPAL_API_DEVISE: $PAYPAL_API_DEVISE", LOG_DEBUG);
+			// All those fields may be empty when making a payment for a free amount for example
 			dol_syslog("shipToName: $shipToName", LOG_DEBUG);
 			dol_syslog("shipToStreet: $shipToStreet", LOG_DEBUG);
 			dol_syslog("shipToCity: $shipToCity", LOG_DEBUG);
@@ -327,9 +337,10 @@ if ($action == 'dopayment')
 			//$_SESSION["FinalPaymentAmt"]=$PAYPAL_API_PRICE;
 
 			// A redirect is added if API call successfull
-			print_paypal_redirect($PAYPAL_API_PRICE,$PAYPAL_API_DEVISE,$PAYPAL_PAYMENT_TYPE,$PAYPAL_API_OK,$PAYPAL_API_KO, $FULLTAG);
+			$mesg = print_paypal_redirect($PAYPAL_API_PRICE,$PAYPAL_API_DEVISE,$PAYPAL_PAYMENT_TYPE,$PAYPAL_API_OK,$PAYPAL_API_KO, $FULLTAG);
 
-			exit;
+			// If we are here, it means the Paypal redirect was not done, so we show error message
+			$action = '';
 		}
 	}
 
@@ -379,10 +390,12 @@ if ($action == 'dopayment')
 // Called when choosing Stripe mode, after the 'dopayment'
 if ($action == 'charge')
 {
+	$amountstripe = $amount;
+
 	// Correct the amount according to unit of currency
 	// See https://support.stripe.com/questions/which-zero-decimal-currencies-does-stripe-support
 	$arrayzerounitcurrency=array('BIF', 'CLP', 'DJF', 'GNF', 'JPY', 'KMF', 'KRW', 'MGA', 'PYG', 'RWF', 'VND', 'VUV', 'XAF', 'XOF', 'XPF');
-	if (! in_array($currency, $arrayzerounitcurrency)) $amount=$amount * 100;
+	if (! in_array($currency, $arrayzerounitcurrency)) $amountstripe=$amountstripe * 100;
 
 	dol_syslog("POST keys  : ".join(',', array_keys($_POST)), LOG_DEBUG, 0, '_stripe');
 	dol_syslog("POST values: ".join(',', $_POST), LOG_DEBUG, 0, '_stripe');
@@ -411,7 +424,7 @@ if ($action == 'charge')
 		dol_syslog("Create charge", LOG_DEBUG, 0, '_stripe');
 		$charge = \Stripe\Charge::create(array(
 		'customer' => $customer->id,
-		'amount'   => price2num($amount, 'MU'),
+		'amount'   => price2num($amountstripe, 'MU'),
 		'currency' => $currency,
 		'description' => 'Stripe payment: '.$FULLTAG,
 		'metadata' => array("FULLTAG" => $FULLTAG, 'Recipient' => $mysoc->name),
@@ -850,7 +863,7 @@ if ($source == 'invoice')
 	print '</td></tr>'."\n";
 
 	// Amount
-	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("Amount");
+	print '<tr class="CTableRow'.($var?'1':'2').'"><td class="CTableRow'.($var?'1':'2').'">'.$langs->trans("PaymentAmount");
 	if (empty($amount) && empty($object->paye)) print ' ('.$langs->trans("ToComplete").')';
 	print '</td><td class="CTableRow'.($var?'1':'2').'">';
 	if (empty($object->paye))
@@ -1432,7 +1445,7 @@ if (preg_match('/^dopayment/',$action))
 
 	    <div class="form-row left">
 	    <label for="card-element">
-	    Credit or debit card
+	    '.$langs->trans("CreditOrDebitCard").'
 	    </label>
 	    <div id="card-element">
 	    <!-- a Stripe Element will be inserted here. -->
@@ -1442,7 +1455,7 @@ if (preg_match('/^dopayment/',$action))
 	    <div id="card-errors" role="alert"></div>
 	    </div>
 	    <br>
-	    <button class="button" id="buttontopay">'.$langs->trans("ToPay").'</button>
+	    <button class="butAction" id="buttontopay">'.$langs->trans("ValidatePayment").'</button>
 	    <img id="hourglasstopay" class="hidden" src="'.DOL_URL_ROOT.'/theme/'.$conf->theme.'/img/working.gif'.'">
 	    </td></tr></tbody></table>
 

+ 362 - 40
htdocs/public/payment/paymentok.php

@@ -44,13 +44,7 @@ if (! empty($conf->paypal->enabled))
 	require_once DOL_DOCUMENT_ROOT.'/paypal/lib/paypalfunctions.lib.php';
 }
 
-$langs->load("main");
-$langs->load("other");
-$langs->load("dict");
-$langs->load("bills");
-$langs->load("companies");
-$langs->load("paybox");
-$langs->load("paypal");
+$langs->loadLangs(array("main","other","dict","bills","companies","paybox","paypal"));
 
 // Clean parameters
 if (! empty($conf->paypal->enabled))
@@ -130,6 +124,8 @@ $object = new stdClass();   // For triggers
  * View
  */
 
+$now = dol_now();
+
 dol_syslog("Callback url when a payment was done. query_string=".(dol_escape_htmltag($_SERVER["QUERY_STRING"])?dol_escape_htmltag($_SERVER["QUERY_STRING"]):'')." script_uri=".(dol_escape_htmltag($_SERVER["SCRIPT_URI"])?dol_escape_htmltag($_SERVER["SCRIPT_URI"]):''), LOG_DEBUG, 0, '_payment');
 
 $tracepost = "";
@@ -183,7 +179,7 @@ if ($urllogo)
 
 if (! empty($conf->paypal->enabled))
 {
-	if ($paymentmethod == 'paypal')
+	if ($paymentmethod == 'paypal')							// We call this page only if payment is ok on payment system
 	{
 		if ($PAYPALTOKEN)
 		{
@@ -251,28 +247,308 @@ if (! empty($conf->paypal->enabled))
 
 if (! empty($conf->paybox->enabled))
 {
-	if ($paymentmethod == 'paybox') $ispaymentok = true;	// We call this page only if payment is ok
+	if ($paymentmethod == 'paybox') $ispaymentok = true;	// We call this page only if payment is ok on payment system
 }
 
 if (! empty($conf->stripe->enabled))
 {
-	if ($paymentmethod == 'stripe') $ispaymentok = true;	// We call this page only if payment is ok
+	if ($paymentmethod == 'stripe') $ispaymentok = true;	// We call this page only if payment is ok on payment system
 }
 
 
+// If data not provided from back url, search them into the session env
+if (empty($ipaddress))       $ipaddress       = $_SESSION['ipaddress'];
+if (empty($TRANSACTIONID))   $TRANSACTIONID   = $_SESSION['TRANSACTIONID'];
+if (empty($FinalPaymentAmt)) $FinalPaymentAmt = $_SESSION["FinalPaymentAmt"];
+if (empty($paymentType))     $paymentType     = $_SESSION["paymentType"];
+
+$fulltag            = $FULLTAG;
+$tmptag=dolExplodeIntoArray($fulltag,'.','=');
+
+
+// Make complementary actions
+$ispostactionok = 0;
+$postactionmessages = array();
+if ($ispaymentok)
+{
+	// Set permission for the anonymous user
+	if (empty($user->rights->societe))  $user->rights->societe=new stdClass();
+	if (empty($user->rights->facture))  $user->rights->facture=new stdClass();
+	if (empty($user->rights->adherent)) { $user->rights->adherent=new stdClass(); $user->rights->adherent->cotisation=new stdClass(); }
+	$user->rights->societe->creer = 1;
+	$user->rights->facture->creer = 1;
+	$user->rights->adherent->cotisation->creer = 1;
+
+	if (in_array('MEM', array_keys($tmptag)))
+	{
+		$defaultdelay=1;
+		$defaultdelayunit='y';
+
+		// Record subscription
+		include_once DOL_DOCUMENT_ROOT.'/adherents/class/adherent.class.php';
+		include_once DOL_DOCUMENT_ROOT.'/adherents/class/adherent_type.class.php';
+		include_once DOL_DOCUMENT_ROOT.'/adherents/class/subscription.class.php';
+		$adht = new AdherentType($db);
+		$object = new Adherent($db);
+
+		$result1 = $object->fetch(0, $tmptag['MEM']);
+		$result2 = $adht->fetch($object->typeid);
+
+		if ($result1 > 0 && $result2 > 0)
+		{
+			$paymentTypeId = 0;
+			if ($paymentmethod == 'paybox') $paymentTypeId = $conf->global->PAYBOX_PAYMENT_MODE_FOR_PAYMENTS;
+			if ($paymentmethod == 'paypal') $paymentTypeId = $conf->global->PAYPAL_PAYMENT_MODE_FOR_PAYMENTS;
+			if ($paymentmethod == 'stripe') $paymentTypeId = $conf->global->STRIPE_PAYMENT_MODE_FOR_PAYMENTS;
+			if (empty($paymentTypeId))
+			{
+				$paymentType = $_SESSION["paymentType"];
+				if (empty($paymentType)) $paymentType = 'CB';
+				$paymentTypeId = dol_getIdFromCode($db, $paymentType, 'c_paiement', 'code', 'id', 1);
+			}
+
+			$currencyCodeType   = $_SESSION['currencyCodeType'];
+
+			// Do action only if $FinalPaymentAmt is set (session variable is cleaned after this page to avoid duplicate actions when page is POST a second time)
+			if (! empty($FinalPaymentAmt) && $paymentTypeId > 0)
+			{
+				// Subscription informations
+				$datesubscription=$object->datevalid;
+				if ($object->datefin > 0)
+				{
+					$datesubscription=dol_time_plus_duree($object->datefin,1,'d');
+				}
+				$datesubend=dol_time_plus_duree(dol_time_plus_duree($datesubscription,$defaultdelay,$defaultdelayunit),-1,'d');
+				$paymentdate=$now;
+				$amount = $FinalPaymentAmt;
+				$label='Online subscription '.dol_print_date($now, 'standard').' using '.$paymentmethod.' from '.$ipaddress.' - Transaction ID = '.$TRANSACTIONID;
+
+				// Payment informations
+				$accountid = 0;
+				if ($paymentmethod == 'paybox') $accountid = $conf->global->PAYBOX_BANK_ACCOUNT_FOR_PAYMENTS;
+				if ($paymentmethod == 'paypal') $accountid = $conf->global->PAYPAL_BANK_ACCOUNT_FOR_PAYMENTS;
+				if ($paymentmethod == 'stripe') $accountid = $conf->global->STRIPE_BANK_ACCOUNT_FOR_PAYMENTS;
+				$operation=$paymentType; // Payment mode code
+				$num_chq='';
+				$emetteur_nom='';
+				$emetteur_banque='';
+				// Define default choice for complementary actions
+				$option='';
+				if (! empty($conf->global->ADHERENT_BANK_USE) && $conf->global->ADHERENT_BANK_USE == 'bankviainvoice' && ! empty($conf->banque->enabled) && ! empty($conf->societe->enabled) && ! empty($conf->facture->enabled)) $option='bankviainvoice';
+				else if (! empty($conf->global->ADHERENT_BANK_USE) && $conf->global->ADHERENT_BANK_USE == 'bankdirect' && ! empty($conf->banque->enabled)) $option='bankdirect';
+				else if (! empty($conf->global->ADHERENT_BANK_USE) && $conf->global->ADHERENT_BANK_USE == 'invoiceonly' && ! empty($conf->banque->enabled) && ! empty($conf->societe->enabled) && ! empty($conf->facture->enabled)) $option='invoiceonly';
+				if (empty($option)) $option='none';
+				$sendalsoemail = 1;
+
+				// Record the subscription then complementary actions
+				$db->begin();
+
+				// Create subscription
+				$crowid=$object->subscription($datesubscription, $amount, $accountid, $operation, $label, $num_chq, $emetteur_nom, $emetteur_banque, $datesubend);
+				if ($crowid <= 0)
+				{
+					$error++;
+					$errmsg=$object->error;
+					$postactionmessages[] = $errmsg;
+					$ispostactionok = -1;
+				}
+				else
+				{
+					$postactionmessages[]='Subscription created';
+					$ispostactionok=1;
+				}
+
+				if (! $error)
+				{
+					$result = $object->subscriptionComplementaryActions($crowid, $option, $accountid, $datesubscription, $paymentdate, $operation, $label, $amount, $num_chq, $emetteur_nom, $emetteur_banque, 1);
+					if ($result < 0)
+					{
+						$error++;
+						$postactionmessages[] = $object->error;
+						$postactionmessages = array_merge($postactionmessages, $object->errors);
+						$ispostactionok = -1;
+					}
+					else
+					{
+						if ($option == 'bankviainvoice') $postactionmessages[] = 'Invoice, payment and bank record created';
+						if ($option == 'bankdirect')     $postactionmessages[] = 'Bank record created';
+						if ($option == 'invoiceonly')    $postactionmessages[] = 'Invoice recorded';
+						$ispostactionok = 1;
+					}
+				}
+
+				if (! $error)
+				{
+					$db->commit();
+				}
+				else
+				{
+					$db->rollback();
+				}
+
+				// Send email
+				if (! $error)
+				{
+					// Send confirmation Email
+					if ($object->email && $sendalsoemail)
+					{
+						$subjecttosend=$object->makeSubstitution($conf->global->ADHERENT_MAIL_COTIS_SUBJECT);
+						$texttosend=$object->makeSubstitution($adht->getMailOnSubscription());
+
+						$result=$object->send_an_email($texttosend,$subjecttosend,array(),array(),array(),"","",0,-1);
+						if ($result < 0)
+						{
+							$errmsg=$object->error;
+							$postactionmessages[] = $errmsg;
+							$ispostactionok = -1;
+						}
+					}
+				}
+			}
+			else
+			{
+				$postactionmessages[] = 'Failed to get a valid value for "amount paid" or "payment type" to record the payment of subscription for member '.$tmptag['MEM'];
+				$ispostactionok = -1;
+			}
+		}
+		else
+		{
+			$postactionmessages[] = 'Member '.$tmptag['MEM'].' for subscription payed was not found';
+			$ispostactionok = -1;
+		}
+	}
+	elseif (in_array('INV', array_keys($tmptag)))
+	{
+		// Record payment
+		include_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
+		$invoice = new Facture($db);
+		$result = $invoice->fetch(0, $tmptag['INV']);
+		if ($result)
+		{
+			$FinalPaymentAmt    = $_SESSION["FinalPaymentAmt"];
+
+			$paymentTypeId = 0;
+			if ($paymentmethod == 'paybox') $paymentTypeId = $conf->global->PAYBOX_PAYMENT_MODE_FOR_PAYMENTS;
+			if ($paymentmethod == 'paypal') $paymentTypeId = $conf->global->PAYPAL_PAYMENT_MODE_FOR_PAYMENTS;
+			if ($paymentmethod == 'stripe') $paymentTypeId = $conf->global->STRIPE_PAYMENT_MODE_FOR_PAYMENTS;
+			if (empty($paymentTypeId))
+			{
+				$paymentType = $_SESSION["paymentType"];
+				if (empty($paymentType)) $paymentType = 'CB';
+				$paymentTypeId = dol_getIdFromCode($db, $paymentType, 'c_paiement', 'code', 'id', 1);
+			}
+
+			$currencyCodeType   = $_SESSION['currencyCodeType'];
+
+			// Do action only if $FinalPaymentAmt is set (session variable is cleaned after this page to avoid duplicate actions when page is POST a second time)
+			if (! empty($FinalPaymentAmt) && $paymentTypeId > 0)
+			{
+				$db->begin();
+
+				// Creation of payment line
+				include_once DOL_DOCUMENT_ROOT.'/compta/paiement/class/paiement.class.php';
+				$paiement = new Paiement($db);
+				$paiement->datepaye     = $now;
+				if ($currencyCodeType == $conf->currency)
+				{
+					$paiement->amounts      = array($invoice->id => $FinalPaymentAmt);   // Array with all payments dispatching with invoice id
+				}
+				else
+				{
+					$paiement->multicurrency_amounts = array($invoice->id => $FinalPaymentAmt);   // Array with all payments dispatching
+
+					$postactionmessages[] = 'Payment was done in a different currency that currency expected of company';
+					$ispostactionok = -1;
+					$error++;	// Not yet supported
+				}
+				$paiement->paiementid   = $paymentTypeId;
+				$paiement->num_paiement = '';
+				$paiement->note_public  = 'Online payment '.dol_print_date($now, 'standard').' using '.$paymentmethod.' from '.$ipaddress.' - Transaction ID = '.$TRANSACTIONID;
+
+				if (! $error)
+				{
+					$paiement_id = $paiement->create($user, 1);    // This include closing invoices and regenerating documents
+					if ($paiement_id < 0)
+					{
+						$postactionmessages[] = $paiement->error.' '.join("<br>\n", $paiement->errors);
+						$ispostactionok = -1;
+						$error++;
+					}
+					else
+					{
+						$postactionmessages[] = 'Payment created';
+						$ispostactionok=1;
+					}
+				}
+
+				if (! $error && ! empty($conf->banque->enabled))
+				{
+					$bankaccountid = 0;
+					if ($paymentmethod == 'paybox') $bankaccountid = $conf->global->PAYBOX_BANK_ACCOUNT_FOR_PAYMENTS;
+					if ($paymentmethod == 'paypal') $bankaccountid = $conf->global->PAYPAL_BANK_ACCOUNT_FOR_PAYMENTS;
+					if ($paymentmethod == 'stripe') $bankaccountid = $conf->global->STRIPE_BANK_ACCOUNT_FOR_PAYMENTS;
+
+					if ($bankaccountid > 0)
+					{
+						$label='(CustomerInvoicePayment)';
+						if ($invoice->type == Facture::TYPE_CREDIT_NOTE) $label='(CustomerInvoicePaymentBack)';  // Refund of a credit note
+						$result=$paiement->addPaymentToBank($user,'payment',$label, $bankaccountid, '', '');
+						if ($result < 0)
+						{
+							$postactionmessages[] = $paiement->error.' '.joint("<br>\n", $paiement->errors);
+							$ispostactionok = -1;
+							$error++;
+						}
+						else
+						{
+							$postactionmessages[] = 'Bank entry of payment created';
+							$ispostactionok=1;
+						}
+					}
+					else
+					{
+						$postactionmessages[] = 'Setup of bank account to use in module '.$paymentmethod.' was not set. Not way to record the payment.';
+						$ispostactionok = -1;
+						$error++;
+					}
+				}
+
+				if (! $error)
+				{
+					$db->commit();
+				}
+				else
+				{
+					$db->rollback();
+				}
+			}
+			else
+			{
+				$postactionmessages[] = 'Failed to get a valid value for "amount paid" ('.$FinalPaymentAmt.') or "payment type" ('.$paymentType.') to record the payment of invoice '.$tmptag['INV'];
+				$ispostactionok = -1;
+			}
+		}
+		else
+		{
+			$postactionmessages[] = 'Invoice payed '.$tmptag['INV'].' was not found';
+			$ispostactionok = -1;
+		}
+	}
+	else
+	{
+		// Nothing done
+	}
+}
+
 if ($ispaymentok)
 {
     // Get on url call
-    $fulltag            = $FULLTAG;
     $onlinetoken        = empty($PAYPALTOKEN)?$_SESSION['onlinetoken']:$PAYPALTOKEN;
     $payerID            = empty($PAYPALPAYERID)?$_SESSION['payerID']:$PAYPALPAYERID;
     // Set by newpayment.php
     $paymentType        = $_SESSION['PaymentType'];
     $currencyCodeType   = $_SESSION['currencyCodeType'];
     $FinalPaymentAmt    = $_SESSION["FinalPaymentAmt"];
-    // From env
-    $ipaddress          = $_SESSION['ipaddress'];
-    $TRANSACTIONID      = $_SESSION['TRANSACTIONID'];
 
     // Appel des triggers
     include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php';
@@ -283,7 +559,7 @@ if ($ispaymentok)
 
 
     print $langs->trans("YourPaymentHasBeenRecorded")."<br>\n";
-    print $langs->trans("ThisIsTransactionId",$TRANSACTIONID)."<br><br>\n";
+    if ($TRANSACTIONID) print $langs->trans("ThisIsTransactionId",$TRANSACTIONID)."<br><br>\n";
 
     $key='ONLINE_PAYMENT_MESSAGE_OK';
     if (! empty($conf->global->$key)) print $conf->global->$key;
@@ -296,6 +572,10 @@ if ($ispaymentok)
 	// Send an email
     if ($sendemail)
 	{
+		$companylangs = new Translate('', $conf);
+		$companylangs->setDefaultLang($mysoc->default_lang);
+		$companylangs->loadLangs(array('main','members','bills','paypal','paybox'));
+
 		$sendto=$sendemail;
 		$from=$conf->global->MAILING_EMAIL_FROM;
 		// Define $urlwithroot
@@ -317,25 +597,60 @@ if ($ispaymentok)
 		else $appli.=" ".DOL_VERSION;
 
 		$urlback=$_SERVER["REQUEST_URI"];
-		$topic='['.$appli.'] '.$langs->transnoentitiesnoconv("NewOnlinePaymentReceived");
+		$topic='['.$appli.'] '.$companylangs->transnoentitiesnoconv("NewOnlinePaymentReceived");
 		$content="";
-		if (! empty($tmptag['MEM']))
+		if (in_array('MEM', array_keys($tmptag)))
 		{
-			$langs->load("members");
 			$url=$urlwithroot."/adherents/card_subscriptions.php?rowid=".$tmptag['MEM'];
-			$content.=$langs->trans("PaymentSubscription")."<br>\n";
-			$content.=$langs->trans("MemberId").': '.$tmptag['MEM']."<br>\n";
-			$content.=$langs->trans("Link").': <a href="'.$url.'">'.$url.'</a>'."<br>\n";
+			$content.='<strong>'.$companylangs->trans("PaymentSubscription")."</strong><br><br>\n";
+			$content.=$companylangs->trans("MemberId").': <strong>'.$tmptag['MEM']."</strong><br>\n";
+			$content.=$companylangs->trans("Link").': <a href="'.$url.'">'.$url.'</a>'."<br>\n";
+		}
+		elseif (in_array('INV', array_keys($tmptag)))
+		{
+			$url=$urlwithroot."/compta/facture/card.php?ref=".$tmptag['INV'];
+			$content.='<strong>'.$companylangs->trans("Payment")."</strong><br><br>\n";
+			$content.=$companylangs->trans("Invoice").': <strong>'.$tmptag['INV']."</strong><br>\n";
+			//$content.=$companylangs->trans("ThirdPartyId").': '.$tmptag['CUS']."<br>\n";
+			$content.=$companylangs->trans("Link").': <a href="'.$url.'">'.$url.'</a>'."<br>\n";
 		}
 		else
 		{
-			$content.=$langs->transnoentitiesnoconv("NewOnlinePaymentReceived")."<br>\n";
+			$content.=$companylangs->transnoentitiesnoconv("NewOnlinePaymentReceived")."<br>\n";
+		}
+		$content.=$companylangs->transnoentities("PostActionAfterPayment").' : ';
+		if ($ispostactionok > 0)
+		{
+			//$topic.=' ('.$companylangs->transnoentitiesnoconv("Status").' '.$companylangs->transnoentitiesnoconv("OK").')';
+			$content.='<font color="green">'.$companylangs->transnoentitiesnoconv("OK").'</font>';
+		}
+		elseif ($ispostactionok == 0)
+		{
+			$content.=$companylangs->transnoentitiesnoconv("None");
+		}
+		else
+		{
+			$topic.=($ispostactionok ? '' : ' ('.$companylangs->trans("WarningPostActionErrorAfterPayment").')');
+			$content.='<font color="red">'.$companylangs->transnoentitiesnoconv("Error").'</font>';
+		}
+		$content.='<br>'."\n";
+		foreach($postactionmessages as $postactionmessage)
+		{
+			$content.=' * '.$postactionmessage.'<br>'."\n";
+		}
+		if ($ispostactionok < 0)
+		{
+			$content.= $langs->transnoentities("ARollbackWasPerformedOnPostActions");
 		}
+		$content.='<br>'."\n";
+
 		$content.="<br>\n";
-		$content.=$langs->transnoentitiesnoconv("TechnicalInformation").":<br>\n";
-		$content.=$langs->transnoentitiesnoconv("OnlinePaymentSystem").': '.$paymentmethod."<br>\n";
-		$content.=$langs->transnoentitiesnoconv("ReturnURLAfterPayment").': '.$urlback."<br>\n";
-		$content.="tag=".$fulltag."\ntoken=".$onlinetoken." paymentType=".$paymentType." currencycodeType=".$currencyCodeType." payerId=".$payerID." ipaddress=".$ipaddress." FinalPaymentAmt=".$FinalPaymentAmt;
+		$content.='<u>'.$companylangs->transnoentitiesnoconv("TechnicalInformation").":</u><br>\n";
+		$content.=$companylangs->transnoentitiesnoconv("OnlinePaymentSystem").': <strong>'.$paymentmethod."</strong><br>\n";
+		$content.=$companylangs->transnoentitiesnoconv("ThisIsTransactionId").': <strong>'.$TRANSACTIONID."</strong><br>\n";
+		$content.=$companylangs->transnoentitiesnoconv("ReturnURLAfterPayment").': '.$urlback."<br>\n";
+		$content.="<br>\n";
+		$content.="tag=".$fulltag."<br>\ntoken=".$onlinetoken."<br>\npaymentType=".$paymentType."<br>\ncurrencycodeType=".$currencyCodeType."<br>\npayerId=".$payerID."<br>\nipaddress=".$ipaddress."<br>\nFinalPaymentAmt=".$FinalPaymentAmt."<br>\n";
 
 		$ishtml=dol_textishtml($content);	// May contain urls
 
@@ -356,15 +671,12 @@ if ($ispaymentok)
 else
 {
     // Get on url call
-    $fulltag            = $FULLTAG;
-    $onlinetoken        = empty($PAYPALTOKEN)?$_SESSION['onlinetoken']:$PAYPALTOKEN;
+	$onlinetoken        = empty($PAYPALTOKEN)?$_SESSION['onlinetoken']:$PAYPALTOKEN;
     $payerID            = empty($PAYPALPAYERID)?$_SESSION['payerID']:$PAYPALPAYERID;
     // Set by newpayment.php
     $paymentType        = $_SESSION['PaymentType'];
     $currencyCodeType   = $_SESSION['currencyCodeType'];
     $FinalPaymentAmt    = $_SESSION["FinalPaymentAmt"];
-    // From env
-    $ipaddress          = $_SESSION['ipaddress'];
 
     // Appel des triggers
     include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php';
@@ -389,12 +701,14 @@ else
     if ($paymentmethod == 'paybox' && ! empty($conf->global->PAYBOX_PAYONLINE_SENDEMAIL)) $sendemail=$conf->global->PAYBOX_PAYONLINE_SENDEMAIL;
     if ($paymentmethod == 'stripe' && ! empty($conf->global->STRIPE_PAYONLINE_SENDEMAIL)) $sendemail=$conf->global->STRIPE_PAYONLINE_SENDEMAIL;
 
-    $tmptag=dolExplodeIntoArray($fulltag,'.','=');
-
     // Send an email
     if ($sendemail)
     {
-        $sendto=$sendemail;
+    	$companylangs = new Translate('', $conf);
+    	$companylangs->setDefaultLang($mysoc->default_lang);
+    	$companylangs->loadLangs(array('main','members','bills','paypal','paybox'));
+
+    	$sendto=$sendemail;
         $from=$conf->global->MAILING_EMAIL_FROM;
         // Define $urlwithroot
         $urlwithouturlroot=preg_replace('/'.preg_quote(DOL_URL_ROOT,'/').'$/i','',trim($dolibarr_main_url_root));
@@ -415,14 +729,17 @@ else
         else $appli.=" ".DOL_VERSION;
 
         $urlback=$_SERVER["REQUEST_URI"];
-        $topic='['.$appli.'] '.$langs->transnoentitiesnoconv("ValidationOfPaymentFailed");
+        $topic='['.$appli.'] '.$companylangs->transnoentitiesnoconv("ValidationOfPaymentFailed");
         $content="";
-        $content.=$langs->transnoentitiesnoconv("PaymentSystemConfirmPaymentPageWasCalledButFailed")."\n";
-        $content.="\n";
-        $content.=$langs->transnoentitiesnoconv("TechnicalInformation").":\n";
-		$content.=$langs->transnoentitiesnoconv("OnlinePaymentSystem").': '.$paymentmethod."\n";
-        $content.=$langs->transnoentitiesnoconv("ReturnURLAfterPayment").': '.$urlback."\n";
-        $content.="tag=".$fulltag."\ntoken=".$onlinetoken." paymentType=".$paymentType." currencycodeType=".$currencyCodeType." payerId=".$payerID." ipaddress=".$ipaddress." FinalPaymentAmt=".$FinalPaymentAmt;
+        $content.='<font color="orange">'.$companylangs->transnoentitiesnoconv("PaymentSystemConfirmPaymentPageWasCalledButFailed")."</font>\n";
+
+        $content.="<br>\n";
+        $content.='<u>'.$companylangs->transnoentitiesnoconv("TechnicalInformation").":</u><br>\n";
+        $content.=$companylangs->transnoentitiesnoconv("OnlinePaymentSystem").': <strong>'.$paymentmethod."</strong><br>\n";
+        $content.=$companylangs->transnoentitiesnoconv("ReturnURLAfterPayment").': '.$urlback."<br>\n";
+        $content.="<br>\n";
+        $content.="tag=".$fulltag."<br>\ntoken=".$onlinetoken."<br>\npaymentType=".$paymentType."<br>\ncurrencycodeType=".$currencyCodeType."<br>\npayerId=".$payerID."<br>\nipaddress=".$ipaddress."<br>\nFinalPaymentAmt=".$FinalPaymentAmt."<br>\n";
+
 
         $ishtml=dol_textishtml($content);	// May contain urls
 
@@ -448,6 +765,11 @@ print "\n</div>\n";
 htmlPrintOnlinePaymentFooter($mysoc,$langs,0,$suffix);
 
 
+// Clean session variables to avoid duplicate actions if post is resent
+unset($_SESSION["FinalPaymentAmt"]);
+unset($_SESSION["TRANSACTIONID"]);
+
+
 llxFooter('', 'public');
 
 $db->close();

+ 1 - 1
htdocs/public/paypal/newpayment.php

@@ -250,7 +250,7 @@ if (GETPOST('action','aZ09') == 'dopayment')
 	    //$_SESSION["FinalPaymentAmt"]=$PAYPAL_API_PRICE;
 
 	    // A redirect is added if API call successfull
-        print_paypal_redirect($PAYPAL_API_PRICE,$PAYPAL_API_DEVISE,$PAYPAL_PAYMENT_TYPE,$PAYPAL_API_OK,$PAYPAL_API_KO, $FULLTAG);
+        $mesg = print_paypal_redirect($PAYPAL_API_PRICE,$PAYPAL_API_DEVISE,$PAYPAL_PAYMENT_TYPE,$PAYPAL_API_OK,$PAYPAL_API_KO, $FULLTAG);
 
 		exit;
 	}

+ 1 - 1
htdocs/public/stripe/newpayment.php

@@ -1168,7 +1168,7 @@ if (preg_match('/^dopayment/',$action))
     <div id="card-errors" role="alert"></div>
     </div>
     <br>
-    <button class="button" id="buttontopay">'.$langs->trans("ToPay").'</button>
+    <button class="button" id="buttontopay">'.$langs->trans("ValidatePayment").'</button>
     <img id="hourglasstopay" class="hidden" src="'.DOL_URL_ROOT.'/theme/'.$conf->theme.'/img/working.gif'.'">
     </td></tr></tbody></table>
 

+ 23 - 25
htdocs/societe/class/societe.class.php

@@ -1169,7 +1169,7 @@ class Societe extends CommonObject
 		$sql .= ' WHERE s.entity IN ('.getEntity($this->element).')';
 		if ($rowid)     $sql .= ' AND s.rowid = '.$rowid;
 		if ($ref)       $sql .= " AND s.nom = '".$this->db->escape($ref)."'";
-		if ($ref_alias) $sql .= " AND s.nom_alias = '".$this->db->escape($nom_alias)."'";
+		if ($ref_alias) $sql .= " AND s.nom_alias = '".$this->db->escape($ref_alias)."'";
 		if ($ref_ext)   $sql .= " AND s.ref_ext = '".$this->db->escape($ref_ext)."'";
 		if ($ref_int)   $sql .= " AND s.ref_int = '".$this->db->escape($ref_int)."'";
 		if ($idprof1)   $sql .= " AND s.siren = '".$this->db->escape($idprof1)."'";
@@ -2833,10 +2833,10 @@ class Societe extends CommonObject
 
 			//Check NIF
 			if (preg_match('/(^[0-9]{8}[A-Z]{1}$)/', $string))
-			if ($num[8] == substr('TRWAGMYFPDXBNJZSQVHLCKE', substr($string, 0, 8) % 23, 1))
-			return 1;
-			else
-			return -1;
+				if ($num[8] == substr('TRWAGMYFPDXBNJZSQVHLCKE', substr($string, 0, 8) % 23, 1))
+				return 1;
+				else
+				return -1;
 
 			//algorithm checking type code CIF
 			$sum = $num[2] + $num[4] + $num[6];
@@ -2846,31 +2846,31 @@ class Societe extends CommonObject
 
 			//Chek special NIF
 			if (preg_match('/^[KLM]{1}/', $string))
-			if ($num[8] == chr(64 + $n) || $num[8] == substr('TRWAGMYFPDXBNJZSQVHLCKE', substr($string, 1, 8) % 23, 1))
-			return 1;
-			else
-			return -1;
+				if ($num[8] == chr(64 + $n) || $num[8] == substr('TRWAGMYFPDXBNJZSQVHLCKE', substr($string, 1, 8) % 23, 1))
+				return 1;
+				else
+				return -1;
 
 			//Check CIF
 			if (preg_match('/^[ABCDEFGHJNPQRSUVW]{1}/', $string))
-			if ($num[8] == chr(64 + $n) || $num[8] == substr($n, strlen($n) - 1, 1))
-			return 2;
-			else
-			return -2;
+				if ($num[8] == chr(64 + $n) || $num[8] == substr($n, strlen($n) - 1, 1))
+				return 2;
+				else
+				return -2;
 
 			//Check NIE T
 			if (preg_match('/^[T]{1}/', $string))
-			if ($num[8] == preg_match('/^[T]{1}[A-Z0-9]{8}$/', $string))
-			return 3;
-			else
-			return -3;
+				if ($num[8] == preg_match('/^[T]{1}[A-Z0-9]{8}$/', $string))
+				return 3;
+				else
+				return -3;
 
 			//Check NIE XYZ
 			if (preg_match('/^[XYZ]{1}/', $string))
-			if ($num[8] == substr('TRWAGMYFPDXBNJZSQVHLCKE', substr(str_replace(array('X','Y','Z'), array('0','1','2'), $string), 0, 8) % 23, 1))
-			return 3;
-			else
-			return -3;
+				if ($num[8] == substr('TRWAGMYFPDXBNJZSQVHLCKE', substr(str_replace(array('X','Y','Z'), array('0','1','2'), $string), 0, 8) % 23, 1))
+				return 3;
+				else
+				return -3;
 
 			//Can not be verified
 			return -4;
@@ -2894,9 +2894,6 @@ class Societe extends CommonObject
 			else {
 				return -1;
 			}
-
-			//Wrong format
-			return 0;
 		}
 
 		return $ok;
@@ -3105,6 +3102,8 @@ class Societe extends CommonObject
 	{
 		global $user,$langs;
 
+		dol_syslog(get_class($this)."::create_from_member", LOG_DEBUG);
+
 		$name = $socname?$socname:$member->societe;
 		if (empty($name)) $name=$member->getFullName($langs);
 
@@ -3137,7 +3136,6 @@ class Societe extends CommonObject
 			$sql.= " SET fk_soc=".$this->id;
 			$sql.= " WHERE rowid=".$member->id;
 
-			dol_syslog(get_class($this)."::create_from_member", LOG_DEBUG);
 			$resql=$this->db->query($sql);
 			if ($resql)
 			{

+ 13 - 1
htdocs/stripe/admin/stripe.php

@@ -56,7 +56,9 @@ if ($action == 'setvalue' && $user->admin)
 	$result=dolibarr_set_const($db, "STRIPE_LIVE_SECRET_KEY",GETPOST('STRIPE_LIVE_SECRET_KEY','alpha'),'chaine',0,'',$conf->entity);
 	if (! $result > 0) $error++;
 	$result=dolibarr_set_const($db, "ONLINE_PAYMENT_CREDITOR",GETPOST('ONLINE_PAYMENT_CREDITOR','alpha'),'chaine',0,'',$conf->entity);
-    if (! $result > 0) $error++;
+	if (! $result > 0) $error++;
+	$result=dolibarr_set_const($db, "STRIPE_BANK_ACCOUNT_FOR_PAYMENTS",GETPOST('STRIPE_BANK_ACCOUNT_FOR_PAYMENTS','int'),'chaine',0,'',$conf->entity);
+	if (! $result > 0) $error++;
 	$result=dolibarr_set_const($db, "ONLINE_PAYMENT_CSS_URL",GETPOST('ONLINE_PAYMENT_CSS_URL','alpha'),'chaine',0,'',$conf->entity);
 	if (! $result > 0) $error++;
     $result=dolibarr_set_const($db, "ONLINE_PAYMENT_MESSAGE_FORM",GETPOST('ONLINE_PAYMENT_MESSAGE_FORM','alpha'),'chaine',0,'',$conf->entity);
@@ -195,6 +197,14 @@ print '<input size="64" type="text" name="ONLINE_PAYMENT_CREDITOR" value="'.$con
 print ' &nbsp; '.$langs->trans("Example").': '.$mysoc->name;
 print '</td></tr>';
 
+if (! empty($conf->banque->enabled))
+{
+	print '<tr class="oddeven"><td>';
+	print $langs->trans("BankAccount").'</td><td>';
+	print $form->select_comptes($conf->global->STRIPE_BANK_ACCOUNT_FOR_PAYMENTS, 'STRIPE_BANK_ACCOUNT_FOR_PAYMENTS', 0, '', 1);
+	print '</td></tr>';
+}
+
 print '<tr class="oddeven"><td>';
 print $langs->trans("CSSUrlForPaymentForm").'</td><td>';
 print '<input size="64" type="text" name="ONLINE_PAYMENT_CSS_URL" value="'.$conf->global->ONLINE_PAYMENT_CSS_URL.'">';
@@ -253,6 +263,8 @@ $token='';
 
 include DOL_DOCUMENT_ROOT.'/core/tpl/onlinepaymentlinks.tpl.php';
 
+print info_admin($langs->trans("ExampleOfTestCreditCard", '4242424242424242', '4000000000000101', '4000000000000069', '4000000000000341'));
+
 if (! empty($conf->use_javascript_ajax))
 {
 	print "\n".'<script type="text/javascript">';

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

@@ -384,6 +384,7 @@ class SupplierProposal extends CommonObject
         if (empty($info_bits)) $info_bits=0;
         if (empty($rang)) $rang=0;
         if (empty($fk_parent_line) || $fk_parent_line < 0) $fk_parent_line=0;
+        if (empty($pu_ht)) $pu_ht=0;
 
         $remise_percent=price2num($remise_percent);
         $qty=price2num($qty);

+ 35 - 21
htdocs/theme/eldy/style.css.php

@@ -296,7 +296,7 @@ input, input.flat, textarea, textarea.flat, form.flat select, select, select.fla
 
 input {
     line-height: 17px;
-	padding: 4px;
+	padding: 6px;
 	padding-left: 5px;
 }
 select {
@@ -356,23 +356,24 @@ input.buttonpayment {
 	line-height: 24px;
 	padding: 8px;
 	background: none;
-	padding-left: 30px;
+	padding-left: 38px;
 	text-align: <?php echo $left; ?>;
 	border: 1px solid #ddd;
 	background-color: #eee;
 	white-space: normal;
+	box-shadow: 1px 1px 8px #bbb;
 }
 input.buttonpaymentcb {
 	background-image: url(<?php echo dol_buildpath($path.'/theme/common/credit_card.png',1) ?>);
 	background-size: 26px;
 	background-repeat: no-repeat;
-	background-position: 2px 11px;
+	background-position: 5px 11px;
 }
 input.buttonpaymentcheque {
 	background-image: url(<?php echo dol_buildpath($path.'/theme/common/cheque.png',1) ?>);
 	background-size: 24px;
 	background-repeat: no-repeat;
-	background-position: 2px 8px;
+	background-position: 5px 8px;
 }
 input.buttonpaymentpaypal {
 	background-image: url(<?php echo dol_buildpath($path.'/paypal/img/object_paypal.png',1) ?>);
@@ -833,21 +834,13 @@ div.fiche>div.tabBar>form>div.div-table-responsive {
     flex-flow: row wrap;
     justify-content: flex-start;
 }
-/*.thumbstat {
-	flex: 1 1 116px;
-}*/
+.thumbstat {
+    min-width: 150px;
+}
 .thumbstat150 {
-	flex: 1 1 170px;
+    min-width: 170px;
 }
 .thumbstat, .thumbstat150 {
-    /*
-    flex-shrink: 1;
-    flex-basis: 140px;
-	display: inline;
-    width: 100%;
-    justify-content: flex-start;
-    align-self: flex-start;
-    */
     flex-grow: 1;
     flex-shrink: 0;
     min-width: 150px;
@@ -1943,7 +1936,7 @@ img.login, img.printer, img.entity {
 	color: white;
 	font-weight: bold;
 }
-.userimgatoplogin img.userphoto {		/* size for user photo in login bar */
+.userimg.atoplogin img.userphoto, .userimgatoplogin img.userphoto {		/* size for user photo in login bar */
 	width: 16px;
     height: 16px;
     border-radius: 8px;
@@ -3095,6 +3088,20 @@ ul.noborder li:nth-child(even):not(.liste_titre) {
 .boxstatscontent {
 	padding: 3px;
 }
+.boxstatsempty {
+    width: 121px;
+    padding-left: 3px;
+    padding-right: 3px;
+    margin-left: 8px;
+    margin-right: 8px;
+}
+.boxstats150empty {
+    width: 158px;
+    padding-left: 3px;
+    padding-right: 3px;
+    margin-left: 8px;
+    margin-right: 8px;
+}
 
 @media only screen and (max-width: 767px)
 {
@@ -3122,6 +3129,10 @@ ul.noborder li:nth-child(even):not(.liste_titre) {
     .boxstats {
         width: 111px;
     }
+    .boxstatsempty {
+    	width: 111px;
+	}
+
 }
 
 .boxstats:hover {
@@ -3757,13 +3768,16 @@ table.cal_event    { border: none; border-collapse: collapse; margin-bottom: 1px
 table.cal_event td { border: none; padding-<?php print $left; ?>: 2px; padding-<?php print $right; ?>: 2px; padding-top: 0px; padding-bottom: 0px; }
 table.cal_event td.cal_event { padding: 4px 4px !important; }
 table.cal_event td.cal_event_right { padding: 4px 4px !important; }
-.cal_event a:link    { color: #111111; font-size: 11px; font-weight: normal !important; }
-.cal_event a:visited { color: #111111; font-size: 11px; font-weight: normal !important; }
-.cal_event a:active  { color: #111111; font-size: 11px; font-weight: normal !important; }
-.cal_event_busy a:hover   { color: #111111; font-size: 11px; font-weight: normal !important; color:rgba(255,255,255,.75); }
+.cal_event              { font-size: 1em; }
+.cal_event a:link       { color: #111111; font-weight: normal !important; }
+.cal_event a:visited    { color: #111111; font-weight: normal !important; }
+.cal_event a:active     { color: #111111; font-weight: normal !important; }
+.cal_event_busy a:hover { color: #111111; font-weight: normal !important; color:rgba(255,255,255,.75); }
 .cal_event_busy      { }
 .cal_peruserviewname { max-width: 140px; height: 22px; }
 
+.calendarviewcontainertr { height: 100px; }
+
 
 /* ============================================================================== */
 /*  Ajax - Liste deroulante de l'autocompletion                                   */

+ 10 - 8
htdocs/theme/md/style.css.php

@@ -153,7 +153,7 @@ if (! empty($user->conf->THEME_ELDY_ENABLE_PERSONALIZED))
     $colorbacklinepairhover=((! isset($user->conf->THEME_ELDY_USE_HOVER) || $user->conf->THEME_ELDY_USE_HOVER === '0')?'':($user->conf->THEME_ELDY_USE_HOVER === '1'?'edf4fb':$user->conf->THEME_ELDY_USE_HOVER));
 }
 
-//if (empty($colortopbordertitle1)) $colortopbordertitle1=$colorbackhmenu1;
+if (empty($colortopbordertitle1)) $colortopbordertitle1=$colorbackhmenu1;
 
 
 // Set text color to black or white
@@ -884,6 +884,7 @@ select.selectarrowonleft option {
 }
 .widthauto { width: auto; }
 .width25  { width: 25px; }
+.width75  { width: 75px; }
 .width50  { width: 50px; }
 .width75  { width: 75px; }
 .width100 { width: 100px; }
@@ -1938,7 +1939,7 @@ img.login, img.printer, img.entity {
 	color: white;
 	font-weight: bold;
 }
-.userimgatoplogin img.userphoto {		/* size for user photo in login bar */
+.userimg.atoplogin img.userphoto, .userimgatoplogin img.userphoto {		/* size for user photo in login bar */
 	border-radius: 8px;
 	width: 16px;
 	height: 16px;
@@ -3184,8 +3185,8 @@ span.dashboardlineko {
 	text-align: center;
 }
 .boxworkingboard .tdboxstats {
-	padding-left: 0px !important;
-	padding-right: 0px !important;
+	padding-left: 1px !important;
+	padding-right: 1px !important;
 }
 a.valignmiddle.dashboardlineindicator {
     line-height: 30px;
@@ -3734,10 +3735,11 @@ table.cal_event    { border: none; border-collapse: collapse; margin-bottom: 1px
 table.cal_event td { border: none; padding-<?php print $left; ?>: 2px; padding-<?php print $right; ?>: 2px; padding-top: 0px; padding-bottom: 0px; }
 table.cal_event td.cal_event { padding: 4px 4px !important; }
 table.cal_event td.cal_event_right { padding: 4px 4px !important; }
-.cal_event a:link    { color: #111111; font-size: 11px; font-weight: normal !important; }
-.cal_event a:visited { color: #111111; font-size: 11px; font-weight: normal !important; }
-.cal_event a:active  { color: #111111; font-size: 11px; font-weight: normal !important; }
-.cal_event_busy a:hover   { color: #111111; font-size: 11px; font-weight: normal !important; color:rgba(255,255,255,.75); }
+.cal_event              { font-size: 1em; }
+.cal_event a:link       { color: #111111; font-weight: normal !important; }
+.cal_event a:visited    { color: #111111; font-weight: normal !important; }
+.cal_event a:active     { color: #111111; font-weight: normal !important; }
+.cal_event_busy a:hover { color: #111111; font-weight: normal !important; color:rgba(255,255,255,.75); }
 .cal_event_busy      { }
 .cal_peruserviewname { max-width: 140px; height: 22px; }
 

+ 3 - 3
htdocs/user/class/user.class.php

@@ -2221,14 +2221,14 @@ class User extends CommonObject
 		  	$paddafterimage='';
 			if (abs($withpictoimg) == 1) $paddafterimage='style="margin-right: 3px;"';
 			// Only picto
-			if ($withpictoimg > 0) $picto='<!-- picto user --><div class="inline-block nopadding '.($morecss?' userimg'.$morecss:'').'">'.img_object('', 'user', $paddafterimage.' '.($notooltip?'':'class="classfortooltip"'), 0, 0, $notooltip?0:1).'</div>';
+			if ($withpictoimg > 0) $picto='<!-- picto user --><div class="inline-block nopadding userimg'.($morecss?' '.$morecss:'').'">'.img_object('', 'user', $paddafterimage.' '.($notooltip?'':'class="classfortooltip"'), 0, 0, $notooltip?0:1).'</div>';
 			// Picto must be a photo
-			else $picto='<!-- picto photo user --><div class="inline-block nopadding '.($morecss?' userimg'.$morecss:'').'"'.($paddafterimage?' '.$paddafterimage:'').'>'.Form::showphoto('userphoto', $this, 0, 0, 0, 'userphoto'.($withpictoimg==-3?'small':''), 'mini', 0, 1).'</div>';
+			else $picto='<!-- picto photo user --><div class="inline-block nopadding userimg'.($morecss?' '.$morecss:'').'"'.($paddafterimage?' '.$paddafterimage:'').'>'.Form::showphoto('userphoto', $this, 0, 0, 0, 'userphoto'.($withpictoimg==-3?'small':''), 'mini', 0, 1).'</div>';
 			$result.=$picto;
 		}
 		if ($withpictoimg > -2 && $withpictoimg != 2)
 		{
-			if (empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) $result.='<div class="inline-block nopadding valignmiddle'.((! isset($this->statut) || $this->statut)?'':' strikefordisabled').($morecss?' usertext'.$morecss:'').'">';
+			if (empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) $result.='<div class="inline-block nopadding valignmiddle usertext'.((! isset($this->statut) || $this->statut)?'':' strikefordisabled').($morecss?' '.$morecss:'').'">';
 			if ($mode == 'login') $result.=dol_trunc($this->login, $maxlen);
 			else $result.=$this->getFullName($langs,'',($mode == 'firstname' ? 2 : -1),$maxlen);
 			if (empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) $result.='</div>';

+ 8 - 12
htdocs/user/perms.php

@@ -176,11 +176,9 @@ $db->commit();
 // Lecture des droits utilisateurs
 $permsuser = array();
 
-$sql = "SELECT DISTINCT r.id, r.libelle, r.module";
-$sql.= " FROM ".MAIN_DB_PREFIX."rights_def as r,";
-$sql.= " ".MAIN_DB_PREFIX."user_rights as ur";
-$sql.= " WHERE ur.fk_id = r.id";
-$sql.= " AND ur.entity = ".$entity;
+$sql = "SELECT DISTINCT ur.fk_id";
+$sql.= " FROM ".MAIN_DB_PREFIX."user_rights as ur";
+$sql.= " WHERE ur.entity = ".$entity;
 $sql.= " AND ur.fk_user = ".$object->id;
 
 dol_syslog("get user perms", LOG_DEBUG);
@@ -192,7 +190,7 @@ if ($result)
 	while ($i < $num)
 	{
 		$obj = $db->fetch_object($result);
-		array_push($permsuser,$obj->id);
+		array_push($permsuser,$obj->fk_id);
 		$i++;
 	}
 	$db->free($result);
@@ -205,12 +203,10 @@ else
 // Lecture des droits groupes
 $permsgroupbyentity = array();
 
-$sql = "SELECT DISTINCT r.id, r.libelle, r.module, gu.entity";
-$sql.= " FROM ".MAIN_DB_PREFIX."rights_def as r,";
-$sql.= " ".MAIN_DB_PREFIX."usergroup_rights as gr,";
+$sql = "SELECT DISTINCT gr.fk_id, gu.entity";
+$sql.= " FROM ".MAIN_DB_PREFIX."usergroup_rights as gr,";
 $sql.= " ".MAIN_DB_PREFIX."usergroup_user as gu";
-$sql.= " WHERE gr.fk_id = r.id";
-$sql.= " AND gr.entity = ".$entity;
+$sql.= " WHERE gr.entity = ".$entity;
 $sql.= " AND gr.fk_usergroup = gu.fk_usergroup";
 $sql.= " AND gu.fk_user = ".$object->id;
 
@@ -225,7 +221,7 @@ if ($result)
 		$obj = $db->fetch_object($result);
 		if (! isset($permsgroupbyentity[$obj->entity]))
 			$permsgroupbyentity[$obj->entity] = array();
-		array_push($permsgroupbyentity[$obj->entity], $obj->id);
+		array_push($permsgroupbyentity[$obj->entity], $obj->fk_id);
 		$i++;
 	}
 	$db->free($result);

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

@@ -616,7 +616,7 @@ class Website extends CommonObject
 
 		    	// Generate the index.php page to be the home page
 		    	//-------------------------------------------------
-		    	$result = dolSaveIndexPage($pathofwebsite, $fileindex, $filetpl);
+		    	$result = dolSaveIndexPage($pathofwebsitenew, $fileindex, $filetpl);
 		    }
 		}
 

+ 1 - 0
scripts/product/migrate_picture_path.php

@@ -104,6 +104,7 @@ function migrate_product_photospath($product)
 	global $conf;
 
 	$dir = $conf->product->multidir_output[$product->entity];
+	$conf->global->PRODUCT_USE_OLD_PATH_FOR_PHOTO = 1;
 	$origin = $dir .'/'. get_exdir($product->id,2,0,0,$product,'product') . $product->id ."/photos";
 	$destin = $dir.'/'.dol_sanitizeFileName($product->ref);