Browse Source

Merge remote-tracking branch 'uptream/develop' into 6.0-stripe

Alexandre SPANGARO 8 years ago
parent
commit
16a41242d3
100 changed files with 3904 additions and 2026 deletions
  1. 3 1
      ChangeLog
  2. 28 9
      build/debian/README.howto
  3. 1 2
      htdocs/accountancy/admin/accountmodel.php
  4. 0 168
      htdocs/accountancy/admin/journals.php
  5. 0 294
      htdocs/accountancy/admin/journals_card.php
  6. 752 0
      htdocs/accountancy/admin/journals_list.php
  7. 6 2
      htdocs/accountancy/bookkeeping/card.php
  8. 2 2
      htdocs/accountancy/bookkeeping/list.php
  9. 26 22
      htdocs/accountancy/bookkeeping/listbyaccount.php
  10. 47 1
      htdocs/accountancy/class/accountancyexport.class.php
  11. 49 14
      htdocs/accountancy/class/accountingaccount.class.php
  12. 0 260
      htdocs/accountancy/class/accountingjournal.class.php
  13. 12 3
      htdocs/accountancy/class/bookkeeping.class.php
  14. 12 4
      htdocs/accountancy/customer/lines.php
  15. 7 2
      htdocs/accountancy/customer/list.php
  16. 11 5
      htdocs/accountancy/index.php
  17. 154 140
      htdocs/accountancy/journal/bankjournal.php
  18. 147 105
      htdocs/accountancy/journal/expensereportsjournal.php
  19. 153 106
      htdocs/accountancy/journal/purchasesjournal.php
  20. 140 97
      htdocs/accountancy/journal/sellsjournal.php
  21. 7 2
      htdocs/accountancy/supplier/lines.php
  22. 7 2
      htdocs/accountancy/supplier/list.php
  23. 3 3
      htdocs/adherents/subscription.php
  24. 2 3
      htdocs/admin/agenda.php
  25. 1 1
      htdocs/admin/agenda_extrafields.php
  26. 1 1
      htdocs/admin/agenda_extsites.php
  27. 3 10
      htdocs/admin/agenda_other.php
  28. 1 1
      htdocs/admin/agenda_xcal.php
  29. 1 3
      htdocs/admin/bank.php
  30. 2 1
      htdocs/admin/clicktodial.php
  31. 13 23
      htdocs/admin/company.php
  32. 4 5
      htdocs/admin/compta.php
  33. 78 33
      htdocs/admin/defaultvalues.php
  34. 14 12
      htdocs/admin/dict.php
  35. 1 1
      htdocs/admin/events.php
  36. 1 1
      htdocs/admin/expensereport.php
  37. 1 1
      htdocs/admin/expensereport_extrafields.php
  38. 3 8
      htdocs/admin/fichinter.php
  39. 0 44
      htdocs/admin/ihm.php
  40. 1 3
      htdocs/admin/loan.php
  41. 19 12
      htdocs/admin/mails_templates.php
  42. 18 0
      htdocs/admin/modulehelp.php
  43. 17 15
      htdocs/admin/modules.php
  44. 4 9
      htdocs/admin/oauth.php
  45. 47 7
      htdocs/admin/pdf.php
  46. 1 3
      htdocs/admin/perms.php
  47. 1 1
      htdocs/admin/salaries.php
  48. 57 0
      htdocs/admin/stock.php
  49. 3 4
      htdocs/admin/supplier_invoice.php
  50. 3 4
      htdocs/admin/supplier_order.php
  51. 12 15
      htdocs/admin/supplier_payment.php
  52. 1 1
      htdocs/admin/supplierinvoice_extrafields.php
  53. 1 1
      htdocs/admin/supplierinvoicedet_extrafields.php
  54. 1 1
      htdocs/admin/supplierorder_extrafields.php
  55. 1 1
      htdocs/admin/supplierorderdet_extrafields.php
  56. 14 8
      htdocs/admin/syslog.php
  57. 5 5
      htdocs/admin/taxes.php
  58. 2 2
      htdocs/admin/user.php
  59. 1 1
      htdocs/admin/usergroup.php
  60. 0 2
      htdocs/admin/websites.php
  61. 1 2
      htdocs/admin/workflow.php
  62. 2 0
      htdocs/api/class/api.class.php
  63. 1 1
      htdocs/api/class/api_login.class.php
  64. 16 5
      htdocs/bookmarks/bookmarks.lib.php
  65. 4 4
      htdocs/categories/index.php
  66. 4 6
      htdocs/comm/action/card.php
  67. 2 17
      htdocs/comm/action/index.php
  68. 2 2
      htdocs/comm/action/listactions.php
  69. 4 4
      htdocs/comm/action/pertype.php
  70. 4 5
      htdocs/comm/action/peruser.php
  71. 1 1
      htdocs/comm/mailing/card.php
  72. 27 24
      htdocs/comm/mailing/cibles.php
  73. 1 1
      htdocs/comm/mailing/class/mailing.class.php
  74. 4 1
      htdocs/comm/propal/card.php
  75. 9 7
      htdocs/comm/propal/class/api_proposals.class.php
  76. 132 104
      htdocs/comm/propal/class/propal.class.php
  77. 2 2
      htdocs/comm/propal/contact.php
  78. 4 1
      htdocs/commande/card.php
  79. 12 4
      htdocs/commande/class/commande.class.php
  80. 3 2
      htdocs/commande/contact.php
  81. 12 12
      htdocs/compta/bank/card.php
  82. 21 3
      htdocs/compta/bank/index.php
  83. 26 34
      htdocs/compta/facture/card.php
  84. 9 5
      htdocs/compta/facture/class/facture.class.php
  85. 2 2
      htdocs/compta/facture/fiche-rec.php
  86. 19 19
      htdocs/compta/paiement.php
  87. 119 112
      htdocs/compta/paiement/cheque/card.php
  88. 4 10
      htdocs/compta/paiement/cheque/index.php
  89. 55 5
      htdocs/compta/paiement/class/paiement.class.php
  90. 9 3
      htdocs/contrat/card.php
  91. 7 1
      htdocs/contrat/class/contrat.class.php
  92. 98 53
      htdocs/core/actions_massactions.inc.php
  93. 6 1
      htdocs/core/ajax/check_notifications.php
  94. 5 2
      htdocs/core/boxes/box_external_rss.php
  95. 17 6
      htdocs/core/class/commondocgenerator.class.php
  96. 10 3
      htdocs/core/class/commoninvoice.class.php
  97. 407 72
      htdocs/core/class/commonobject.class.php
  98. 3 3
      htdocs/core/class/conf.class.php
  99. 438 0
      htdocs/core/class/coreobject.class.php
  100. 500 0
      htdocs/core/class/ctyperesource.class.php

+ 3 - 1
ChangeLog

@@ -13,7 +13,9 @@ Following changes may create regression for some external modules, but were nece
 * The page compta/facture.php was renamed into compta/facture/card.php to match page naming conventions.
 * The signature of method ->delete() of class Product and PriceExpression was changed from 
   ->delete($id, notrigger) to ->delete(User, notrigger) to match standard dev rules.
-
+* Removed CommonObject::displayMarginInfos (was deprecated in 3.8). Use same method into
+  html.formmargin.class.php
+* Removed Societe::set_commnucation_level (was deprecated in 4.0). Was not used.
 
 ***** ChangeLog for 5.0.1 compared to 5.0.0 *****
 FIX: #6503: SQL error in "Last pending payment invoices"

+ 28 - 9
build/debian/README.howto

@@ -152,7 +152,7 @@ tag 729538 -moreinfo
 
 
 
-##### Testing a package into unstable env
+##### Testing a package into a chroot environment
 
 Check you have a mysql server available from another interface than "localhost".
 Set line in /etc/mysql/my.cnf if required and restart mysql
@@ -160,9 +160,11 @@ Set line in /etc/mysql/my.cnf if required and restart mysql
 [mysqld]
 bind-address           = *
 
-Create a chroot called "unstable-amd64-sbuild".
+Create a chroot called "jessie" or "unstable".
 Chroot env is stored into /srv/chroot directory.
 > sudo sbuild-createchroot --keyring=unstable /srv/chroot/unstable http://ftp.uk.debian.org/debian
+or
+> sudo sbuild-createchroot jessie /srv/chroot/jessie http://ftp.uk.debian.org/debian
 
 Pour lister les env chroot
 > schroot -l
@@ -170,8 +172,9 @@ or
 > ls /srv/chroot
 
 Puis pour se connecter et préparer l'environnement 
-> schroot -c name_of_chroot
+> schroot -c name_of_chroot  (exemple schroot -c unstable-amd64-sbuild)
 > cat /etc/debian_chroot       to check which debian branch we are into
+> apt-get install vi dialog
 > vi /usr/sbin/policy-rc.d     and replace return code 101 (not allowed) into 0 (ok)
 > apt-get update
 > apt-get upgrade
@@ -385,13 +388,14 @@ http://packages.qa.debian.org
 * Package will be into release when test will be moved as stable.
 
 
-##### Send an unblock request 
+
+##### Send an unblock request to make a full update of a stable package 
 
 Use this to move from unstable to testing.
 
 reportbug -B debian --smtphost=smtp.gmail.com:587 --smtpuser=xxxx --smtppasswd=yyyy --tls
 Choose package "release.debian.org"
-Then "unblock"
+Then usertag "unblock"
 Then name of package "dolibarr"
 Fill message, for example:
 "Please unblock package dolibarr
@@ -401,11 +405,11 @@ so it is a better solution to validate this maintenance release than applying a
 After discussion with ..., it appears that security holes are enough to request this unblock request."
 
 
-Use this to request an update of a stable package
+Use this to request an full update of a stable package
 
 reportbug -B debian --smtphost=smtp.gmail.com:587 --smtpuser=xxxx --smtppasswd=yyyy --tls
 Choose package "release.debian.org"
-Then "unblock"
+Then usertag "unblock"
 Then name of package "dolibarr"
 Fill message, for example:
 "
@@ -417,11 +421,26 @@ Pro are:
 - It fixes also stability bugs
 - Patches were already tested because deployed and used by several thousands of users.
 - It is easier for package maintener to include this official set of fixes than applying one patch after one patch for each debian report or backported each patch into a dedicated version.
-- Debian maintenance version matches with official project maintenance version (better when all fixes are not related to the way the software is packaged)
+- Debian maintenance version is inline with official project maintenance version (better when all fixes are not related to the way the software is packaged)
 Cons are: 
-- The patch include more than the only one security reported fxes
+- The patch include more than the only one security reported fixes
 
 So I just need to know if it's ok to push such a version 3.5.7 (fixes for 3.5.* branch) instead of only one fix for only the few (the only) reported debian bugs,
 since it provides more stability and is for me a more secured process.
 "
 
+##### Send an request to ask a simple fix of a stable package 
+
+Use this to ask to apply patches on a stable version.
+
+reportbug -B debian --smtphost=smtp.gmail.com:587 --smtpuser=xxxx --smtppasswd=yyyy --tls
+Choose package "release.debian.org"
+Then usertag "jessie-pu" (if tags is not available in list, choose another one, and change it later into email content text)
+Then name of package "dolibarr"
+Fill message, for example:
+"Please unblock package dolibarr
+A security error CVE-2015-3935 was reported and is fixed into package 3.5.7.
+Note that package 3.5.7 contains not only fixed for bugs reported to debian. It includes other fixes, but they are all related to stability or security,
+so it is a better solution to validate this maintenance release than applying a patch of the only CVE-2015-3935. 
+After discussion with ..., it appears that security holes are enough to request this unblock request."
+

+ 1 - 2
htdocs/accountancy/admin/accountmodel.php

@@ -757,8 +757,7 @@ if ($id)
         {
         	print '<tr><td colspan="8">* '.$langs->trans("AvailableVariables").": ";
         	require_once DOL_DOCUMENT_ROOT.'/core/class/html.formmail.class.php';
-        	$formmail=new FormMail($db);
-        	$tmp=$formmail->getAvailableSubstitKey('form');
+        	$tmp=FormMail::getAvailableSubstitKey('formemail');
         	print implode(', ', $tmp);
         	print '</td></tr>';
         }

+ 0 - 168
htdocs/accountancy/admin/journals.php

@@ -1,168 +0,0 @@
-<?php
-/* Copyright (C) 2017		Alexandre Spangaro   <aspangaro@zendsi.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-/**
- * \file		htdocs/accountancy/admin/journals.php
- * \ingroup		Advanced accountancy
- * \brief		Setup page to configure journals
- */
-require '../../main.inc.php';
-require_once DOL_DOCUMENT_ROOT . '/core/lib/admin.lib.php';
-require_once DOL_DOCUMENT_ROOT . '/core/lib/accounting.lib.php';
-require_once DOL_DOCUMENT_ROOT . '/accountancy/class/accountingjournal.class.php';
-
-$action = GETPOST('action');
-
-// Load variable for pagination
-$limit = GETPOST("limit")?GETPOST("limit","int"):$conf->liste_limit;
-$sortfield = GETPOST('sortfield','alpha');
-$sortorder = GETPOST('sortorder','alpha');
-$page = GETPOST('page','int');
-if ($page == -1) { $page = 0; }
-$offset = $limit * $page;
-$pageprev = $page - 1;
-$pagenext = $page + 1;
-if (! $sortfield) $sortfield="j.rowid"; // Set here default search field
-if (! $sortorder) $sortorder="ASC";
-
-$langs->load("admin");
-$langs->load("compta");
-$langs->load("accountancy");
-
-// Security check
-if ($user->societe_id > 0)
-	accessforbidden();
-if (! $user->rights->accounting->fiscalyear)              // If we can read accounting records, we shoul be able to see fiscal year.
-    accessforbidden();
-	
-$error = 0;
-
-// List of status
-/*
-static $tmptype2label = array (
-		'0' => 'AccountingJournalTypeVariousOperation',
-		'1' => 'AccountingJournalTypeSale',
-		'2' => 'AccountingJournalTypePurchase',
-		'3' => 'AccountingJournalTypeBank',
-		'9' => 'AccountingJournalTypeHasNew'
-);
-$type2label = array (
-		'' 
-);
-foreach ( $tmptype2label as $key => $val )
-	$type2label[$key] = $langs->trans($val);
-*/
-
-$errors = array ();
-
-$object = new AccountingJournal($db);
-
-
-/*
- * Actions
- */
-
-
-
-/*
- * View
- */
-$title = $langs->trans('AccountingJournals');
-$helpurl = "";
-llxHeader('', $title, $helpurl);
-
-$max = 100;
-$form = new Form($db);
-
-$linkback = '<a href="' . DOL_URL_ROOT . '/admin/modules.php">' . $langs->trans("BackToModuleList") . '</a>';
-print load_fiche_titre($langs->trans('ConfigAccountingExpert'), $linkback, 'title_setup');
-
-$head = admin_accounting_prepare_head(null);
-
-dol_fiche_head($head, 'journal', $langs->trans("Configuration"), -1, 'cron');
-
-$sql = "SELECT j.rowid, j.code, j.label, j.nature, j.active";
-$sql .= " FROM " . MAIN_DB_PREFIX . "accounting_journal as j";
-// $sql .= " WHERE j.entity = " . $conf->entity;
-$sql.=$db->order($sortfield,$sortorder);
-
-// Count total nb of records
-$nbtotalofrecords = '';
-if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST))
-{
-	$result = $db->query($sql);
-	$nbtotalofrecords = $db->num_rows($result);
-}
-
-$sql.= $db->plimit($limit+1, $offset);
-
-$result = $db->query($sql);
-if ($result) {
-	$num = $db->num_rows($result);
-
-	$i = 0;
-
-	// $title = $langs->trans('AccountingJournals');
-	// print_barre_liste($title, $page, $_SERVER["PHP_SELF"], $params, $sortfield, $sortorder, '', $num, $nbtotalofrecords, 'title_accountancy', 0, '', '', $limit, 1);
-
-	// Load attribute_label
-	print '<table class="noborder" width="100%">';
-	print '<tr class="liste_titre">';
-	// print '<td>' . $langs->trans("Ref") . '</td>';
-	print '<td>' . $langs->trans("Code") . '</td>';
-	print '<td>' . $langs->trans("Label") . '</td>';
-	print '<td>' . $langs->trans("Nature") . '</td>';
-	print '</tr>';
-
-	if ($num) {
-		$accountingjournalstatic = new AccountingJournal($db);
-
-		while ( $i < $num && $i < $max ) {
-			$obj = $db->fetch_object($result);
-			$accountingjournalstatic->id = $obj->rowid;
-			print '<tr class="oddeven">';
-			print '<td><a href="journals_card.php?id=' . $obj->rowid . '">' . img_object($langs->trans("ShowJournal"), "technic") . ' ' . $obj->code . '</a></td>';
-			print '<td align="left">' . $obj->label . '</td>';
-			print '<td>' . $accountingjournalstatic->LibType($obj->nature, 0) . '</td>';
-			print '</tr>';
-			$i ++;
-		}
-	} else {
-		print '<tr class="oddeven"><td colspan="3" class="opacitymedium">' . $langs->trans("None") . '</td></tr>';
-	}
-	print '</table>';
-} else {
-	dol_print_error($db);
-}
-
-dol_fiche_end();
-
-// Buttons
-print '<div class="tabsAction">';
-if (! empty($user->rights->accounting->fiscalyear))
-{
-    print '<a class="butAction" href="journals_card.php?action=create">' . $langs->trans("NewAccountingJournal") . '</a>';
-}
-else
-{
-    print '<a class="butActionRefused" href="#">' . $langs->trans("NewAccountingJournal") . '</a>';
-}
-print '</div>';
-
-llxFooter();
-$db->close();

+ 0 - 294
htdocs/accountancy/admin/journals_card.php

@@ -1,294 +0,0 @@
-<?php
-/* Copyright (C) 2017		Alexandre Spangaro	<aspangaro@zendsi.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/**
- * \file        htdocs/accountancy/admin/journals_card.php
- * \ingroup     Advanced accountancy
- * \brief       Page to show an accounting journal
- */
-require '../../main.inc.php';
-
-require_once DOL_DOCUMENT_ROOT . '/core/lib/accounting.lib.php';
-require_once DOL_DOCUMENT_ROOT . '/accountancy/class/accountingjournal.class.php';
-
-$langs->load("admin");
-$langs->load("compta");
-$langs->load("accountancy");
-
-// Security check
-if ($user->societe_id > 0)
-	accessforbidden();
-if (empty($user->rights->accounting->fiscalyear))
-	accessforbidden();
-
-$error = 0;
-
-$action = GETPOST('action', 'alpha');
-$confirm = GETPOST('confirm', 'alpha');
-$id = GETPOST('id', 'int');
-
-// List of status
-static $tmptype2label = array (
-		'0' => 'AccountingJournalTypeVariousOperation',
-		'1' => 'AccountingJournalTypeSale',
-		'2' => 'AccountingJournalTypePurchase',
-		'3' => 'AccountingJournalTypeBank',
-		'9' => 'AccountingJournalTypeHasNew'
-);
-$type2label = array (
-		'' 
-);
-foreach ( $tmptype2label as $key => $val )
-	$type2label[$key] = $langs->trans($val);
-
-$object = new AccountingJournal($db);
-
-/*
- * Actions
- */
-
-if ($action == 'confirm_delete' && $confirm == "yes") {
-	$result = $object->delete($id);
-	if ($result >= 0) {
-		header("Location: journals.php");
-		exit();
-	} else {
-		setEventMessages($object->error, $object->errors, 'errors');
-	}
-} 
-
-else if ($action == 'add') {
-	if (! GETPOST('cancel', 'alpha')) {
-		$error = 0;
-
-		$object->code = GETPOST('code', 'alpha');
-		$object->label = GETPOST('label', 'alpha');
-		$object->nature = GETPOST('nature', 'int');
-
-		if (empty($object->code)) {
-			setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Code")), null, 'errors');
-			$error ++;
-		}
-		if (empty($object->label)) {
-			setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Label")), null, 'errors');
-			$error ++;
-		}
-
-		if (! $error) {
-			$db->begin();
-
-			$id = $object->create($user);
-
-			if ($id > 0) {
-				$db->commit();
-
-				header("Location: " . $_SERVER["PHP_SELF"] . "?id=" . $id);
-				exit();
-			} else {
-				$db->rollback();
-
-				setEventMessages($object->error, $object->errors, 'errors');
-				$action = 'create';
-			}
-		} else {
-			$action = 'create';
-		}
-	} else {
-		header("Location: ./journals.php");
-		exit();
-	}
-} 
-
-// Update record
-else if ($action == 'update') {
-	if (! GETPOST('cancel', 'alpha')) {
-		$result = $object->fetch($id);
-
-		$object->code = GETPOST('code', 'alpha');
-		$object->label = GETPOST('label', 'alpha');
-		$object->nature = GETPOST('nature', 'int');
-
-		if (empty($object->code)) {
-			setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Code")), null, 'errors');
-			$error ++;
-		}
-		if (empty($object->label)) {
-			setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Label")), null, 'errors');
-			$error ++;
-		}
-
-		$result = $object->update($user);
-		
-		if ($result > 0) {
-			header("Location: " . $_SERVER["PHP_SELF"] . "?id=" . $id);
-			exit();
-		} else {
-			setEventMessages($object->error, $object->errors, 'errors');
-		}
-	} else {
-		header("Location: " . $_SERVER["PHP_SELF"] . "?id=" . $id);
-		exit();
-	}
-}
-
-
-
-/*
- * View
- */
-
-$title = $langs->trans("Journal") . " - " . $langs->trans("Card");
-$helpurl = "";
-llxHeader("",$title,$helpurl);
-
-$form = new Form($db);
-
-if ($action == 'create') 
-{
-	print load_fiche_titre($langs->trans("NewAccountingJournal"));
-
-	print '<form action="' . $_SERVER["PHP_SELF"] . '" method="POST">';
-	print '<input type="hidden" name="token" value="' . $_SESSION['newtoken'] . '">';
-	print '<input type="hidden" name="action" value="add">';
-
-	dol_fiche_head();
-
-	print '<table class="border" width="100%">';
-
-	// Code
-	print '<tr><td class="titlefieldcreate fieldrequired">' . $langs->trans("Code") . '</td><td><input name="code" size="10" value="' . GETPOST("code") . '"></td></tr>';
-
-
-	// Label
-	print '<tr><td class="fieldrequired">' . $langs->trans("Label") . '</td><td><input name="label" size="32" value="' . GETPOST("label") . '"></td></tr>';
-
-	// Nature
-	print '<tr>';
-	print '<td class="fieldrequired">' . $langs->trans("Type") . '</td>';
-	print '<td class="valeur">';
-	print $form->selectarray('nature', $type2label, GETPOST('nature'));
-	print '</td></tr>';
-	
-	print '</table>';
-
-	dol_fiche_end();
-
-	print '<div class="center">';
-	print '<input class="button" type="submit" value="' . $langs->trans("Save") . '">';
-	print '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;';
-	print '<input class="button" type="submit" name="cancel" value="' . $langs->trans("Cancel") . '">';
-	print '</div>';
-
-	print '</form>';
-} else if ($id) {
-	$result = $object->fetch($id);
-	if ($result > 0) {
-		$head = accounting_journal_prepare_head($object);
-
-		if ($action == 'edit') {
-			dol_fiche_head($head, 'card', $langs->trans("AccountingJournal"), 0, 'cron');
-
-			print '<form name="update" action="' . $_SERVER["PHP_SELF"] . '" method="POST">' . "\n";
-			print '<input type="hidden" name="token" value="' . $_SESSION['newtoken'] . '">';
-			print '<input type="hidden" name="action" value="update">';
-			print '<input type="hidden" name="id" value="' . $id . '">';
-
-			print '<table class="border" width="100%">';
-
-			// Code
-			print "<tr>";
-			print '<td class="titlefieldcreate fieldrequired">' . $langs->trans("Code") . '</td><td>';
-			print '<input name="code" class="flat" size="8" value="' . $object->code . '">';
-			print '</td></tr>';
-
-			// Label
-			print '<tr><td class="fieldrequired">' . $langs->trans("Label") . '</td><td>';
-			print '<input name="label" class="flat" size="32" value="' . $object->label . '">';
-			print '</td></tr>';
-
-			// Nature
-			print '<tr><td>' . $langs->trans("Type") . '</td><td>';
-			print $form->selectarray('nature', $type2label, $object->nature);
-			print '</td></tr>';
-
-			print '</table>';
-
-			print '<br><div class="center">';
-			print '<input type="submit" class="button" value="' . $langs->trans("Save") . '">';
-			print '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;';
-			print '<input type="submit" name="cancel" class="button" value="' . $langs->trans("Cancel") . '">';
-			print '</div>';
-
-			print '</form>';
-
-			dol_fiche_end();
-		} else {
-			/*
-			 * Confirm delete
-			 */
-			if ($action == 'delete') {
-				print $form->formconfirm($_SERVER["PHP_SELF"] . "?id=" . $id, $langs->trans("DeleteFiscalYear"), $langs->trans("ConfirmDeleteFiscalYear"), "confirm_delete");
-			}
-
-			dol_fiche_head($head, 'card', $langs->trans("AccountingJournal"), 0, 'cron');
-
-			print '<table class="border" width="100%">';
-
-			$linkback = '<a href="' . DOL_URL_ROOT . '/accountancy/admin/journals.php">' . $langs->trans("BackToList") . '</a>';
-
-			// Ref
-			print '<tr><td class="titlefield">' . $langs->trans("Code") . '</td><td width="50%">';
-			print $object->code;
-			print '</td><td>';
-			print $linkback;
-			print '</td></tr>';
-
-			// Label
-			print '<tr><td class="tdtop">';
-			print $form->editfieldkey("Label", 'label', $object->label, $object, $conf->global->MAIN_EDIT_ALSO_INLINE, 'alpha:32');
-			print '</td><td colspan="2">';
-			print $form->editfieldval("Label", 'label', $object->label, $object, $conf->global->MAIN_EDIT_ALSO_INLINE, 'alpha:32');
-			print "</td></tr>";
-
-			// Nature
-			print '<tr><td>' . $langs->trans("Type") . '</td><td colspan="2">' . $object->getLibType(0) . '</td></tr>';
-
-			print "</table>";
-
-			dol_fiche_end();
-
-			if (! empty($user->rights->accounting->fiscalyear))
-			{
-    			/*
-    			 * Barre d'actions
-    			 */
-    			print '<div class="tabsAction">';
-
-    			print '<a class="butAction" href="' . $_SERVER["PHP_SELF"] . '?action=edit&id=' . $id . '">' . $langs->trans('Modify') . '</a>';
-
-    			print '<a class="butActionDelete" href="' . $_SERVER["PHP_SELF"] . '?action=delete&id=' . $id . '">' . $langs->trans('Delete') . '</a>';
-
-    			print '</div>';
-			}
-		}
-	} else {
-		dol_print_error($db);
-	}
-}
-
-llxFooter();
-$db->close();

+ 752 - 0
htdocs/accountancy/admin/journals_list.php

@@ -0,0 +1,752 @@
+<?php
+/* Copyright (C) 2017		Alexandre Spangaro   <aspangaro@zendsi.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+/**
+ * \file		htdocs/accountancy/admin/journals_list.php
+ * \ingroup		Advanced accountancy
+ * \brief		Setup page to configure journals
+ */
+require '../../main.inc.php';
+require_once DOL_DOCUMENT_ROOT.'/core/class/html.formadmin.class.php';
+require_once DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php';
+require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php';
+require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
+require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
+require_once DOL_DOCUMENT_ROOT.'/core/lib/accounting.lib.php';
+require_once DOL_DOCUMENT_ROOT.'/accountancy/class/accountingjournal.class.php';
+
+$langs->load("admin");
+$langs->load("compta");
+$langs->load("accountancy");
+
+$action=GETPOST('action','alpha')?GETPOST('action','alpha'):'view';
+$confirm=GETPOST('confirm','alpha');
+$id=GETPOST('id','int');
+$rowid=GETPOST('rowid','alpha');
+
+// Security access
+if (! empty($user->rights->accountancy->chartofaccount))
+{
+	accessforbidden();
+}
+
+$acts[0] = "activate";
+$acts[1] = "disable";
+$actl[0] = img_picto($langs->trans("Disabled"),'switch_off');
+$actl[1] = img_picto($langs->trans("Activated"),'switch_on');
+
+$listoffset=GETPOST('listoffset');
+$listlimit=GETPOST('listlimit')>0?GETPOST('listlimit'):1000;
+$active = 1;
+
+$sortfield = GETPOST("sortfield",'alpha');
+$sortorder = GETPOST("sortorder",'alpha');
+$page = GETPOST("page",'int');
+if ($page == -1) { $page = 0 ; }
+$offset = $listlimit * $page ;
+$pageprev = $page - 1;
+$pagenext = $page + 1;
+if (empty($sortfield)) $sortfield='code';
+if (empty($sortorder)) $sortorder='ASC';
+
+$error = 0;
+
+// Initialize technical object to manage hooks of thirdparties. Note that conf->hooks_modules contains array array
+$hookmanager->initHooks(array('admin'));
+
+// This page is a generic page to edit dictionaries
+// Put here declaration of dictionaries properties
+
+// Sort order to show dictionary (0 is space). All other dictionaries (added by modules) will be at end of this.
+$taborder=array(35);
+
+// Name of SQL tables of dictionaries
+$tabname=array();
+$tabname[35]= MAIN_DB_PREFIX."accounting_journal";
+
+// Dictionary labels
+$tablib=array();
+$tablib[35]= "DictionaryAccountancyJournal";
+
+// Requests to extract data
+$tabsql=array();
+$tabsql[35]= "SELECT a.rowid as rowid, a.code as code, a.label, a.nature, a.active FROM ".MAIN_DB_PREFIX."accounting_journal as a";
+
+// Criteria to sort dictionaries
+$tabsqlsort=array();
+$tabsqlsort[35]="code ASC";
+
+// Nom des champs en resultat de select pour affichage du dictionnaire
+$tabfield=array();
+$tabfield[35]= "code,label,nature";
+
+// Nom des champs d'edition pour modification d'un enregistrement
+$tabfieldvalue=array();
+$tabfieldvalue[35]= "code,label,nature";
+
+// Nom des champs dans la table pour insertion d'un enregistrement
+$tabfieldinsert=array();
+$tabfieldinsert[35]= "code,label,nature";
+
+// Nom du rowid si le champ n'est pas de type autoincrement
+// Example: "" if id field is "rowid" and has autoincrement on
+//          "nameoffield" if id field is not "rowid" or has not autoincrement on
+$tabrowid=array();
+$tabrowid[35]= "";
+
+// Condition to show dictionary in setup page
+$tabcond=array();
+$tabcond[35]= ! empty($conf->accounting->enabled);
+
+// List of help for fields
+$tabhelp=array();
+$tabhelp[35] = array('code'=>$langs->trans("EnterAnyCode"));
+
+// List of check for fields (NOT USED YET)
+$tabfieldcheck=array();
+$tabfieldcheck[35] = array();
+
+// Complete all arrays with entries found into modules
+complete_dictionary_with_modules($taborder,$tabname,$tablib,$tabsql,$tabsqlsort,$tabfield,$tabfieldvalue,$tabfieldinsert,$tabrowid,$tabcond,$tabhelp,$tabfieldcheck);
+
+
+// Define elementList and sourceList (used for dictionary type of contacts "llx_c_type_contact")
+$elementList = array();
+    // Must match ids defined into eldy.lib.php 
+    $sourceList = array(
+			'1' => $langs->trans('AccountingJournalType1'),
+			'2' => $langs->trans('AccountingJournalType2'),
+			'3' => $langs->trans('AccountingJournalType3'),
+			'4' => $langs->trans('AccountingJournalType4'),
+			'9' => $langs->trans('AccountingJournalType9')
+	);
+
+/*
+ * Actions
+ */
+
+if (GETPOST('button_removefilter') || GETPOST('button_removefilter.x') || GETPOST('button_removefilter_x'))
+{
+    $search_country_id = '';    
+}
+
+// Actions add or modify an entry into a dictionary
+if (GETPOST('actionadd') || GETPOST('actionmodify'))
+{
+    $listfield=explode(',', str_replace(' ', '',$tabfield[$id]));
+    $listfieldinsert=explode(',',$tabfieldinsert[$id]);
+    $listfieldmodify=explode(',',$tabfieldinsert[$id]);
+    $listfieldvalue=explode(',',$tabfieldvalue[$id]);
+
+    // Check that all fields are filled
+    $ok=1;
+    foreach ($listfield as $f => $value)
+    {
+		if ($fieldnamekey == 'libelle' || ($fieldnamekey == 'label'))  $fieldnamekey='Label';
+        if ($fieldnamekey == 'code') $fieldnamekey = 'Code';
+		if ($fieldnamekey == 'nature') $fieldnamekey = 'Nature';
+    }
+    // Other checks
+    if (isset($_POST["code"]))
+    {
+    	if ($_POST["code"]=='0')
+    	{
+        	$ok=0;
+    		setEventMessages($langs->transnoentities('ErrorCodeCantContainZero'), null, 'errors');
+        }
+        /*if (!is_numeric($_POST['code']))	// disabled, code may not be in numeric base
+    	{
+	    	$ok = 0;
+	    	$msg .= $langs->transnoentities('ErrorFieldFormat', $langs->transnoentities('Code')).'<br />';
+	    }*/
+    }
+
+	// Clean some parameters
+    if ($_POST["accountancy_code"] <= 0) $_POST["accountancy_code"]='';	// If empty, we force to null
+	if ($_POST["accountancy_code_sell"] <= 0) $_POST["accountancy_code_sell"]='';	// If empty, we force to null
+	if ($_POST["accountancy_code_buy"] <= 0) $_POST["accountancy_code_buy"]='';	// If empty, we force to null
+
+    // Si verif ok et action add, on ajoute la ligne
+    if ($ok && GETPOST('actionadd'))
+    {
+        if ($tabrowid[$id])
+        {
+            // Recupere id libre pour insertion
+            $newid=0;
+            $sql = "SELECT max(".$tabrowid[$id].") newid from ".$tabname[$id];
+            $result = $db->query($sql);
+            if ($result)
+            {
+                $obj = $db->fetch_object($result);
+                $newid=($obj->newid + 1);
+
+            } else {
+                dol_print_error($db);
+            }
+        }
+
+        // Add new entry
+        $sql = "INSERT INTO ".$tabname[$id]." (";
+        // List of fields
+        if ($tabrowid[$id] && ! in_array($tabrowid[$id],$listfieldinsert))
+        	$sql.= $tabrowid[$id].",";
+        $sql.= $tabfieldinsert[$id];
+        $sql.=",active)";
+        $sql.= " VALUES(";
+
+        // List of values
+        if ($tabrowid[$id] && ! in_array($tabrowid[$id],$listfieldinsert))
+        	$sql.= $newid.",";
+        $i=0;
+        foreach ($listfieldinsert as $f => $value)
+        {
+            if ($value == 'entity') {
+            	$_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 = ''
+            else $sql.="'".$db->escape($_POST[$listfieldvalue[$i]])."'";
+            $i++;
+        }
+        $sql.=",1)";
+
+        dol_syslog("actionadd", LOG_DEBUG);
+        $result = $db->query($sql);
+        if ($result)	// Add is ok
+        {
+            setEventMessages($langs->transnoentities("RecordSaved"), null, 'mesgs');
+        	$_POST=array('id'=>$id);	// Clean $_POST array, we keep only
+        }
+        else
+        {
+            if ($db->errno() == 'DB_ERROR_RECORD_ALREADY_EXISTS') {
+                setEventMessages($langs->transnoentities("ErrorRecordAlreadyExists"), null, 'errors');
+            }
+            else {
+                dol_print_error($db);
+            }
+        }
+    }
+
+    // Si verif ok et action modify, on modifie la ligne
+    if ($ok && GETPOST('actionmodify'))
+    {
+        if ($tabrowid[$id]) { $rowidcol=$tabrowid[$id]; }
+        else { $rowidcol="rowid"; }
+
+        // Modify entry
+        $sql = "UPDATE ".$tabname[$id]." SET ";
+        // Modifie valeur des champs
+        if ($tabrowid[$id] && ! in_array($tabrowid[$id],$listfieldmodify))
+        {
+            $sql.= $tabrowid[$id]."=";
+            $sql.= "'".$db->escape($rowid)."', ";
+        }
+        $i = 0;
+        foreach ($listfieldmodify as $field)
+        {
+            if ($field == 'price' || preg_match('/^amount/i',$field) || $field == 'taux') {
+            	$_POST[$listfieldvalue[$i]] = price2num($_POST[$listfieldvalue[$i]],'MU');
+            }
+            else if ($field == 'entity') {
+            	$_POST[$listfieldvalue[$i]] = $conf->entity;
+            }
+            if ($i) $sql.=",";
+            $sql.= $field."=";
+            if ($_POST[$listfieldvalue[$i]] == '' && ! ($listfieldvalue[$i] == 'code' && $id == 10)) $sql.="null";  // For vat, we want/accept code = ''
+            else $sql.="'".$db->escape($_POST[$listfieldvalue[$i]])."'";
+            $i++;
+        }
+        $sql.= " WHERE ".$rowidcol." = '".$rowid."'";
+
+        dol_syslog("actionmodify", LOG_DEBUG);
+        //print $sql;
+        $resql = $db->query($sql);
+        if (! $resql)
+        {
+            setEventMessages($db->error(), null, 'errors');
+        }
+    }
+    //$_GET["id"]=GETPOST('id', 'int');       // Force affichage dictionnaire en cours d'edition
+}
+
+if (GETPOST('actioncancel'))
+{
+    //$_GET["id"]=GETPOST('id', 'int');       // Force affichage dictionnaire en cours d'edition
+}
+
+if ($action == 'confirm_delete' && $confirm == 'yes')       // delete
+{
+    if ($tabrowid[$id]) { $rowidcol=$tabrowid[$id]; }
+    else { $rowidcol="rowid"; }
+
+    $sql = "DELETE from ".$tabname[$id]." WHERE ".$rowidcol."='".$rowid."'";
+
+    dol_syslog("delete", LOG_DEBUG);
+    $result = $db->query($sql);
+    if (! $result)
+    {
+        if ($db->errno() == 'DB_ERROR_CHILD_EXISTS')
+        {
+            setEventMessages($langs->transnoentities("ErrorRecordIsUsedByChild"), null, 'errors');
+        }
+        else
+        {
+            dol_print_error($db);
+        }
+    }
+}
+
+// activate
+if ($action == $acts[0])
+{
+    if ($tabrowid[$id]) { $rowidcol=$tabrowid[$id]; }
+    else { $rowidcol="rowid"; }
+
+    if ($rowid) {
+        $sql = "UPDATE ".$tabname[$id]." SET active = 1 WHERE ".$rowidcol."='".$rowid."'";
+    }
+    elseif ($_GET["code"]) {
+        $sql = "UPDATE ".$tabname[$id]." SET active = 1 WHERE code='".$_GET["code"]."'";
+    }
+
+    $result = $db->query($sql);
+    if (!$result)
+    {
+        dol_print_error($db);
+    }
+}
+
+// disable
+if ($action == $acts[1])
+{
+    if ($tabrowid[$id]) { $rowidcol=$tabrowid[$id]; }
+    else { $rowidcol="rowid"; }
+
+    if ($rowid) {
+        $sql = "UPDATE ".$tabname[$id]." SET active = 0 WHERE ".$rowidcol."='".$rowid."'";
+    }
+    elseif ($_GET["code"]) {
+        $sql = "UPDATE ".$tabname[$id]." SET active = 0 WHERE code='".$_GET["code"]."'";
+    }
+
+    $result = $db->query($sql);
+    if (!$result)
+    {
+        dol_print_error($db);
+    }
+}
+
+/*
+ * View
+ */
+
+$form = new Form($db);
+$formadmin=new FormAdmin($db);
+
+llxHeader();
+
+$titre=$langs->trans("DictionarySetup");
+$linkback='';
+if ($id)
+{
+    $titre.=' - '.$langs->trans($tablib[$id]);
+    $titlepicto='title_accountancy';
+}
+
+print load_fiche_titre($titre,$linkback,$titlepicto);
+
+if (empty($id))
+{
+    print $langs->trans("DictionaryDesc");
+    print " ".$langs->trans("OnlyActiveElementsAreShown")."<br>\n";
+}
+print "<br>\n";
+
+
+// Confirmation de la suppression de la ligne
+if ($action == 'delete')
+{
+    print $form->formconfirm($_SERVER["PHP_SELF"].'?'.($page?'page='.$page.'&':'').'sortfield='.$sortfield.'&sortorder='.$sortorder.'&rowid='.$rowid.'&code='.$_GET["code"].'&id='.$id, $langs->trans('DeleteLine'), $langs->trans('ConfirmDeleteLine'), 'confirm_delete','',0,1);
+}
+//var_dump($elementList);
+
+/*
+ * Show a dictionary
+ */
+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;
+    }
+    
+    if ($sortfield)
+    {
+        // If sort order is "country", we use country_code instead
+    	if ($sortfield == 'country') $sortfield='country_code';
+        $sql.= " ORDER BY ".$sortfield;
+        if ($sortorder)
+        {
+            $sql.=" ".strtoupper($sortorder);
+        }
+        $sql.=", ";
+        // Clear the required sort criteria for the tabsqlsort to be able to force it with selected value
+        $tabsqlsort[$id]=preg_replace('/([a-z]+\.)?'.$sortfield.' '.$sortorder.',/i','',$tabsqlsort[$id]);
+        $tabsqlsort[$id]=preg_replace('/([a-z]+\.)?'.$sortfield.',/i','',$tabsqlsort[$id]);
+    }
+    else {
+        $sql.=" ORDER BY ";
+    }
+    $sql.=$tabsqlsort[$id];
+    $sql.=$db->plimit($listlimit+1,$offset);
+    //print $sql;
+
+    $fieldlist=explode(',',$tabfield[$id]);
+
+    print '<form action="'.$_SERVER['PHP_SELF'].'?id='.$id.'" method="POST">';
+    print '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
+    print '<input type="hidden" name="from" value="'.dol_escape_htmltag(GETPOST('from','alpha')).'">';
+    
+    print '<table class="noborder" width="100%">';
+
+    // Form to add a new line
+    if ($tabname[$id])
+    {
+        $alabelisused=0;
+        $var=false;
+
+        $fieldlist=explode(',',$tabfield[$id]);
+
+        // Line for title
+        print '<tr class="liste_titre">';
+        foreach ($fieldlist as $field => $value)
+        {
+            // Determine le nom du champ par rapport aux noms possibles
+            // dans les dictionnaires de donnees
+            $valuetoshow=ucfirst($fieldlist[$field]);   // Par defaut
+            $valuetoshow=$langs->trans($valuetoshow);   // try to translate
+            $align="left";
+            if ($fieldlist[$field]=='code')            { $valuetoshow=$langs->trans("Code"); }
+            if ($fieldlist[$field]=='libelle' || $fieldlist[$field]=='label')
+            {
+            	$valuetoshow=$langs->trans("Label");
+            }
+            if ($fieldlist[$field]=='nature')          { $valuetoshow=$langs->trans("Nature"); }
+				
+            if ($valuetoshow != '')
+            {
+                print '<td align="'.$align.'">';
+            	if (! empty($tabhelp[$id][$value]) && preg_match('/^http(s*):/i',$tabhelp[$id][$value])) print '<a href="'.$tabhelp[$id][$value].'" target="_blank">'.$valuetoshow.' '.img_help(1,$valuetoshow).'</a>';
+            	else if (! empty($tabhelp[$id][$value])) print $form->textwithpicto($valuetoshow,$tabhelp[$id][$value]);
+            	else print $valuetoshow;
+                print '</td>';
+             }
+             if ($fieldlist[$field]=='libelle' || $fieldlist[$field]=='label') $alabelisused=1;
+        }
+
+        print '<td>';
+        print '<input type="hidden" name="id" value="'.$id.'">';
+        print '</td>';
+        print '<td style="min-width: 26px;"></td>';
+        print '<td style="min-width: 26px;"></td>';
+        print '<td style="min-width: 26px;"></td>';
+        print '</tr>';
+
+        // Line to enter new values
+        print '<tr class="oddeven nodrag nodrap nohover">';
+
+        $obj = new stdClass();
+        // If data was already input, we define them in obj to populate input fields.
+        if (GETPOST('actionadd'))
+        {
+            foreach ($fieldlist as $key=>$val)
+            {
+                if (GETPOST($val) != '')
+                	$obj->$val=GETPOST($val);
+            }
+        }
+
+        $tmpaction = 'create';
+        $parameters=array('fieldlist'=>$fieldlist, 'tabname'=>$tabname[$id]);
+        $reshook=$hookmanager->executeHooks('createDictionaryFieldlist',$parameters, $obj, $tmpaction);    // Note that $action and $object may have been modified by some hooks
+        $error=$hookmanager->error; $errors=$hookmanager->errors;
+
+        if (empty($reshook))
+        {
+       		fieldList($fieldlist,$obj,$tabname[$id],'add');
+        }
+
+        print '<td colspan="4" align="right">';
+       	print '<input type="submit" class="button" name="actionadd" value="'.$langs->trans("Add").'">';
+        print '</td>';
+        print "</tr>";
+
+        print '<tr><td colspan="7">&nbsp;</td></tr>';	// Keep &nbsp; to have a line with enough height
+    }
+
+
+
+    // List of available record in database
+    dol_syslog("htdocs/admin/dict", LOG_DEBUG);
+    $resql=$db->query($sql);
+    if ($resql)
+    {
+        $num = $db->num_rows($resql);
+        $i = 0;
+        $var=true;
+
+        $param = '&id='.$id;
+        if ($search_country_id > 0) $param.= '&search_country_id='.$search_country_id;
+        $paramwithsearch = $param;
+        if ($sortorder) $paramwithsearch.= '&sortorder='.$sortorder;
+        if ($sortfield) $paramwithsearch.= '&sortfield='.$sortfield;
+        if (GETPOST('from')) $paramwithsearch.= '&from='.GETPOST('from','alpha');
+        
+        // There is several pages
+        if ($num > $listlimit)
+        {
+            print '<tr class="none"><td align="right" colspan="'.(3+count($fieldlist)).'">';
+            print_fleche_navigation($page, $_SERVER["PHP_SELF"], $paramwithsearch, ($num > $listlimit), '<li class="pagination"><span>'.$langs->trans("Page").' '.($page+1).'</span></li>');
+            print '</td></tr>';
+        }
+
+        // Title of lines
+        print '<tr class="liste_titre liste_titre_add">';
+        foreach ($fieldlist as $field => $value)
+        {
+            // Determine le nom du champ par rapport aux noms possibles
+            // dans les dictionnaires de donnees
+            $showfield=1;							  	// By defaut
+            $align="left";
+            $sortable=1;
+            $valuetoshow='';
+            /*
+            $tmparray=getLabelOfField($fieldlist[$field]);
+            $showfield=$tmp['showfield'];
+            $valuetoshow=$tmp['valuetoshow'];
+            $align=$tmp['align'];
+            $sortable=$tmp['sortable'];
+			*/
+            $valuetoshow=ucfirst($fieldlist[$field]);   // By defaut
+            $valuetoshow=$langs->trans($valuetoshow);   // try to translate
+            if ($fieldlist[$field]=='code')            { $valuetoshow=$langs->trans("Code"); }
+            if ($fieldlist[$field]=='libelle' || $fieldlist[$field]=='label') { $valuetoshow=$langs->trans("Label"); }
+            if ($fieldlist[$field]=='nature')          { $valuetoshow=$langs->trans("Nature"); }
+
+            // Affiche nom du champ
+            if ($showfield)
+            {
+                print getTitleFieldOfList($valuetoshow, 0, $_SERVER["PHP_SELF"], ($sortable?$fieldlist[$field]:''), ($page?'page='.$page.'&':''), $param, "align=".$align, $sortfield, $sortorder);
+            }
+        }
+		print getTitleFieldOfList($langs->trans("Status"), 0, $_SERVER["PHP_SELF"], "active", ($page?'page='.$page.'&':''), $param, 'align="center"', $sortfield, $sortorder);
+        print getTitleFieldOfList('');
+        print getTitleFieldOfList('');
+        print getTitleFieldOfList('');
+        print '</tr>';
+
+        // Title line with search boxes
+        print '<tr class="liste_titre_filter">';
+        print '<td class="liste_titre"></td>';
+        print '<td class="liste_titre"></td>';
+        print '<td class="liste_titre"></td>';
+        print '<td class="liste_titre"></td>';
+        print '<td class="liste_titre"></td>';
+        print '<td class="liste_titre"></td>';
+        print '<td class="liste_titre" align="center">';
+    	if ($filterfound)
+    	{
+        	$searchpitco=$form->showFilterAndCheckAddButtons(0);
+        	print $searchpitco;
+    	}
+    	print '</td>';
+    	print '</tr>';
+            
+        if ($num)
+        {
+            // Lines with values
+            while ($i < $num)
+            {
+                $obj = $db->fetch_object($resql);
+                //print_r($obj);
+                print '<tr class="oddeven" id="rowid-'.$obj->rowid.'">';
+                if ($action == 'edit' && ($rowid == (! empty($obj->rowid)?$obj->rowid:$obj->code)))
+                {
+                    $tmpaction='edit';
+                    $parameters=array('fieldlist'=>$fieldlist, 'tabname'=>$tabname[$id]);
+                    $reshook=$hookmanager->executeHooks('editDictionaryFieldlist',$parameters,$obj, $tmpaction);    // Note that $action and $object may have been modified by some hooks
+                    $error=$hookmanager->error; $errors=$hookmanager->errors;
+
+                    // Show fields
+                    if (empty($reshook)) fieldList($fieldlist,$obj,$tabname[$id],'edit');
+
+                    print '<td align="center" colspan="4">';
+                    print '<input type="hidden" name="page" value="'.$page.'">';
+                    print '<input type="hidden" name="rowid" value="'.$rowid.'">';
+                    print '<input type="submit" class="button" name="actionmodify" value="'.$langs->trans("Modify").'">';
+                    print '<input type="submit" class="button" name="actioncancel" value="'.$langs->trans("Cancel").'">';
+                    print '<div name="'.(! empty($obj->rowid)?$obj->rowid:$obj->code).'"></div>';
+                    print '</td>';
+                }
+                else
+                {
+	              	$tmpaction = 'view';
+                    $parameters=array('var'=>$var, 'fieldlist'=>$fieldlist, 'tabname'=>$tabname[$id]);
+                    $reshook=$hookmanager->executeHooks('viewDictionaryFieldlist',$parameters,$obj, $tmpaction);    // Note that $action and $object may have been modified by some hooks
+
+                    $error=$hookmanager->error; $errors=$hookmanager->errors;
+
+                    if (empty($reshook))
+                    {
+                        foreach ($fieldlist as $field => $value)
+                        {
+                            
+                            $showfield=1;
+                        	$align="left";
+                            $valuetoshow=$obj->{$fieldlist[$field]};
+                            if ($valuetoshow=='all') {
+                                $valuetoshow=$langs->trans('All');
+                            }
+                            else if ($fieldlist[$field]=='nature' && $tabname[$id]==MAIN_DB_PREFIX.'accounting_journal') {
+                                $langs->load("accountancy");
+                                $key=$langs->trans("AccountingJournalType".strtoupper($obj->nature));
+                                $valuetoshow=($obj->nature && $key != "AccountingJournalType".strtoupper($obj->nature)?$key:$obj->{$fieldlist[$field]});
+                            }
+
+                            $class='tddict';
+							// Show value for field
+							if ($showfield) print '<!-- '.$fieldlist[$field].' --><td align="'.$align.'" class="'.$class.'">'.$valuetoshow.'</td>';
+                        }
+                    }
+
+                    // Can an entry be erased or disabled ?
+                    $iserasable=1;$canbedisabled=1;$canbemodified=1;	// true by default
+                    if (isset($obj->code) && $id != 10)
+                    {
+                    	if (($obj->code == '0' || $obj->code == '' || preg_match('/unknown/i',$obj->code))) { $iserasable = 0; $canbedisabled = 0; }
+                    	else if ($obj->code == 'RECEP') { $iserasable = 0; $canbedisabled = 0; }
+                    	else if ($obj->code == 'EF0')   { $iserasable = 0; $canbedisabled = 0; }
+                    }
+
+                    $canbemodified=$iserasable;
+
+                    $url = $_SERVER["PHP_SELF"].'?'.($page?'page='.$page.'&':'').'sortfield='.$sortfield.'&sortorder='.$sortorder.'&rowid='.(! empty($obj->rowid)?$obj->rowid:(! empty($obj->code)?$obj->code:'')).'&code='.(! empty($obj->code)?urlencode($obj->code):'');
+                    if ($param) $url .= '&'.$param;
+                    $url.='&';
+
+                    // Active
+                    print '<td align="center" class="nowrap">';
+                    if ($canbedisabled) print '<a href="'.$url.'action='.$acts[$obj->active].'">'.$actl[$obj->active].'</a>';
+                    else
+                 	{
+                 		if (in_array($obj->code, array('AC_OTH','AC_OTH_AUTO'))) print $langs->trans("AlwaysActive");
+                 		else if (isset($obj->type) && in_array($obj->type, array('systemauto')) && empty($obj->active)) print $langs->trans("Deprecated");
+                  		else if (isset($obj->type) && in_array($obj->type, array('system')) && ! empty($obj->active) && $obj->code != 'AC_OTH') print $langs->trans("UsedOnlyWithTypeOption");
+                    	else print $langs->trans("AlwaysActive");
+                    }
+                    print "</td>";
+
+                    // Modify link
+                    if ($canbemodified) print '<td align="center"><a class="reposition" href="'.$url.'action=edit">'.img_edit().'</a></td>';
+                    else print '<td>&nbsp;</td>';
+
+                    // Delete link
+                    if ($iserasable)
+                    {
+                        print '<td align="center">';
+                        if ($user->admin) print '<a href="'.$url.'action=delete">'.img_delete().'</a>';
+                        //else print '<a href="#">'.img_delete().'</a>';    // Some dictionnary can be edited by other profile than admin
+                        print '</td>';
+                    }
+                    else print '<td>&nbsp;</td>';
+
+                    print '<td></td>';
+                                         
+                    print '</td>';
+                }
+                
+                print "</tr>\n";
+                $i++;
+            }
+        }
+    }
+    else {
+        dol_print_error($db);
+    }
+
+    print '</table>';
+
+    print '</form>';
+}
+
+print '<br>';
+
+
+llxFooter();
+$db->close();
+
+
+/**
+ *	Show fields in insert/edit mode
+ *
+ * 	@param		array	$fieldlist		Array of fields
+ * 	@param		Object	$obj			If we show a particular record, obj is filled with record fields
+ *  @param		string	$tabname		Name of SQL table
+ *  @param		string	$context		'add'=Output field for the "add form", 'edit'=Output field for the "edit form", 'hide'=Output field for the "add form" but we dont want it to be rendered
+ *	@return		void
+ */
+function fieldList($fieldlist, $obj='', $tabname='', $context='')
+{
+	global $conf,$langs,$db;
+	global $form, $mysoc;
+	global $region_id;
+	global $elementList,$sourceList,$localtax_typeList;
+	global $bc;
+
+	$formadmin = new FormAdmin($db);
+	$formcompany = new FormCompany($db);
+
+	foreach ($fieldlist as $field => $value)
+	{
+		if ($fieldlist[$field] == 'nature')
+		{
+			print '<td>';
+			print $form->selectarray('nature', $sourceList,(! empty($obj->{$fieldlist[$field]})?$obj->{$fieldlist[$field]}:''));
+			print '</td>';
+		}
+		elseif ($fieldlist[$field] == 'code' && isset($obj->{$fieldlist[$field]})) {
+			print '<td><input type="text" class="flat minwidth100" value="'.(! empty($obj->{$fieldlist[$field]})?$obj->{$fieldlist[$field]}:'').'" name="'.$fieldlist[$field].'"></td>';
+		}
+		else
+		{
+			print '<td>';
+			$size=''; $class='';
+			if ($fieldlist[$field]=='code')  $class='maxwidth100';
+			if ($fieldlist[$field]=='label') $class='quatrevingtpercent';
+			if ($fieldlist[$field]=='sortorder' || $fieldlist[$field]=='sens' || $fieldlist[$field]=='category_type') $size='size="2" ';
+			print '<input type="text" '.$size.'class="flat'.($class?' '.$class:'').'" value="'.(isset($obj->{$fieldlist[$field]})?$obj->{$fieldlist[$field]}:'').'" name="'.$fieldlist[$field].'">';
+			print '</td>';
+		}
+	}
+}

+ 6 - 2
htdocs/accountancy/bookkeeping/card.php

@@ -305,6 +305,8 @@ if ($action == 'create') {
 
 		dol_fiche_head();
 		
+		print '<div class="fichecenter">';
+		
 		print '<table class="border" width="100%">';
 		print '<tr class="pair">';
 		print '<td class="titlefield">' . $langs->trans("NumMvts") . '</td>';
@@ -328,6 +330,8 @@ if ($action == 'create') {
 		print '</tr>';
 		print '</table>';
 		
+		print '</div>';
+		
 		dol_fiche_end();
 
 		print '<br>';
@@ -427,8 +431,8 @@ if ($action == 'create') {
 					print $formventilation->select_auxaccount($code_tiers, 'code_tiers', 1);
 					print '</td>';
 					print '<td><input type="text" size="15" name="label_compte" value="' . $label_compte . '"/></td>';
-					print '<td align="right"><input type="text" size="6" name="debit" value="' . price($debit) . '"/></td>';
-					print '<td align="right"><input type="text" size="6" name="credit" value="' . price($credit) . '"/></td>';
+					print '<td align="right"><input type="text" class="right maxwidth50" name="debit" value="' . price($debit) . '"/></td>';
+					print '<td align="right"><input type="text" class="right maxwidth50" name="credit" value="' . price($credit) . '"/></td>';
 					print '<td></td>';
 					print '<td></td>';
 					print '<td><input type="submit" class="button" name="save" value="' . $langs->trans("Add") . '"></td>';

+ 2 - 2
htdocs/accountancy/bookkeeping/list.php

@@ -360,7 +360,7 @@ if (count($filter)) $button.= $langs->trans("ExportFilteredList");
 else $button.= $langs->trans("ExportList");
 $button.= '</a>';
 
-$groupby = ' <a href="./listbyaccount.php">' . $langs->trans("GroupByAccountAccounting") . '</a>';
+$groupby = ' <a class="nohover" href="'.DOL_URL_ROOT.'/accountancy/bookkeeping/listbyaccount.php"">' . $langs->trans("GroupByAccountAccounting") . '</a>';
 
 print_barre_liste($title_page, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $button, $result, $nbtotalofrecords, 'title_accountancy', 0, $groupby, '', $limit);
 
@@ -437,7 +437,7 @@ foreach ($object->lines as $line ) {
 
 	print '<td><a href="./card.php?piece_num=' . $line->piece_num . '">' . $line->piece_num . '</a></td>';
 	print '<td align="center">' . dol_print_date($line->doc_date, 'day') . '</td>';
-	print '<td>' . $line->doc_ref . '</td>';
+	print '<td class="nowrap">' . $line->doc_ref . '</td>';
 	print '<td>' . length_accountg($line->numero_compte) . '</td>';
 	print '<td>' . length_accounta($line->code_tiers) . '</td>';
 	print '<td>' . $line->label_compte . '</td>';

+ 26 - 22
htdocs/accountancy/bookkeeping/listbyaccount.php

@@ -207,7 +207,7 @@ if ($action == 'delbookkeepingyear') {
 
 print '<form method="GET" id="searchFormList" action="' . $_SERVER["PHP_SELF"] . '">';
 
-$viewflat = ' <a href="./list.php">' . $langs->trans("ViewFlatList") . '</a>';
+$viewflat = ' <a class="nohover" href="'.DOL_URL_ROOT.'/accountancy/bookkeeping/list.php">' . $langs->trans("ViewFlatList") . '</a>';
 
 print_barre_liste($title_page, $page, $_SERVER["PHP_SELF"], $options, $sortfield, $sortorder, '', $result, $nbtotalofrecords,'title_accountancy',0,$viewflat,'',$limit);
 
@@ -222,17 +222,6 @@ print '<div class="inline-block divButAction"><a class="butAction" href="./card.
 print '</div>';
 
 print '<table class="noborder" width="100%">';
-print '<tr class="liste_titre">';
-print '<td>' . $langs->trans("AccountAccounting") . '</td>';
-print_liste_field_titre($langs->trans("TransactionNumShort"), $_SERVER['PHP_SELF'], "t.piece_num", "", $options, 'align="right"', $sortfield, $sortorder);
-print_liste_field_titre($langs->trans("Docdate"), $_SERVER['PHP_SELF'], "t.doc_date", "", $options, 'align="center"', $sortfield, $sortorder);
-print_liste_field_titre($langs->trans("Docref"), $_SERVER['PHP_SELF'], "t.doc_ref", "", $options, "", $sortfield, $sortorder);
-print_liste_field_titre($langs->trans("SuppliersInvoices") . ' / ' . $langs->trans("CustomersInvoices"));
-print_liste_field_titre($langs->trans("Debit"), $_SERVER['PHP_SELF'], "t.debit", "", $options, 'align="right"', $sortfield, $sortorder);
-print_liste_field_titre($langs->trans("Credit"), $_SERVER['PHP_SELF'], "t.credit", "", $options, 'align="right"', $sortfield, $sortorder);
-print_liste_field_titre($langs->trans("Codejournal"), $_SERVER['PHP_SELF'], "t.code_journal", "", $options, 'align="right"', $sortfield, $sortorder);
-print_liste_field_titre('', $_SERVER["PHP_SELF"], "", $options, "", 'width="60" align="center"', $sortfield, $sortorder);
-print "</tr>\n";
 
 print '<tr class="liste_titre">';
 print '<td class="liste_titre">' . $object->select_account($search_accountancy_code_start, 'search_accountancy_code_start', 1, array (), 1, 1, '') . '</td>';
@@ -254,6 +243,18 @@ $searchpitco=$form->showFilterAndCheckAddButtons(0);
 print $searchpitco;
 print '</td>';
 
+print '<tr class="liste_titre">';
+print_liste_field_titre($langs->trans("AccountAccountingShort"), $_SERVER['PHP_SELF']);
+print_liste_field_titre($langs->trans("TransactionNumShort"), $_SERVER['PHP_SELF'], "t.piece_num", "", $options, 'align="right"', $sortfield, $sortorder);
+print_liste_field_titre($langs->trans("Docdate"), $_SERVER['PHP_SELF'], "t.doc_date", "", $options, 'align="center"', $sortfield, $sortorder);
+print_liste_field_titre($langs->trans("Docref"), $_SERVER['PHP_SELF'], "t.doc_ref", "", $options, "", $sortfield, $sortorder);
+print_liste_field_titre($langs->trans("Label"));
+print_liste_field_titre($langs->trans("Debit"), $_SERVER['PHP_SELF'], "t.debit", "", $options, 'align="right"', $sortfield, $sortorder);
+print_liste_field_titre($langs->trans("Credit"), $_SERVER['PHP_SELF'], "t.credit", "", $options, 'align="right"', $sortfield, $sortorder);
+print_liste_field_titre($langs->trans("Codejournal"), $_SERVER['PHP_SELF'], "t.code_journal", "", $options, 'align="right"', $sortfield, $sortorder);
+print_liste_field_titre('', $_SERVER["PHP_SELF"], "", $options, "", 'width="60" align="center"', $sortfield, $sortorder);
+print "</tr>\n";
+
 print '</tr>';
 
 $var = True;
@@ -277,9 +278,10 @@ foreach ( $object->lines as $line ) {
         
         // Affiche un Sous-Total par compte comptable
         if (isset($displayed_account_number)) {
-          print '<tr class="liste_total"><td align="right" colspan="4">'.$langs->trans("SubTotal").':</td><td class="nowrap" align="right">'.price($sous_total_debit).'</td><td class="nowrap" align="right">'.price($sous_total_credit).'</td>';
-          print "<td>&nbsp;</td>\n";
-          print '</tr>';
+            print '<tr class="liste_total"><td align="right" colspan="5">'.$langs->trans("SubTotal").':</td><td class="nowrap" align="right">'.price($sous_total_debit).'</td><td class="nowrap" align="right">'.price($sous_total_credit).'</td>';
+            print "<td>&nbsp;</td>\n";
+            print "<td>&nbsp;</td>\n";
+            print '</tr>';
         }
         
         // Show the break account
@@ -299,17 +301,18 @@ foreach ( $object->lines as $line ) {
 
 	print '<tr class="oddeven">';
 	print '<td>&nbsp;</td>';
-	print '<td align="right">'.$line->piece_num.'</td>';
+	print '<td align="right"><a href="./card.php?piece_num=' . $line->piece_num . '">'.$line->piece_num.'</a></td>';
 	print '<td align="center">' . dol_print_date($line->doc_date, 'day') . '</td>';
-	print '<td><a href="./card.php?piece_num=' . $line->piece_num . '">' . $line->doc_ref . '</a></td>';
+	
+	// TODO Add a link according to doc_type and fk_doc
+	print '<td class="nowrap">';
+    //if ($line->doc_type == 'supplier_invoice')
+    //if ($line->doc_type == 'customer_invoice')
+	print $line->doc_ref;
+    print '</td>';
     
     // Affiche un lien vers la facture client/fournisseur
     $doc_ref = preg_replace('/\(.*\)/', '', $line->doc_ref);
-    if ($line->doc_type == 'supplier_invoice')
-     print strlen(length_accounta($line->code_tiers)) == 0 ? '<td><a href="/fourn/facture/list.php?search_ref_supplier=' . $doc_ref . '">' . $line->label_compte . '</a></td>' : '<td><a href="/fourn/facture/list.php?search_ref_supplier=' . $doc_ref . '">' . $line->label_compte . '</a><br /><span style="font-size:0.8em">(' . length_accounta($line->code_tiers) . ')</span></td>';
-    elseif ($line->doc_type == 'customer_invoice')
-    print strlen(length_accounta($line->code_tiers)) == 0 ? '<td><a href="/compta/facture/list.php?search_ref=' . $doc_ref . '">' . $line->label_compte . '</a></td>' : '<td><a href="/compta/facture/list.php?search_ref=' . $doc_ref . '">' . $line->label_compte . '</a><br /><span style="font-size:0.8em">(' . length_accounta($line->code_tiers) . ')</span></td>';
-    else
     print strlen(length_accounta($line->code_tiers)) == 0 ? '<td>' . $line->label_compte . '</td>' : '<td>' . $line->label_compte . '<br /><span style="font-size:0.8em">(' . length_accounta($line->code_tiers) . ')</span></td>';
 
 
@@ -332,6 +335,7 @@ foreach ( $object->lines as $line ) {
 print '<tr class="liste_total">';
 print '<td align="right" colspan="5">'.$langs->trans("SubTotal").':</td><td class="nowrap" align="right">'.price($sous_total_debit).'</td><td class="nowrap" align="right">'.price($sous_total_credit).'</td>';
 print "<td>&nbsp;</td>\n";
+print "<td>&nbsp;</td>\n";
 print '</tr>';
 
 

+ 47 - 1
htdocs/accountancy/class/accountancyexport.class.php

@@ -47,6 +47,7 @@ class AccountancyExport
 	public static $EXPORT_TYPE_QUADRATUS = 6;
 	public static $EXPORT_TYPE_EBP = 7;
 	public static $EXPORT_TYPE_COGILOG = 8;
+	public static $EXPORT_TYPE_AGIRIS = 9;
 
 	/**
 	 *
@@ -96,6 +97,7 @@ class AccountancyExport
 				self::$EXPORT_TYPE_QUADRATUS => $langs->trans('Modelcsv_quadratus'),
 				self::$EXPORT_TYPE_EBP => $langs->trans('Modelcsv_ebp'),
 				self::$EXPORT_TYPE_COGILOG => $langs->trans('Modelcsv_cogilog'),
+				self::$EXPORT_TYPE_AGIRIS => $langs->trans('Modelcsv_agiris')
 		);
 	}
 
@@ -145,6 +147,9 @@ class AccountancyExport
 			case self::$EXPORT_TYPE_COGILOG :
 				$this->exportCogilog($TData);
 				break;
+			case self::$EXPORT_TYPE_AGIRIS :
+				$this->exportAgiris($TData);
+				break;
 			default:
 				$this->errors[] = $langs->trans('accountancy_error_modelnotfound');
 				break;
@@ -382,7 +387,7 @@ class AccountancyExport
 
 
 	/**
-	 * Export format : Normal
+	 * Export format : EBP
 	 *
 	 * @param array $objectLines data
 	 *
@@ -412,6 +417,47 @@ class AccountancyExport
 	}
 
 
+	/**
+	 * Export format : Agiris
+	 *
+	 * @param array $objectLines data
+	 *
+	 * @return void
+	 */
+	public function exportAgiris($objectLines) {
+
+		$this->separator = ';';
+
+		foreach ( $objectLines as $line ) {
+
+			$date = dol_print_date($line->doc_date, '%d%m%Y');
+
+			print $line->id . $this->separator;
+			print '"'.dol_trunc($line->piece_num,15,'right','UTF-8',1).'"'.$this->separator;
+			print $date . $this->separator;
+			print '"'.dol_trunc($line->piece_num,15,'right','UTF-8',1).'"'.$this->separator;
+			
+			if (empty($line->code_tiers)) {
+				print length_accountg($line->numero_compte) . $this->separator;
+			} else {
+				if (substr($line->numero_compte, 0, 1) == 'C' || substr($line->numero_compte, 0, 1) == '9') {
+					print '411' . substr(str_replace(" ", "", $line->code_tiers), 0, 5) . $this->separator;
+				}
+				if (substr($line->numero_compte, 0, 1) == 'F' || substr($line->numero_compte, 0, 1) == '0') {
+					print '401' . substr(str_replace(" ", "", $line->code_tiers), 0, 5) . $this->separator;
+				}
+			}
+			
+			print length_accounta($line->code_tiers) . $this->separator;
+			print price($line->debit) . $this->separator;
+			print price($line->credit) . $this->separator;
+			print price($line->montant).$this->separator;
+			print $line->sens.$this->separator;
+			print $line->code_journal . $this->separator;
+			print $this->end_line;
+		}
+	}
+
 
 	/**
 	 *

+ 49 - 14
htdocs/accountancy/class/accountingaccount.class.php

@@ -364,28 +364,63 @@ class AccountingAccount extends CommonObject
 	/**
 	 * Return clicable name (with picto eventually)
 	 *
-	 * @param int $withpicto 0=No picto, 1=Include picto into link, 2=Only picto
-	 * @return string Chaine avec URL
+	 * @param	int		$withpicto		0=No picto, 1=Include picto into link, 2=Only picto
+	 * @param	int		$withlabel		0=No label, 1=Include label of account
+	 * @param	int  	$nourl			1=Disable url
+	 * @param	string  $moretitle		Add more text to title tooltip
+	 * @param	int  	$notooltip		1=Disable tooltip
+	 * @return	string	String with URL
 	 */
-	function getNomUrl($withpicto = 0) {
-		global $langs;
+	function getNomUrl($withpicto = 0, $withlabel = 0, $nourl = 0, $moretitle='',$notooltip=0)
+	{
+		global $langs, $conf, $user;
+		require_once DOL_DOCUMENT_ROOT.'/core/lib/accounting.lib.php';
+		
+		if (! empty($conf->dol_no_mouse_hover)) $notooltip=1;   // Force disable tooltips
 
 		$result = '';
 
-		$link = '<a href="' . DOL_URL_ROOT . '/accountancy/admin/card.php?id=' . $this->id . '">';
-		$linkend = '</a>';
+		$url = DOL_URL_ROOT . '/accountancy/admin/card.php?id=' . $this->id;
 
 		$picto = 'billr';
+		$label='';
+
+		$label = '<u>' . $langs->trans("ShowAccountingAccount") . '</u>';
+		if (! empty($this->account_number))
+			$label .= '<br><b>'.$langs->trans('AccountAccounting') . ':</b> ' . length_accountg($this->account_number);
+		if (! empty($this->label))
+			$label .= '<br><b>'.$langs->trans('Label') . ':</b> ' . $this->label;
+		if ($moretitle) $label.=' - '.$moretitle;
+
+		$linkclose='';
+		if (empty($notooltip))
+		{
+		    if (! empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER))
+		    {
+		        $label=$langs->trans("ShowAccoutingAccount");
+		        $linkclose.=' alt="'.dol_escape_htmltag($label, 1).'"';
+		    }
+		    $linkclose.= ' title="'.dol_escape_htmltag($label, 1).'"';
+		    $linkclose.=' class="classfortooltip"';
+		}
+
+        $linkstart='<a href="'.$url.'"';
+        $linkstart.=$linkclose.'>';
+		$linkend='</a>';
+
+		if ($nourl)
+		{
+			$linkstart = '';
+			$linkclose = '';
+			$linkend = '';			
+		}
 
-		$label = $langs->trans("Show") . ': ' . $this->account_number . ' - ' . $this->label;
+		$label_link = length_accountg($this->account_number);
+		if ($withlabel) $label_link .= ' - ' . $this->label;
 
-		if ($withpicto)
-			$result .= ($link . img_object($label, $picto) . $linkend);
-		if ($withpicto && $withpicto != 2)
-			$result .= ' ';
-		if ($withpicto != 2)
-			require_once DOL_DOCUMENT_ROOT.'/core/lib/accounting.lib.php';
-			$result .= $link . length_accountg($this->account_number) . ' - ' . $this->label . $linkend;
+		if ($withpicto) $result.=($linkstart.img_object(($notooltip?'':$label), $picto, ($notooltip?'':'class="classfortooltip"'), 0, 0, $notooltip?0:1).$linkend);
+		if ($withpicto && $withpicto != 2) $result .= ' ';
+		if ($withpicto != 2) $result.=$linkstart . $label_link . $linkend;
 		return $result;
 	}
 	

+ 0 - 260
htdocs/accountancy/class/accountingjournal.class.php

@@ -82,208 +82,6 @@ class AccountingJournal extends CommonObject
 		}
 	}
 	
-	/**
-	 * Insert journal in database
-	 *
-	 * @param	User	$user		Use making action
-	 * @param	int		$notrigger	Disable triggers
-	 * @return 	int 				<0 if KO, >0 if OK
-	 */
-	function create($user, $notrigger = 0)
-	{
-		global $conf;
-		$error = 0;
-		$now = dol_now();
-		
-		// Clean parameters
-		if (isset($this->code))
-			$this->code = trim($this->code);
-		if (isset($this->label))
-			$this->label = trim($this->label);
-
-		// Check parameters
-		if (empty($this->nature) || $this->nature == '-1')
-		{
-		    $this->nature = '0';
-		}
-
-		// Insert request
-		$sql = "INSERT INTO " . MAIN_DB_PREFIX . "accounting_journal(";
-		$sql .= "code";
-		$sql .= ", label";
-		$sql .= ", nature";
-		$sql .= ", active";
-		$sql .= ") VALUES (";
-		$sql .= " " . (empty($this->code) ? 'NULL' : "'" . $this->db->escape($this->code) . "'");
-		$sql .= ", " . (empty($this->label) ? 'NULL' : "'" . $this->db->escape($this->label) . "'");
-		$sql .= ", " . (empty($this->nature) ? '0' : "'" . $this->db->escape($this->nature) . "'");
-		$sql .= ", " . (! isset($this->active) ? 'NULL' : $this->db->escape($this->active));
-		$sql .= ")";
-		
-		$this->db->begin();
-		
-		dol_syslog(get_class($this) . "::create sql=" . $sql, LOG_DEBUG);
-		$resql = $this->db->query($sql);
-		if (! $resql) {
-			$error ++;
-			$this->errors[] = "Error " . $this->db->lasterror();
-		}
-		
-		if (! $error) {
-			$this->id = $this->db->last_insert_id(MAIN_DB_PREFIX . "accounting_journal");
-			
-			// if (! $notrigger) {
-			// Uncomment this and change MYOBJECT to your own tag if you
-			// want this action calls a trigger.
-			
-			// // Call triggers
-			// include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php';
-			// $interface=new Interfaces($this->db);
-			// $result=$interface->run_triggers('MYOBJECT_CREATE',$this,$user,$langs,$conf);
-			// if ($result < 0) { $error++; $this->errors=$interface->errors; }
-			// // End call triggers
-			// }
-		}
-		
-		// Commit or rollback
-		if ($error) {
-			foreach ( $this->errors as $errmsg ) {
-				dol_syslog(get_class($this) . "::create " . $errmsg, LOG_ERR);
-				$this->error .= ($this->error ? ', ' . $errmsg : $errmsg);
-			}
-			$this->db->rollback();
-			return - 1 * $error;
-		} else {
-			$this->db->commit();
-			return $this->id;
-		}
-	}
-	
-	/**
-	 * Update record
-	 *
-	 * @param  User $user      Use making update
-	 * @return int             <0 if KO, >0 if OK
-	 */
-	function update($user) 
-	{
-	    // Check parameters
-	    if (empty($this->nature) || $this->nature == '-1')
-	    {
-	        $this->nature = '0';
-	    }
-
-	    $this->db->begin();
-		
-		$sql = "UPDATE " . MAIN_DB_PREFIX . "accounting_journal ";
-		$sql .= " SET code = " . ($this->code ? "'" . $this->db->escape($this->code) . "'" : "null");
-		$sql .= " , label = " . ($this->label ? "'" . $this->db->escape($this->label) . "'" : "null");
-		$sql .= " , nature = " . ($this->nature ? "'" . $this->db->escape($this->nature) . "'" : "0");
-		$sql .= " , active = '" . $this->active . "'";
-		$sql .= " WHERE rowid = " . $this->id;
-		
-		dol_syslog(get_class($this) . "::update sql=" . $sql, LOG_DEBUG);
-		$result = $this->db->query($sql);
-		if ($result) {
-			$this->db->commit();
-			return 1;
-		} else {
-			$this->error = $this->db->lasterror();
-			$this->db->rollback();
-			return - 1;
-		}
-	}
-	
-	/**
-	 * Check usage of accounting journal
-	 *
-	 * @return int <0 if KO, >0 if OK
-	 */
-	function checkUsage() {
-		global $langs;
-		
-		$sql = "(SELECT fk_code_ventilation FROM " . MAIN_DB_PREFIX . "facturedet";
-		$sql .= " WHERE  fk_code_ventilation=" . $this->id . ")";
-		$sql .= "UNION";
-		$sql .= "(SELECT fk_code_ventilation FROM " . MAIN_DB_PREFIX . "facture_fourn_det";
-		$sql .= " WHERE  fk_code_ventilation=" . $this->id . ")";
-		
-		dol_syslog(get_class($this) . "::checkUsage sql=" . $sql, LOG_DEBUG);
-		$resql = $this->db->query($sql);
-		
-		if ($resql) {
-			$num = $this->db->num_rows($resql);
-			if ($num > 0) {
-				$this->error = $langs->trans('ErrorAccountingJournalIsAlreadyUse');
-				return 0;
-			} else {
-				return 1;
-			}
-		} else {
-			$this->error = $this->db->lasterror();
-			return - 1;
-		}
-	}
-	
-	/**
-	 * Delete object in database
-	 *
-	 * @param User $user User that deletes
-	 * @param int $notrigger 0=triggers after, 1=disable triggers
-	 * @return int <0 if KO, >0 if OK
-	 */
-	function delete($user, $notrigger = 0) {
-		$error = 0;
-		
-		$result = $this->checkUsage();
-		
-		if ($result > 0) {
-			
-			$this->db->begin();
-			
-			// if (! $error) {
-			// if (! $notrigger) {
-			// Uncomment this and change MYOBJECT to your own tag if you
-			// want this action calls a trigger.
-			
-			// // Call triggers
-			// include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php';
-			// $interface=new Interfaces($this->db);
-			// $result=$interface->run_triggers('ACCOUNTANCY_ACCOUNT_DELETE',$this,$user,$langs,$conf);
-			// if ($result < 0) { $error++; $this->errors=$interface->errors; }
-			// // End call triggers
-			// }
-			// }
-			
-			if (! $error) {
-				$sql = "DELETE FROM " . MAIN_DB_PREFIX . "accounting_journal";
-				$sql .= " WHERE rowid=" . $this->id;
-				
-				dol_syslog(get_class($this) . "::delete sql=" . $sql);
-				$resql = $this->db->query($sql);
-				if (! $resql) {
-					$error ++;
-					$this->errors[] = "Error " . $this->db->lasterror();
-				}
-			}
-			
-			// Commit or rollback
-			if ($error) {
-				foreach ( $this->errors as $errmsg ) {
-					dol_syslog(get_class($this) . "::delete " . $errmsg, LOG_ERR);
-					$this->error .= ($this->error ? ', ' . $errmsg : $errmsg);
-				}
-				$this->db->rollback();
-				return - 1 * $error;
-			} else {
-				$this->db->commit();
-				return 1;
-			}
-		} else {
-			return - 1;
-		}
-	}
-	
 	/**
 	 * Return clicable name (with picto eventually)
 	 *
@@ -311,64 +109,6 @@ class AccountingJournal extends CommonObject
 		return $result;
 	}
 	
-	/**
-	 * Deactivate journal
-	 *
-	 * @param int $id Id
-	 * @return int <0 if KO, >0 if OK
-	 */
-	function journal_deactivate($id) {
-		$result = $this->checkUsage();
-		
-		if ($result > 0) {
-			$this->db->begin();
-			
-			$sql = "UPDATE " . MAIN_DB_PREFIX . "accounting_journal ";
-			$sql .= "SET active = '0'";
-			$sql .= " WHERE rowid = " . $this->db->escape($id);
-			
-			dol_syslog(get_class($this) . "::deactivate sql=" . $sql, LOG_DEBUG);
-			$result = $this->db->query($sql);
-			
-			if ($result) {
-				$this->db->commit();
-				return 1;
-			} else {
-				$this->error = $this->db->lasterror();
-				$this->db->rollback();
-				return - 1;
-			}
-		} else {
-			return - 1;
-		}
-	}
-	
-	/**
-	 * Activate journal
-	 *
-	 * @param int $id Id
-	 * @return int <0 if KO, >0 if OK
-	 */
-	function journal_activate($id) {
-		$this->db->begin();
-		
-		$sql = "UPDATE " . MAIN_DB_PREFIX . "accounting_journal ";
-		$sql .= "SET active = '1'";
-		$sql .= " WHERE rowid = " . $this->db->escape($id);
-		
-		dol_syslog(get_class($this) . "::activate sql=" . $sql, LOG_DEBUG);
-		$result = $this->db->query($sql);
-		if ($result) {
-			$this->db->commit();
-			return 1;
-		} else {
-			$this->error = $this->db->lasterror();
-			$this->db->rollback();
-			return - 1;
-		}
-	}
-	
-	
 	/**
 	 *  Retourne le libelle du statut d'un user (actif, inactif)
 	 *

+ 12 - 3
htdocs/accountancy/class/bookkeeping.class.php

@@ -169,7 +169,15 @@ class BookKeeping extends CommonObject
 		if (empty($this->numero_compte) || $this->numero_compte == '-1')
 		{
 		    $langs->load("errors");
-            $this->errors[]=$langs->trans('ErrorFieldAccountNotDefinedForBankLine', $this->fk_docdet);		    
+            if (in_array($this->doc_type, array('bank', 'expense_report')))
+            {
+		        $this->errors[]=$langs->trans('ErrorFieldAccountNotDefinedForBankLine', $this->fk_docdet,  $this->doc_type);
+            }
+            else
+            {
+                $this->errors[]=$langs->trans('ErrorFieldAccountNotDefinedForInvoiceLine', $this->fk_doc,  $this->doc_type);		    
+            }
+		    
 		    return -1;
 		}
 		
@@ -178,11 +186,12 @@ class BookKeeping extends CommonObject
 		
 		$this->piece_num = 0;
 		
-		// first check if line not yet in bookkeeping
+		// First check if line not yet already in bookkeeping
 		$sql = "SELECT count(*) as nb";
 		$sql .= " FROM " . MAIN_DB_PREFIX . $this->table_element;
 		$sql .= " WHERE doc_type = '" . $this->doc_type . "'";
-		$sql .= " AND fk_docdet = " . $this->fk_docdet;
+		$sql .= " AND fk_doc = " . $this->fk_doc;
+		$sql .= " AND fk_docdet = " . $this->fk_docdet;                   // This field can be 0 is record is for several lines 
 		$sql .= " AND numero_compte = '" . $this->numero_compte . "'";
 	    $sql .= " AND entity IN (" . getEntity("accountancy", 1) . ")";
 		

+ 12 - 4
htdocs/accountancy/customer/lines.php

@@ -43,6 +43,7 @@ $langs->load("productbatch");
 $account_parent = GETPOST('account_parent');
 $changeaccount = GETPOST('changeaccount');
 // Search Getpost
+$search_lineid = GETPOST('search_lineid', 'int');
 $search_ref = GETPOST('search_ref', 'alpha');
 $search_invoice = GETPOST('search_invoice', 'alpha');
 $search_label = GETPOST('search_label', 'alpha');
@@ -86,6 +87,7 @@ $formventilation = new FormVentilation($db);
 // Purge search criteria
 if (GETPOST("button_removefilter_x") || GETPOST("button_removefilter.x") || GETPOST("button_removefilter")) // All tests are required to be compatible with all browsers
 {
+    $search_lineid = '';
 	$search_ref = '';
 	$search_invoice = '';
 	$search_label = '';
@@ -151,7 +153,7 @@ print '<script type="text/javascript">
  * Customer Invoice lines
  */
 $sql = "SELECT f.rowid, f.facnumber, f.type, f.datef, f.ref_client,";
-$sql .= " fd.rowid as fdid, fd.description, fd.product_type, fd.total_ht, fd.total_tva, fd.tva_tx, fd.total_ttc,";
+$sql .= " fd.rowid, fd.description, fd.product_type, fd.total_ht, fd.total_tva, fd.tva_tx, fd.total_ttc,";
 $sql .= " s.rowid as socid, s.nom as name, s.code_compta, s.code_client,";
 $sql .= " p.rowid as product_id, p.ref as product_ref, p.label as product_label, p.accountancy_code_sell, aa.rowid as fk_compte, aa.account_number, aa.label as label_compte,";
 $sql .= " fd.situation_percent, co.label as country, s.tva_intra";
@@ -169,6 +171,9 @@ if (! empty($conf->global->FACTURE_DEPOSITS_ARE_JUST_PAYMENTS)) {
 } else {
 	$sql .= " AND f.type IN (" . Facture::TYPE_STANDARD . "," . Facture::TYPE_STANDARD . "," . Facture::TYPE_CREDIT_NOTE . "," . Facture::TYPE_DEPOSIT . "," . Facture::TYPE_SITUATION . ")";
 }
+if ($search_lineid) {
+    $sql .= natural_search("fd.rowid", $search_lineid, 1);
+}
 if (strlen(trim($search_invoice))) {
 	$sql .= natural_search("f.facnumber", $search_invoice);
 }
@@ -257,7 +262,7 @@ if ($result) {
 	print '<table class="tagtable liste'.($moreforfilter?" listwithfilterbefore":"").'">'."\n";
 	
 	print '<tr class="liste_titre_filter">';
-	print '<td class="liste_titre"></td>';
+	print '<td class="liste_titre"><input type="text" class="flat maxwidth50" name="search_lineid" value="' . dol_escape_htmltag($search_lineid) . '""></td>';
 	print '<td class="liste_titre"><input type="text" class="flat maxwidth50" name="search_invoice" value="' . dol_escape_htmltag($search_invoice) . '"></td>';
 	print '<td class="liste_titre"></td>';
 	print '<td class="liste_titre"><input type="text" class="flat maxwidth50" name="search_ref" value="' . dol_escape_htmltag($search_ref) . '"></td>';
@@ -328,13 +333,16 @@ if ($result) {
 		print '<td align="right">' . price($objp->total_ht) . '</td>';
 		print '<td align="center">' . price($objp->tva_tx) . '</td>';
 		print '<td>';
-		print $codecompta . ' <a href="./card.php?id=' . $objp->fdid . '">';
+		print $codecompta . ' <a href="./card.php?id=' . $objp->rowid . '">';
 		print img_edit();
 		print '</a>';
 		print '</td>';
+		
 		print '<td>' . $objp->country .'</td>';
+		
 		print '<td>' . $objp->tva_intra . '</td>';
-		print '<td class="center"><input type="checkbox" class="checkforaction" name="changeaccount[]" value="' . $objp->fdid . '"/></td>';
+		
+		print '<td class="center"><input type="checkbox" class="checkforaction" name="changeaccount[]" value="' . $objp->rowid . '"/></td>';
 
 		print "</tr>";
 		$i ++;

+ 7 - 2
htdocs/accountancy/customer/list.php

@@ -52,6 +52,7 @@ $toselect = GETPOST('toselect', 'array');
 $mesCasesCochees = GETPOST('toselect', 'array');
 
 // Search Getpost
+$search_lineid = GETPOST('search_lineid', 'int');
 $search_invoice = GETPOST('search_invoice', 'alpha');
 $search_ref = GETPOST('search_ref', 'alpha');
 $search_label = GETPOST('search_label', 'alpha');
@@ -100,6 +101,7 @@ if (! GETPOST('confirmmassaction') && $massaction != 'presend' && $massaction !=
 // Purge search criteria
 if (GETPOST("button_removefilter_x") || GETPOST("button_removefilter.x") || GETPOST("button_removefilter")) // All test are required to be compatible with all browsers
 {
+    $search_lineid = '';
 	$search_ref = '';
 	$search_invoice = '';
 	$search_label = '';
@@ -177,7 +179,7 @@ llxHeader('', $langs->trans("Ventilation"));
 
 // Customer Invoice lines
 $sql = "SELECT f.facnumber, f.rowid as facid, f.datef, f.type as ftype,";
-$sql .= " l.fk_product, l.description, l.total_ht, l.rowid, l.fk_code_ventilation, l.product_type as type_l, l.tva_tx as tva_tx_line,";
+$sql .= " l.rowid, l.fk_product, l.description, l.total_ht, l.fk_code_ventilation, l.product_type as type_l, l.tva_tx as tva_tx_line,";
 $sql .= " p.rowid as product_id, p.ref as product_ref, p.label as product_label, p.fk_product_type as type, p.accountancy_code_sell as code_sell, p.tva_tx as tva_tx_prod,";
 $sql .= " aa.rowid as aarowid";
 $sql .= " FROM " . MAIN_DB_PREFIX . "facture as f";
@@ -189,6 +191,9 @@ $sql .= " WHERE f.fk_statut > 0 AND l.fk_code_ventilation <= 0";
 $sql .= " AND product_type <= 2";
 $sql .= " AND (accsys.rowid='" . $conf->global->CHARTOFACCOUNTS . "' OR p.accountancy_code_sell IS NULL OR p.accountancy_code_sell ='')";
 // Add search filter like
+if ($search_lineid) {
+    $sql .= natural_search("l.rowid", $search_lineid, 1);
+}
 if (strlen(trim($search_invoice))) {
     $sql .= natural_search("f.facnumber",$search_invoice);
 }
@@ -274,7 +279,7 @@ if ($result) {
 
 	// We add search filter
 	print '<tr class="liste_titre_filter">';
-	print '<td class="liste_titre"></td>';
+	print '<td class="liste_titre"><input type="text" class="flat maxwidth50" name="search_lineid" value="' . dol_escape_htmltag($search_lineid) . '""></td>';
 	print '<td class="liste_titre"><input type="text" class="flat maxwidth50" name="search_invoice" value="' . dol_escape_htmltag($search_invoice) . '"></td>';
 	print '<td class="liste_titre"></td>';
 	print '<td class="liste_titre"><input type="text" class="flat maxwidth50" name="search_ref" value="' . dol_escape_htmltag($search_ref) . '"></td>';

+ 11 - 5
htdocs/accountancy/index.php

@@ -71,6 +71,10 @@ print "<br>\n";
 
 // STEPS
 $step++;
+print img_picto('', 'puce').' '.$langs->trans("AccountancyAreaDescJournalSetup", $step, '<strong>'.$langs->transnoentitiesnoconv("MenuFinancial").'-'.$langs->transnoentitiesnoconv("MenuAccountancy").'-'.$langs->transnoentitiesnoconv("Setup")."-".$langs->transnoentitiesnoconv("AccountingJournals").'</strong>');
+print "<br>\n";
+print "<br>\n";
+$step++;
 print img_picto('', 'puce').' '.$langs->trans("AccountancyAreaDescChartModel", $step, '<strong>'.$langs->transnoentitiesnoconv("MenuFinancial").'-'.$langs->transnoentitiesnoconv("MenuAccountancy").'-'.$langs->transnoentitiesnoconv("Setup")."-".$langs->transnoentitiesnoconv("Pcg_version").'</strong>');
 print "<br>\n";
 print "<br>\n";
@@ -148,24 +152,26 @@ print '<hr>';
 print "<br>\n";
 $step = 0;
 
+$langs->loadLangs(array('bills', 'trips'));
+
 $step++;
-print img_picto('', 'puce').' '.$langs->trans("AccountancyAreaDescCustomer", $step, '<strong>'.$langs->transnoentitiesnoconv("MenuFinancial").'-'.$langs->transnoentitiesnoconv("MenuAccountancy")."-".$langs->transnoentitiesnoconv("CustomersVentilation").'</strong>')."<br>\n";
+print img_picto('', 'puce').' '.$langs->trans("AccountancyAreaDescBind", chr(64+$step), $langs->transnoentitiesnoconv("BillsCustomers"), '<strong>'.$langs->transnoentitiesnoconv("MenuFinancial").'-'.$langs->transnoentitiesnoconv("MenuAccountancy")."-".$langs->transnoentitiesnoconv("CustomersVentilation").'</strong>')."<br>\n";
 print "<br>\n";
 
 $step++;
-print img_picto('', 'puce').' '.$langs->trans("AccountancyAreaDescSupplier", $step, '<strong>'.$langs->transnoentitiesnoconv("MenuFinancial").'-'.$langs->transnoentitiesnoconv("MenuAccountancy")."-".$langs->transnoentitiesnoconv("SuppliersVentilation").'</strong>')."<br>\n";
+print img_picto('', 'puce').' '.$langs->trans("AccountancyAreaDescBind", chr(64+$step), $langs->transnoentitiesnoconv("BillsSuppliers"), '<strong>'.$langs->transnoentitiesnoconv("MenuFinancial").'-'.$langs->transnoentitiesnoconv("MenuAccountancy")."-".$langs->transnoentitiesnoconv("SuppliersVentilation").'</strong>')."<br>\n";
 print "<br>\n";
 
 $step++;
-print img_picto('', 'puce').' '.$langs->trans("AccountancyAreaDescExpenseReport", $step, '<strong>'.$langs->transnoentitiesnoconv("MenuFinancial").'-'.$langs->transnoentitiesnoconv("MenuAccountancy")."-".$langs->transnoentitiesnoconv("ExpenseReportsVentilation").'</strong>')."<br>\n";
+print img_picto('', 'puce').' '.$langs->trans("AccountancyAreaDescBind", chr(64+$step), $langs->transnoentitiesnoconv("ExpenseReports"), '<strong>'.$langs->transnoentitiesnoconv("MenuFinancial").'-'.$langs->transnoentitiesnoconv("MenuAccountancy")."-".$langs->transnoentitiesnoconv("ExpenseReportsVentilation").'</strong>')."<br>\n";
 print "<br>\n";
 
 $step++;
-print img_picto('', 'puce').' '.$langs->trans("AccountancyAreaDescWriteRecords", $step)."<br>\n";
+print img_picto('', 'puce').' '.$langs->trans("AccountancyAreaDescWriteRecords", chr(64+$step), $langs->transnoentitiesnoconv("Journalization"), $langs->transnoentitiesnoconv("WriteBookKeeping"))."<br>\n";
 print "<br>\n";
 
 $step++;
-print img_picto('', 'puce').' '.$langs->trans("AccountancyAreaDescAnalyze", $step)."<br>\n";
+print img_picto('', 'puce').' '.$langs->trans("AccountancyAreaDescAnalyze", chr(64+$step))."<br>\n";
 print "<br>\n";
 
 llxFooter();

+ 154 - 140
htdocs/accountancy/journal/bankjournal.php

@@ -106,7 +106,7 @@ if (empty($date_start) || empty($date_end)) // We define date_start and date_end
 $p = explode(":", $conf->global->MAIN_INFO_SOCIETE_COUNTRY);
 $idpays = $p[0];
 
-$sql  = "SELECT b.rowid , b.dateo as do, b.datev as dv, b.amount, b.label, b.rappro, b.num_releve, b.num_chq, b.fk_type,";
+$sql  = "SELECT b.rowid, b.dateo as do, b.datev as dv, b.amount, b.label, b.rappro, b.num_releve, b.num_chq, b.fk_type,";
 $sql .= " ba.courant, ba.ref as baref, ba.account_number,";
 $sql .= " soc.code_compta, soc.code_compta_fournisseur, soc.rowid as socid, soc.nom as name, bu1.type as typeop,";
 $sql .= " u.accountancy_code, u.rowid as userid, u.lastname as name, u.firstname as firstname, bu2.type as typeop";
@@ -341,79 +341,81 @@ if (! $error && $action == 'writebookkeeping') {
 		    // Line into bank account
     		foreach ( $tabbq[$key] as $k => $mt ) 
     		{
-    			$bookkeeping = new BookKeeping($db);
-    			$bookkeeping->doc_date = $val["date"];
-    			$bookkeeping->doc_ref = $val["ref"];
-    			$bookkeeping->doc_type = 'bank';
-    			$bookkeeping->fk_doc = $key;
-    			$bookkeeping->fk_docdet = $val["fk_bank"];
-    			$bookkeeping->numero_compte = $k;
-    			$bookkeeping->label_compte = $compte->label;
-    			$bookkeeping->montant = ($mt < 0 ? - $mt : $mt);
-    			$bookkeeping->sens = ($mt >= 0) ? 'D' : 'C';
-    			$bookkeeping->debit = ($mt >= 0 ? $mt : 0);
-    			$bookkeeping->credit = ($mt < 0 ? - $mt : 0);
-    			$bookkeeping->code_journal = $journal;
-    			$bookkeeping->fk_user_author = $user->id;
-    			$bookkeeping->date_create = $now;
+    			if ($mt) {
+        		    $bookkeeping = new BookKeeping($db);
+        			$bookkeeping->doc_date = $val["date"];
+        			$bookkeeping->doc_ref = $val["ref"];
+        			$bookkeeping->doc_type = 'bank';
+        			$bookkeeping->fk_doc = $key;
+        			$bookkeeping->fk_docdet = $val["fk_bank"];
+        			$bookkeeping->numero_compte = $k;
+        			$bookkeeping->label_compte = $compte->label;
+        			$bookkeeping->montant = ($mt < 0 ? - $mt : $mt);
+        			$bookkeeping->sens = ($mt >= 0) ? 'D' : 'C';
+        			$bookkeeping->debit = ($mt >= 0 ? $mt : 0);
+        			$bookkeeping->credit = ($mt < 0 ? - $mt : 0);
+        			$bookkeeping->code_journal = $journal;
+        			$bookkeeping->fk_user_author = $user->id;
+        			$bookkeeping->date_create = $now;
+        
+        			if ($tabtype[$key] == 'payment') {
+        			    $bookkeeping->code_tiers = $tabcompany[$key]['code_compta'];
     
-    			if ($tabtype[$key] == 'payment') {
-    			    $bookkeeping->code_tiers = $tabcompany[$key]['code_compta'];
-
-    				$sqlmid = 'SELECT fac.facnumber';
-    				$sqlmid .= " FROM " . MAIN_DB_PREFIX . "facture fac";
-    				$sqlmid .= " INNER JOIN " . MAIN_DB_PREFIX . "paiement_facture as payfac ON payfac.fk_facture=fac.rowid";
-    				$sqlmid .= " INNER JOIN " . MAIN_DB_PREFIX . "paiement as pay ON  payfac.fk_paiement=pay.rowid";
-    				$sqlmid .= " WHERE pay.fk_bank=" . $key;
-    				dol_syslog("accountancy/journal/bankjournal.php:: sqlmid=" . $sqlmid, LOG_DEBUG);
-    				$resultmid = $db->query($sqlmid);
-    				if ($resultmid) {
-    					$objmid = $db->fetch_object($resultmid);
-    					$bookkeeping->doc_ref = $objmid->facnumber;    // Ref of invoice
-    				}
-    			} else if ($tabtype[$key] == 'payment_supplier') {
-    			    $bookkeeping->code_tiers = $tabcompany[$key]['code_compta'];
-
-    				$sqlmid = 'SELECT facf.ref_supplier, facf.ref';
-    				$sqlmid .= " FROM " . MAIN_DB_PREFIX . "facture_fourn facf";
-    				$sqlmid .= " INNER JOIN " . MAIN_DB_PREFIX . "paiementfourn_facturefourn as payfacf ON payfacf.fk_facturefourn=facf.rowid";
-    				$sqlmid .= " INNER JOIN " . MAIN_DB_PREFIX . "paiementfourn as payf ON  payfacf.fk_paiementfourn=payf.rowid";
-    				$sqlmid .= " WHERE payf.fk_bank=" . $key;
-    				dol_syslog("accountancy/journal/bankjournal.php:: sqlmid=" . $sqlmid, LOG_DEBUG);
-    				$resultmid = $db->query($sqlmid);
-    				if ($resultmid) {
-    					$objmid = $db->fetch_object($resultmid);
-    					$bookkeeping->doc_ref = $objmid->ref_supplier . ' (' . $objmid->ref . ')'; // Ref on invoice
-    				}
-    			} else if ($tabtype[$key] == 'payment_expensereport') {
-    			    $bookkeeping->code_tiers = $tabuser[$key]['accountancy_code'];
-
-    				$sqlmid = 'SELECT e.ref';
-    				$sqlmid .= " FROM " . MAIN_DB_PREFIX . "expensereport as e";
-    				$sqlmid .= " INNER JOIN " . MAIN_DB_PREFIX . "payment_expensereport as payer ON payer.fk_expensereport=e.rowid";
-    				$sqlmid .= " WHERE payer.fk_expensereport=" . $val["fk_expensereport"];
-    				dol_syslog("accountancy/journal/bankjournal.php:: sqlmid=" . $sqlmid, LOG_DEBUG);
-    				$resultmid = $db->query($sqlmid);
-    				if ($resultmid) {
-    					$objmid = $db->fetch_object($resultmid);
-    					$bookkeeping->doc_ref = $objmid->ref; // Ref of expensereport
-    				}
-    			}
+        				$sqlmid = 'SELECT fac.facnumber';
+        				$sqlmid .= " FROM " . MAIN_DB_PREFIX . "facture fac";
+        				$sqlmid .= " INNER JOIN " . MAIN_DB_PREFIX . "paiement_facture as payfac ON payfac.fk_facture=fac.rowid";
+        				$sqlmid .= " INNER JOIN " . MAIN_DB_PREFIX . "paiement as pay ON  payfac.fk_paiement=pay.rowid";
+        				$sqlmid .= " WHERE pay.fk_bank=" . $key;
+        				dol_syslog("accountancy/journal/bankjournal.php:: sqlmid=" . $sqlmid, LOG_DEBUG);
+        				$resultmid = $db->query($sqlmid);
+        				if ($resultmid) {
+        					$objmid = $db->fetch_object($resultmid);
+        					$bookkeeping->doc_ref = $objmid->facnumber;    // Ref of invoice
+        				}
+        			} else if ($tabtype[$key] == 'payment_supplier') {
+        			    $bookkeeping->code_tiers = $tabcompany[$key]['code_compta'];
+    
+        				$sqlmid = 'SELECT facf.ref_supplier, facf.ref';
+        				$sqlmid .= " FROM " . MAIN_DB_PREFIX . "facture_fourn facf";
+        				$sqlmid .= " INNER JOIN " . MAIN_DB_PREFIX . "paiementfourn_facturefourn as payfacf ON payfacf.fk_facturefourn=facf.rowid";
+        				$sqlmid .= " INNER JOIN " . MAIN_DB_PREFIX . "paiementfourn as payf ON  payfacf.fk_paiementfourn=payf.rowid";
+        				$sqlmid .= " WHERE payf.fk_bank=" . $key;
+        				dol_syslog("accountancy/journal/bankjournal.php:: sqlmid=" . $sqlmid, LOG_DEBUG);
+        				$resultmid = $db->query($sqlmid);
+        				if ($resultmid) {
+        					$objmid = $db->fetch_object($resultmid);
+        					$bookkeeping->doc_ref = $objmid->ref_supplier . ' (' . $objmid->ref . ')'; // Ref on invoice
+        				}
+        			} else if ($tabtype[$key] == 'payment_expensereport') {
+        			    $bookkeeping->code_tiers = $tabuser[$key]['accountancy_code'];
     
-    			$result = $bookkeeping->create($user);
-    			if ($result < 0) {
-    				if ($bookkeeping->error == 'BookkeepingRecordAlreadyExists')	// Already exists
-    				{
-    					$error++;
-    					$errorforline++;
-    					//setEventMessages('Transaction for ('.$bookkeeping->doc_type.', '.$bookkeeping->doc_ref.', '.$bookkeeping->fk_docdet.') were already recorded', null, 'warnings');
-    				}
-    				else
-    				{
-	    				$error++;
-	    				$errorforline++;
-	    				setEventMessages($bookkeeping->error, $bookkeeping->errors, 'errors');
-    				}
+        				$sqlmid = 'SELECT e.ref';
+        				$sqlmid .= " FROM " . MAIN_DB_PREFIX . "expensereport as e";
+        				$sqlmid .= " INNER JOIN " . MAIN_DB_PREFIX . "payment_expensereport as payer ON payer.fk_expensereport=e.rowid";
+        				$sqlmid .= " WHERE payer.fk_expensereport=" . $val["fk_expensereport"];
+        				dol_syslog("accountancy/journal/bankjournal.php:: sqlmid=" . $sqlmid, LOG_DEBUG);
+        				$resultmid = $db->query($sqlmid);
+        				if ($resultmid) {
+        					$objmid = $db->fetch_object($resultmid);
+        					$bookkeeping->doc_ref = $objmid->ref; // Ref of expensereport
+        				}
+        			}
+        
+        			$result = $bookkeeping->create($user);
+        			if ($result < 0) {
+        				if ($bookkeeping->error == 'BookkeepingRecordAlreadyExists')	// Already exists
+        				{
+        					$error++;
+        					$errorforline++;
+        					//setEventMessages('Transaction for ('.$bookkeeping->doc_type.', '.$bookkeeping->doc_ref.', '.$bookkeeping->fk_docdet.') were already recorded', null, 'warnings');
+        				}
+        				else
+        				{
+    	    				$error++;
+    	    				$errorforline++;
+    	    				setEventMessages($bookkeeping->error, $bookkeeping->errors, 'errors');
+        				}
+        			}
     			}
     		}
 		}
@@ -423,65 +425,76 @@ if (! $error && $action == 'writebookkeeping') {
 		{
 		    // Line into thirdparty account
     		foreach ( $tabtp[$key] as $k => $mt ) {
-    			$bookkeeping = new BookKeeping($db);
-    			$bookkeeping->doc_date = $val["date"];
-    			$bookkeeping->doc_ref = $val["ref"];
-    			$bookkeeping->doc_type = 'bank';
-    			$bookkeeping->fk_doc = $key;
-    			$bookkeeping->fk_docdet = $val["fk_bank"];
-    			$bookkeeping->label_compte = $tabcompany[$key]['name'];
-    			$bookkeeping->montant = ($mt < 0 ? - $mt : $mt);
-    			$bookkeeping->sens = ($mt < 0) ? 'D' : 'C';
-    			$bookkeeping->debit = ($mt < 0 ? - $mt : 0);
-    			$bookkeeping->credit = ($mt >= 0) ? $mt : 0;
-    			$bookkeeping->code_journal = $journal;
-    			$bookkeeping->fk_user_author = $user->id;
-    			$bookkeeping->date_create = $now;
-    
-    			if (in_array($tabtype[$key], array('sc', 'payment_sc'))) {   // If payment is payment of social contribution
-    				$bookkeeping->code_tiers = '';
-    				$bookkeeping->numero_compte = $k;
-    			} else if ($tabtype[$key] == 'payment') {    // If payment is payment of customer invoice, we get ref of invoice
-    				$sqlmid = 'SELECT fac.facnumber';
-    				$sqlmid .= " FROM " . MAIN_DB_PREFIX . "facture fac ";
-    				$sqlmid .= " INNER JOIN " . MAIN_DB_PREFIX . "paiement_facture as payfac ON  payfac.fk_facture=fac.rowid";
-    				$sqlmid .= " INNER JOIN " . MAIN_DB_PREFIX . "paiement as pay ON  payfac.fk_paiement=pay.rowid";
-    				$sqlmid .= " WHERE pay.fk_bank=" . $key;
-    				dol_syslog("accountancy/journal/bankjournal.php:: sqlmid=" . $sqlmid, LOG_DEBUG);
-    				$resultmid = $db->query($sqlmid);
-    				if ($resultmid) {
-    					$objmid = $db->fetch_object($resultmid);
-    					$bookkeeping->doc_ref = $objmid->facnumber;
-    				}
-    				$bookkeeping->code_tiers = $tabcompany[$key]['code_compta'];
-    				$bookkeeping->numero_compte = $k;
-    			} else if ($tabtype[$key] == 'payment_supplier') {           // If payment is payment of supplier invoice, we get ref of invoice
-    
-    				$sqlmid = 'SELECT facf.ref_supplier,facf.ref';
-    				$sqlmid .= " FROM " . MAIN_DB_PREFIX . "facture_fourn facf ";
-    				$sqlmid .= " INNER JOIN " . MAIN_DB_PREFIX . "paiementfourn_facturefourn as payfacf ON  payfacf.fk_facturefourn=facf.rowid";
-    				$sqlmid .= " INNER JOIN " . MAIN_DB_PREFIX . "paiementfourn as payf ON  payfacf.fk_paiementfourn=payf.rowid";
-    				$sqlmid .= " WHERE payf.fk_bank=" . $key;
-    				dol_syslog("accountancy/journal/bankjournal.php:: sqlmid=" . $sqlmid, LOG_DEBUG);
-    				$resultmid = $db->query($sqlmid);
-    				if ($resultmid) {
-    					$objmid = $db->fetch_object($resultmid);
-    					$bookkeeping->doc_ref = $objmid->ref_supplier . ' (' . $objmid->ref . ')';
-    				}
-                    $bookkeeping->code_tiers = $tabcompany[$key]['code_compta'];
-    				$bookkeeping->numero_compte = $k;
-    			} else {
-    			    // FIXME Should be a temporary account ???
-    				$bookkeeping->doc_ref = $k;
-    				//$bookkeeping->numero_compte = $conf->global->ACCOUNTING_ACCOUNT_CUSTOMER;
-    				$bookkeeping->numero_compte = 'CodeNotDef';
-    			}
-    
-    			$result = $bookkeeping->create($user);
-    			if ($result < 0) {
-    				$error++;
-    				$errorforline++;
-    				setEventMessages($bookkeeping->error, $bookkeeping->errors, 'errors');
+    			if ($mt) {
+        		    $bookkeeping = new BookKeeping($db);
+        			$bookkeeping->doc_date = $val["date"];
+        			$bookkeeping->doc_ref = $val["ref"];
+        			$bookkeeping->doc_type = 'bank';
+        			$bookkeeping->fk_doc = $key;
+        			$bookkeeping->fk_docdet = $val["fk_bank"];
+        			$bookkeeping->label_compte = $tabcompany[$key]['name'];
+        			$bookkeeping->montant = ($mt < 0 ? - $mt : $mt);
+        			$bookkeeping->sens = ($mt < 0) ? 'D' : 'C';
+        			$bookkeeping->debit = ($mt < 0 ? - $mt : 0);
+        			$bookkeeping->credit = ($mt >= 0) ? $mt : 0;
+        			$bookkeeping->code_journal = $journal;
+        			$bookkeeping->fk_user_author = $user->id;
+        			$bookkeeping->date_create = $now;
+        
+        			if (in_array($tabtype[$key], array('sc', 'payment_sc'))) {   // If payment is payment of social contribution
+        				$bookkeeping->code_tiers = '';
+        				$bookkeeping->numero_compte = $k;
+        			} else if ($tabtype[$key] == 'payment') {    // If payment is payment of customer invoice, we get ref of invoice
+        				$sqlmid = 'SELECT fac.facnumber';
+        				$sqlmid .= " FROM " . MAIN_DB_PREFIX . "facture fac ";
+        				$sqlmid .= " INNER JOIN " . MAIN_DB_PREFIX . "paiement_facture as payfac ON  payfac.fk_facture=fac.rowid";
+        				$sqlmid .= " INNER JOIN " . MAIN_DB_PREFIX . "paiement as pay ON  payfac.fk_paiement=pay.rowid";
+        				$sqlmid .= " WHERE pay.fk_bank=" . $key;
+        				dol_syslog("accountancy/journal/bankjournal.php:: sqlmid=" . $sqlmid, LOG_DEBUG);
+        				$resultmid = $db->query($sqlmid);
+        				if ($resultmid) {
+        					$objmid = $db->fetch_object($resultmid);
+        					$bookkeeping->doc_ref = $objmid->facnumber;
+        				}
+        				$bookkeeping->code_tiers = $tabcompany[$key]['code_compta'];
+        				$bookkeeping->numero_compte = $k;
+        			} else if ($tabtype[$key] == 'payment_supplier') {           // If payment is payment of supplier invoice, we get ref of invoice
+        
+        				$sqlmid = 'SELECT facf.ref_supplier,facf.ref';
+        				$sqlmid .= " FROM " . MAIN_DB_PREFIX . "facture_fourn facf ";
+        				$sqlmid .= " INNER JOIN " . MAIN_DB_PREFIX . "paiementfourn_facturefourn as payfacf ON  payfacf.fk_facturefourn=facf.rowid";
+        				$sqlmid .= " INNER JOIN " . MAIN_DB_PREFIX . "paiementfourn as payf ON  payfacf.fk_paiementfourn=payf.rowid";
+        				$sqlmid .= " WHERE payf.fk_bank=" . $key;
+        				dol_syslog("accountancy/journal/bankjournal.php:: sqlmid=" . $sqlmid, LOG_DEBUG);
+        				$resultmid = $db->query($sqlmid);
+        				if ($resultmid) {
+        					$objmid = $db->fetch_object($resultmid);
+        					$bookkeeping->doc_ref = $objmid->ref_supplier . ' (' . $objmid->ref . ')';
+        				}
+                        $bookkeeping->code_tiers = $tabcompany[$key]['code_compta'];
+        				$bookkeeping->numero_compte = $k;
+        			} else {
+        			    // FIXME Should be a temporary account ???
+        				$bookkeeping->doc_ref = $k;
+        				//$bookkeeping->numero_compte = $conf->global->ACCOUNTING_ACCOUNT_CUSTOMER;
+        				$bookkeeping->numero_compte = 'CodeNotDef';
+        			}
+        
+        			$result = $bookkeeping->create($user);
+        			if ($result < 0) {
+        				if ($bookkeeping->error == 'BookkeepingRecordAlreadyExists')	// Already exists
+        				{
+        					$error++;
+        					$errorforline++;
+        					//setEventMessages('Transaction for ('.$bookkeeping->doc_type.', '.$bookkeeping->doc_ref.', '.$bookkeeping->fk_docdet.') were already recorded', null, 'warnings');
+        				}
+        				else
+        				{
+    	    				$error++;
+    	    				$errorforline++;
+    	    				setEventMessages($bookkeeping->error, $bookkeeping->errors, 'errors');
+        				}
+        			}
     			}
     		}
 		}
@@ -512,6 +525,7 @@ if (! $error && $action == 'writebookkeeping') {
 }
 
 // Export
+/*
 if ($action == 'export_csv') {
 	$sep = $conf->global->ACCOUNTING_EXPORT_SEPARATORCSV;
 
@@ -678,8 +692,7 @@ if ($action == 'export_csv') {
 		}
 	}
 }
-
-
+*/
 
 
 /*
@@ -702,18 +715,19 @@ if (empty($action) || $action == 'view') {
 	$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);
 
 	$varlink = 'id_account=' . $id_bank_account;
-	report_header($nom, $nomlink, $period, $periodlink, $description, $builddate, $exportlink, array (
-			'action' => ''
-	), '', $varlink);
+	
+	journalHead($nom, $nomlink, $period, $periodlink, $description, $builddate, $exportlink, array('action' => ''), '', $varlink);
 
-	if ($conf->global->ACCOUNTING_EXPORT_MODELCSV != 1 && $conf->global->ACCOUNTING_EXPORT_MODELCSV != 2) {
+	/*if ($conf->global->ACCOUNTING_EXPORT_MODELCSV != 1 && $conf->global->ACCOUNTING_EXPORT_MODELCSV != 2) {
 		print '<input type="button" class="butActionRefused" style="float: right;" value="' . $langs->trans('Export') . '" disabled="disabled" title="' . $langs->trans('ExportNotSupported') . '"/>';
 	} else {
 		print '<input type="button" class="butAction" style="float: right;" value="' . $langs->trans("Export") . '" onclick="launch_export();" />';
-	}
+	}*/
 
+    print '<div class="tabsAction">';
 	print '<input type="button" class="butAction" value="' . $langs->trans("WriteBookKeeping") . '" onclick="writebookkeeping();" />';
-
+    print '</div>';
+    
 	// TODO Avoid using js. We can use a direct link with $param
 	print '
 	<script type="text/javascript">
@@ -734,7 +748,7 @@ if (empty($action) || $action == 'view') {
 	/*
 	 * Show result array
 	 */
-	print '<br><br>';
+	print '<br>';
 
 	$i = 0;
 	print "<table class=\"noborder\" width=\"100%\">";

+ 147 - 105
htdocs/accountancy/journal/expensereportsjournal.php

@@ -157,100 +157,140 @@ if ($action == 'writebookkeeping') {
 	{
 		$errorforline = 0;
 
-		foreach ( $tabttc[$key] as $k => $mt ) {
-			// get compte id and label
-
-			$bookkeeping = new BookKeeping($db);
-			$bookkeeping->doc_date = $val["date"];
-			$bookkeeping->doc_ref = $val["ref"];
-			$bookkeeping->date_create = $now;
-			$bookkeeping->doc_type = 'expense_report';
-			$bookkeeping->fk_doc = $key;
-			$bookkeeping->fk_docdet = $val["fk_expensereportdet"];
-			$bookkeeping->code_tiers = $tabuser[$key]['user_accountancy_code'];
-			$bookkeeping->label_compte = $tabuser[$key]['name'];
-			$bookkeeping->numero_compte = $conf->global->SALARIES_ACCOUNTING_ACCOUNT_PAYMENT;
-			$bookkeeping->montant = $mt;
-			$bookkeeping->sens = ($mt >= 0) ? 'C' : 'D';
-			$bookkeeping->debit = ($mt <= 0) ? $mt : 0;
-			$bookkeeping->credit = ($mt > 0) ? $mt : 0;
-			$bookkeeping->code_journal = $conf->global->ACCOUNTING_EXPENSEREPORT_JOURNAL;
-			$bookkeeping->fk_user_author = $user->id;
-
-			$result = $bookkeeping->create($user);
-			if ($result < 0) {
-				$error++;
-				$errorforline++;
-				setEventMessages($bookkeeping->error, $bookkeeping->errors, 'errors');
-			}
-		}
-
-		// Fees
-		foreach ( $tabht[$key] as $k => $mt ) {
-			$accountingaccount = new AccountingAccount($db);
-			$accountingaccount->fetch(null, $k, true);
-			if ($mt) {
-				// get compte id and label
-				$accountingaccount = new AccountingAccount($db);
-				if ($accountingaccount->fetch(null, $k, true)) {
-					$bookkeeping = new BookKeeping($db);
-					$bookkeeping->doc_date = $val["date"];
-					$bookkeeping->doc_ref = $val["ref"];
-					$bookkeeping->date_create = $now;
-					$bookkeeping->doc_type = 'expense_report';
-					$bookkeeping->fk_doc = $key;
-					$bookkeeping->fk_docdet = $val["fk_expensereportdet"];
-					$bookkeeping->code_tiers = '';
-					$bookkeeping->label_compte = $accountingaccount->label;
-					$bookkeeping->numero_compte = $k;
-					$bookkeeping->montant = $mt;
-					$bookkeeping->sens = ($mt < 0) ? 'C' : 'D';
-					$bookkeeping->debit = ($mt > 0) ? $mt : 0;
-					$bookkeeping->credit = ($mt <= 0) ? $mt : 0;
-					$bookkeeping->code_journal = $conf->global->ACCOUNTING_EXPENSEREPORT_JOURNAL;
-					$bookkeeping->fk_user_author = $user->id;
-
-					$result = $bookkeeping->create($user);
-					if ($result < 0) {
-						$error++;
-						$errorforline++;
-						setEventMessages($bookkeeping->error, $bookkeeping->errors, 'errors');
-					}
-				}
-			}
-		}
-
-		// VAT
-		// var_dump($tabtva);
-		foreach ( $tabtva[$key] as $k => $mt ) {
-			if ($mt) {
-				// get compte id and label
-				$bookkeeping = new BookKeeping($db);
-				$bookkeeping->doc_date = $val["date"];
-				$bookkeeping->doc_ref = $val["ref"];
-				$bookkeeping->date_create = $now;
-				$bookkeeping->doc_type = 'expense_report';
-				$bookkeeping->fk_doc = $key;
-				$bookkeeping->fk_docdet = $val["fk_expensereportdet"];
-				$bookkeeping->code_tiers = '';
-				$bookkeeping->label_compte = $langs->trans("VAT"). ' '.$def_tva[$key];
-				$bookkeeping->numero_compte = $k;
-				$bookkeeping->montant = $mt;
-				$bookkeeping->sens = ($mt < 0) ? 'C' : 'D';
-				$bookkeeping->debit = ($mt > 0) ? $mt : 0;
-				$bookkeeping->credit = ($mt <= 0) ? $mt : 0;
-				$bookkeeping->code_journal = $conf->global->ACCOUNTING_EXPENSEREPORT_JOURNAL;
-				$bookkeeping->fk_user_author = $user->id;
-
-				$result = $bookkeeping->create($user);
-				if ($result < 0) {
-					$error++;
-					$errorforline++;
-					setEventMessages($object->error, $object->errors, 'errors');
-				}
-			}
-		}
-
+	    $db->begin();
+	     
+        if (! $errorforline)
+        {
+    	    foreach ( $tabttc[$key] as $k => $mt ) {
+    			if ($mt) {
+        	        // get compte id and label
+        
+        			$bookkeeping = new BookKeeping($db);
+        			$bookkeeping->doc_date = $val["date"];
+        			$bookkeeping->doc_ref = $val["ref"];
+        			$bookkeeping->date_create = $now;
+        			$bookkeeping->doc_type = 'expense_report';
+        			$bookkeeping->fk_doc = $key;
+        			$bookkeeping->fk_docdet = $val["fk_expensereportdet"];
+        			$bookkeeping->code_tiers = $tabuser[$key]['user_accountancy_code'];
+        			$bookkeeping->label_compte = $tabuser[$key]['name'];
+        			$bookkeeping->numero_compte = $conf->global->SALARIES_ACCOUNTING_ACCOUNT_PAYMENT;
+        			$bookkeeping->montant = $mt;
+        			$bookkeeping->sens = ($mt >= 0) ? 'C' : 'D';
+        			$bookkeeping->debit = ($mt <= 0) ? $mt : 0;
+        			$bookkeeping->credit = ($mt > 0) ? $mt : 0;
+        			$bookkeeping->code_journal = $conf->global->ACCOUNTING_EXPENSEREPORT_JOURNAL;
+        			$bookkeeping->fk_user_author = $user->id;
+        
+        			$result = $bookkeeping->create($user);
+        			if ($result < 0) {
+        			    if ($bookkeeping->error == 'BookkeepingRecordAlreadyExists')	// Already exists
+        			    {
+        			        $error++;
+        			        $errorforline++;
+        			        //setEventMessages('Transaction for ('.$bookkeeping->doc_type.', '.$bookkeeping->doc_ref.', '.$bookkeeping->fk_docdet.') were already recorded', null, 'warnings');
+        			    }
+        			    else
+        			    {
+        			        $error++;
+        			        $errorforline++;
+        			        setEventMessages($bookkeeping->error, $bookkeeping->errors, 'errors');
+        			    }
+        			}
+    			}
+    		}
+        }
+        
+        if (! $errorforline)
+        {
+            // Fees
+    		foreach ( $tabht[$key] as $k => $mt ) {
+    			$accountingaccount = new AccountingAccount($db);
+    			$accountingaccount->fetch(null, $k, true);
+    			if ($mt) {
+    				// get compte id and label
+    				$accountingaccount = new AccountingAccount($db);
+    				if ($accountingaccount->fetch(null, $k, true)) {
+    					$bookkeeping = new BookKeeping($db);
+    					$bookkeeping->doc_date = $val["date"];
+    					$bookkeeping->doc_ref = $val["ref"];
+    					$bookkeeping->date_create = $now;
+    					$bookkeeping->doc_type = 'expense_report';
+    					$bookkeeping->fk_doc = $key;
+    					$bookkeeping->fk_docdet = $val["fk_expensereportdet"];
+    					$bookkeeping->code_tiers = '';
+    					$bookkeeping->label_compte = $accountingaccount->label;
+    					$bookkeeping->numero_compte = $k;
+    					$bookkeeping->montant = $mt;
+    					$bookkeeping->sens = ($mt < 0) ? 'C' : 'D';
+    					$bookkeeping->debit = ($mt > 0) ? $mt : 0;
+    					$bookkeeping->credit = ($mt <= 0) ? $mt : 0;
+    					$bookkeeping->code_journal = $conf->global->ACCOUNTING_EXPENSEREPORT_JOURNAL;
+    					$bookkeeping->fk_user_author = $user->id;
+    
+    					$result = $bookkeeping->create($user);
+	        			if ($result < 0) {
+            			    if ($bookkeeping->error == 'BookkeepingRecordAlreadyExists')	// Already exists
+            			    {
+            			        $error++;
+            			        $errorforline++;
+            			        //setEventMessages('Transaction for ('.$bookkeeping->doc_type.', '.$bookkeeping->doc_ref.', '.$bookkeeping->fk_docdet.') were already recorded', null, 'warnings');
+            			    }
+            			    else
+            			    {
+            			        $error++;
+            			        $errorforline++;
+            			        setEventMessages($bookkeeping->error, $bookkeeping->errors, 'errors');
+            			    }
+	        			}
+    				}
+    			}
+    		}
+        }
+        
+        if (! $errorforline)
+        {
+            // VAT
+    		// var_dump($tabtva);
+    		foreach ( $tabtva[$key] as $k => $mt ) {
+    			if ($mt) {
+    				// get compte id and label
+    				$bookkeeping = new BookKeeping($db);
+    				$bookkeeping->doc_date = $val["date"];
+    				$bookkeeping->doc_ref = $val["ref"];
+    				$bookkeeping->date_create = $now;
+    				$bookkeeping->doc_type = 'expense_report';
+    				$bookkeeping->fk_doc = $key;
+    				$bookkeeping->fk_docdet = $val["fk_expensereportdet"];
+    				$bookkeeping->code_tiers = '';
+    				$bookkeeping->label_compte = $langs->trans("VAT"). ' '.$def_tva[$key];
+    				$bookkeeping->numero_compte = $k;
+    				$bookkeeping->montant = $mt;
+    				$bookkeeping->sens = ($mt < 0) ? 'C' : 'D';
+    				$bookkeeping->debit = ($mt > 0) ? $mt : 0;
+    				$bookkeeping->credit = ($mt <= 0) ? $mt : 0;
+    				$bookkeeping->code_journal = $conf->global->ACCOUNTING_EXPENSEREPORT_JOURNAL;
+    				$bookkeeping->fk_user_author = $user->id;
+    
+    				$result = $bookkeeping->create($user);
+    				if ($result < 0) {
+           			    if ($bookkeeping->error == 'BookkeepingRecordAlreadyExists')	// Already exists
+        			    {
+        			        $error++;
+        			        $errorforline++;
+        			        //setEventMessages('Transaction for ('.$bookkeeping->doc_type.', '.$bookkeeping->doc_ref.', '.$bookkeeping->fk_docdet.') were already recorded', null, 'warnings');
+        			    }
+        			    else
+        			    {
+        			        $error++;
+        			        $errorforline++;
+        			        setEventMessages($bookkeeping->error, $bookkeeping->errors, 'errors');
+        			    }
+    				}
+    			}
+    		}
+        }
+        
 		if (! $errorforline)
 		{
 		    $db->commit();
@@ -286,7 +326,7 @@ $form = new Form($db);
 $userstatic = new User($db);
 
 // Export
-if ($action == 'export_csv') {
+/*if ($action == 'export_csv') {
 	$sep = $conf->global->ACCOUNTING_EXPORT_SEPARATORCSV;
 	$journal = $conf->global->ACCOUNTING_EXPENSEREPORT_JOURNAL;
 
@@ -393,6 +433,7 @@ if ($action == 'export_csv') {
 		}
 	}
 }
+*/
 
 if (empty($action) || $action == 'view') {
 
@@ -406,18 +447,19 @@ if (empty($action) || $action == 'view') {
 	$description.= $langs->trans("DescJournalOnlyBindedVisible").'<br>';
 
 	$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);
-	report_header($nom, $nomlink, $period, $periodlink, $description, $builddate, $exportlink, array (
-			'action' => ''
-	));
 
-	if ($conf->global->ACCOUNTING_EXPORT_MODELCSV != 1 && $conf->global->ACCOUNTING_EXPORT_MODELCSV != 2) {
+	journalHead($nom, $nomlink, $period, $periodlink, $description, $builddate, $exportlink, array('action' => ''));
+
+	/*if ($conf->global->ACCOUNTING_EXPORT_MODELCSV != 1 && $conf->global->ACCOUNTING_EXPORT_MODELCSV != 2) {
 		print '<input type="button" class="butActionRefused" style="float: right;" value="' . $langs->trans("Export") . '" disabled="disabled" title="' . $langs->trans('ExportNotSupported') . '"/>';
 	} else {
 		print '<input type="button" class="butAction" style="float: right;" value="' . $langs->trans("Export") . '" onclick="launch_export();" />';
-	}
+	}*/
 
+    print '<div class="tabsAction">';
 	print '<input type="button" class="butAction" value="' . $langs->trans("WriteBookKeeping") . '" onclick="writebookkeeping();" />';
-
+    print '</div>';
+    
 	print '
 	<script type="text/javascript">
 		function launch_export() {
@@ -435,7 +477,7 @@ if (empty($action) || $action == 'view') {
 	/*
 	 * Show result array
 	 */
-	print '<br><br>';
+	print '<br>';
 
 	$i = 0;
 	print "<table class=\"noborder\" width=\"100%\">";
@@ -511,11 +553,11 @@ if (empty($action) || $action == 'view') {
 				print "</tr>";
 			}
 		}
-		print '<tr class="oddeven">';
 
 		// Third party
 		foreach ( $tabttc[$key] as $k => $mt ) {
-			print "<td><!-- Thirdparty --></td>";
+		    print '<tr class="oddeven">';
+		    print "<td><!-- Thirdparty --></td>";
 		    print "<td>" . $date . "</td>";
 			print "<td>" . $expensereportstatic->getNomUrl(1) . "</td>";
 			$userstatic->id = $tabuser[$key]['id'];
@@ -531,8 +573,8 @@ if (empty($action) || $action == 'view') {
 			print "<td>" . $userstatic->getNomUrl(0, 'user', 16) . ' - ' . $langs->trans("Code_tiers") . "</td>";
 			print '<td align="right">' . ($mt < 0 ? - price(- $mt) : '') . "</td>";
 			print '<td align="right">' . ($mt >= 0 ? price($mt) : '') . "</td>";
+		    print "</tr>";
 		}
-		print "</tr>";
 	}
 
 	print "</table>";

+ 153 - 106
htdocs/accountancy/journal/purchasesjournal.php

@@ -109,6 +109,7 @@ dol_syslog('accountancy/journal/purchasesjournal.php:: $sql=' . $sql);
 $result = $db->query($sql);
 if ($result) {
 	$num = $db->num_rows($result);
+
 	// les variables
 	$cptfour = (! empty($conf->global->ACCOUNTING_ACCOUNT_SUPPLIER)) ? $conf->global->ACCOUNTING_ACCOUNT_SUPPLIER : $langs->trans("CodeNotDef");
 	$cpttva = (! empty($conf->global->ACCOUNTING_VAT_BUY_ACCOUNT)) ? $conf->global->ACCOUNTING_VAT_BUY_ACCOUNT : $langs->trans("CodeNotDef");
@@ -123,8 +124,10 @@ if ($result) {
 	$i = 0;
 	while ( $i < $num ) {
 		$obj = $db->fetch_object($result);
+
 		// contrôles
 		$compta_soc = (! empty($obj->code_compta_fournisseur)) ? $obj->code_compta_fournisseur : $cptfour;
+		
 		$compta_prod = $obj->compte;
 		if (empty($compta_prod)) {
 			if ($obj->product_type == 0)
@@ -144,14 +147,21 @@ if ($result) {
 
 		$tabfac[$obj->rowid]["type"] = $obj->type;
 		$tabfac[$obj->rowid]["description"] = $obj->description;
-		$tabfac[$obj->rowid]["fk_facturefourndet"] = $obj->fdid;
+		//$tabfac[$obj->rowid]["fk_facturefourndet"] = $obj->fdid;
+		
+        // Avoid warnings
+        if (! isset($tabttc[$obj->rowid][$compta_soc])) $tabttc[$obj->rowid][$compta_soc] = 0;
+        if (! isset($tabht[$obj->rowid][$compta_prod])) $tabht[$obj->rowid][$compta_prod] = 0;
+        if (! isset($tabtva[$obj->rowid][$compta_tva])) $tabtva[$obj->rowid][$compta_tva] = 0;
+
 		$tabttc[$obj->rowid][$compta_soc] += $obj->total_ttc;
 		$tabht[$obj->rowid][$compta_prod] += $obj->total_ht;
 		$tabtva[$obj->rowid][$compta_tva] += $obj->total_tva;
 		$tabcompany[$obj->rowid] = array (
 				'id' => $obj->socid,
 				'name' => $obj->name,
-				'code_fournisseur' => $obj->code_compta_fournisseur
+				'code_fournisseur' => $obj->code_fournisseur,
+				'code_compta_fournisseur' => $compta_soc
 		);
 
 		$i ++;
@@ -165,7 +175,7 @@ if ($action == 'writebookkeeping') {
 	$now = dol_now();
 	$error = 0;
 
-	foreach ($tabfac as $key => $val)
+	foreach ($tabfac as $key => $val)  // Loop on each invoice
 	{
 	    $errorforline = 0;
 	     
@@ -188,101 +198,136 @@ if ($action == 'writebookkeeping') {
 		$companystatic->code_fournisseur = $tabcompany[$key]['code_fournisseur'];
 		$companystatic->client = $tabcompany[$key]['code_client'];
 
-		foreach ( $tabttc[$key] as $k => $mt ) {
-			// get compte id and label
-
-			$bookkeeping = new BookKeeping($db);
-			$bookkeeping->doc_date = $val["date"];
-			$bookkeeping->doc_ref = $val["ref"];
-			$bookkeeping->date_create = $now;
-			$bookkeeping->doc_type = 'supplier_invoice';
-			$bookkeeping->fk_doc = $key;
-			$bookkeeping->fk_docdet = $val["fk_facturefourndet"];
-			$bookkeeping->code_tiers = $tabcompany[$key]['code_fournisseur'];
-			$bookkeeping->label_compte = dol_trunc($companystatic->name, 16) . ' - ' . $invoicestatic->refsupplier . ' - ' . $langs->trans("Code_tiers");
-			$bookkeeping->numero_compte = $conf->global->ACCOUNTING_ACCOUNT_SUPPLIER;
-			$bookkeeping->montant = $mt;
-			$bookkeeping->sens = ($mt >= 0) ? 'C' : 'D';
-			$bookkeeping->debit = ($mt <= 0) ? $mt : 0;
-			$bookkeeping->credit = ($mt > 0) ? $mt : 0;
-			$bookkeeping->code_journal = $conf->global->ACCOUNTING_PURCHASE_JOURNAL;
-			$bookkeeping->fk_user_author = $user->id;
-
-			$result = $bookkeeping->create($user);
-			if ($result < 0) {
-			    $error++;
-			    $errorforline++;
-			    setEventMessages($bookkeeping->error, $bookkeeping->errors, 'errors');
-			}
-		}
-
+        if (! $errorforline)
+        {
+    		foreach ( $tabttc[$key] as $k => $mt ) {
+    			// get compte id and label
+    		    if ($mt) {
+        			$bookkeeping = new BookKeeping($db);
+        			$bookkeeping->doc_date = $val["date"];
+        			$bookkeeping->doc_ref = $val["ref"];
+        			$bookkeeping->date_create = $now;
+        			$bookkeeping->doc_type = 'supplier_invoice';
+        			$bookkeeping->fk_doc = $key;
+        			$bookkeeping->fk_docdet = 0;    // Useless, can be several lines that are source of this record to add
+        			$bookkeeping->code_tiers = $tabcompany[$key]['code_fournisseur'];
+        			$bookkeeping->label_compte = dol_trunc($companystatic->name, 16) . ' - ' . $invoicestatic->refsupplier . ' - ' . $langs->trans("Code_tiers");
+        			$bookkeeping->numero_compte = $tabcompany[$key]['code_compta_fournisseur'];
+        			$bookkeeping->montant = $mt;
+        			$bookkeeping->sens = ($mt >= 0) ? 'C' : 'D';
+        			$bookkeeping->debit = ($mt <= 0) ? $mt : 0;
+        			$bookkeeping->credit = ($mt > 0) ? $mt : 0;
+        			$bookkeeping->code_journal = $conf->global->ACCOUNTING_PURCHASE_JOURNAL;
+        			$bookkeeping->fk_user_author = $user->id;
+        
+        			$result = $bookkeeping->create($user);
+           			if ($result < 0) {
+                        if ($bookkeeping->error == 'BookkeepingRecordAlreadyExists')	// Already exists
+                        {
+                            $error++;
+                            $errorforline++;
+                            //setEventMessages('Transaction for ('.$bookkeeping->doc_type.', '.$bookkeeping->doc_ref.', '.$bookkeeping->fk_docdet.') were already recorded', null, 'warnings');
+                        }
+                        else
+                        {
+                            $error++;
+                            $errorforline++;
+                            setEventMessages($bookkeeping->error, $bookkeeping->errors, 'errors');
+                        }
+        			}
+    		    }
+    		}
+        }
+        
 		// Product / Service
-		foreach ( $tabht[$key] as $k => $mt ) {
-			$accountingaccount = new AccountingAccount($db);
-			$accountingaccount->fetch(null, $k, true);
-			if ($mt) {
-				// get compte id and label
-				$accountingaccount = new AccountingAccount($db);
-				if ($accountingaccount->fetch(null, $k, true)) {
-					$bookkeeping = new BookKeeping($db);
-					$bookkeeping->doc_date = $val["date"];
-					$bookkeeping->doc_ref = $val["ref"];
-					$bookkeeping->date_create = $now;
-					$bookkeeping->doc_type = 'supplier_invoice';
-					$bookkeeping->fk_doc = $key;
-					$bookkeeping->fk_docdet = $val["fk_facturefourndet"];
-					$bookkeeping->code_tiers = '';
-					$bookkeeping->label_compte = dol_trunc($companystatic->name, 16) . ' - ' . $invoicestatic->refsupplier . ' - ' . $accountingaccount->label;
-					$bookkeeping->numero_compte = $k;
-					$bookkeeping->montant = $mt;
-					$bookkeeping->sens = ($mt < 0) ? 'C' : 'D';
-					$bookkeeping->debit = ($mt > 0) ? $mt : 0;
-					$bookkeeping->credit = ($mt <= 0) ? $mt : 0;
-					$bookkeeping->code_journal = $conf->global->ACCOUNTING_PURCHASE_JOURNAL;
-					$bookkeeping->fk_user_author = $user->id;
-
-					$result = $bookkeeping->create($user);
-					if ($result < 0) {
-						$error++;
-						$errorforline++;
-						setEventMessages($bookkeeping->error, $bookkeeping->errors, 'errors');
-					}
-				}
-			}
-		}
-
+        if (! $errorforline)
+        {
+            foreach ( $tabht[$key] as $k => $mt ) {
+    			$accountingaccount = new AccountingAccount($db);
+    			$accountingaccount->fetch(null, $k, true);
+    			if ($mt) {
+    				// get compte id and label
+    				$accountingaccount = new AccountingAccount($db);
+    				if ($accountingaccount->fetch(null, $k, true)) {
+    					$bookkeeping = new BookKeeping($db);
+    					$bookkeeping->doc_date = $val["date"];
+    					$bookkeeping->doc_ref = $val["ref"];
+    					$bookkeeping->date_create = $now;
+    					$bookkeeping->doc_type = 'supplier_invoice';
+    					$bookkeeping->fk_doc = $key;
+    					$bookkeeping->fk_docdet = 0;    // Useless, can be several lines that are source of this record to add
+    					$bookkeeping->code_tiers = '';
+    					$bookkeeping->label_compte = dol_trunc($companystatic->name, 16) . ' - ' . $invoicestatic->refsupplier . ' - ' . $accountingaccount->label;
+    					$bookkeeping->numero_compte = $k;
+    					$bookkeeping->montant = $mt;
+    					$bookkeeping->sens = ($mt < 0) ? 'C' : 'D';
+    					$bookkeeping->debit = ($mt > 0) ? $mt : 0;
+    					$bookkeeping->credit = ($mt <= 0) ? $mt : 0;
+    					$bookkeeping->code_journal = $conf->global->ACCOUNTING_PURCHASE_JOURNAL;
+    					$bookkeeping->fk_user_author = $user->id;
+    
+    					$result = $bookkeeping->create($user);
+    					if ($result < 0) {
+    					    if ($bookkeeping->error == 'BookkeepingRecordAlreadyExists')	// Already exists
+            			    {
+            			        $error++;
+            			        $errorforline++;
+            			        //setEventMessages('Transaction for ('.$bookkeeping->doc_type.', '.$bookkeeping->doc_ref.', '.$bookkeeping->fk_docdet.') were already recorded', null, 'warnings');
+            			    }
+            			    else
+            			    {
+            			        $error++;
+            			        $errorforline++;
+            			        setEventMessages($bookkeeping->error, $bookkeeping->errors, 'errors');
+            			    }
+    					}
+    				}
+    			}
+    		}
+        }
+        
 		// VAT
 		// var_dump($tabtva);
-		foreach ( $tabtva[$key] as $k => $mt ) {
-			if ($mt) {
-				// get compte id and label
-				$bookkeeping = new BookKeeping($db);
-				$bookkeeping->doc_date = $val["date"];
-				$bookkeeping->doc_ref = $val["ref"];
-				$bookkeeping->date_create = $now;
-				$bookkeeping->doc_type = 'supplier_invoice';
-				$bookkeeping->fk_doc = $key;
-				$bookkeeping->fk_docdet = $val["fk_facturefourndet"];
-				$bookkeeping->code_tiers = '';
-				$bookkeeping->label_compte = dol_trunc($companystatic->name, 16) . ' - ' . $invoicestatic->refsupplier . ' - ' . $langs->trans("VAT"). ' '.$def_tva[$key];
-				$bookkeeping->numero_compte = $k;
-				$bookkeeping->montant = $mt;
-				$bookkeeping->sens = ($mt < 0) ? 'C' : 'D';
-				$bookkeeping->debit = ($mt > 0) ? $mt : 0;
-				$bookkeeping->credit = ($mt <= 0) ? $mt : 0;
-				$bookkeeping->code_journal = $conf->global->ACCOUNTING_PURCHASE_JOURNAL;
-				$bookkeeping->fk_user_author = $user->id;
-
-				$result = $bookkeeping->create($user);
-				if ($result < 0) {
-					$error++;
-					$errorforline++;
-					setEventMessages($object->error, $object->errors, 'errors');
-				}
-			}
-		}
-		
-
+        if (! $errorforline)
+        {
+            foreach ( $tabtva[$key] as $k => $mt ) {
+    			if ($mt) {
+    				// get compte id and label
+    				$bookkeeping = new BookKeeping($db);
+    				$bookkeeping->doc_date = $val["date"];
+    				$bookkeeping->doc_ref = $val["ref"];
+    				$bookkeeping->date_create = $now;
+    				$bookkeeping->doc_type = 'supplier_invoice';
+    				$bookkeeping->fk_doc = $key;
+    				$bookkeeping->fk_docdet = 0;    // Useless, can be several lines that are source of this record to add
+    				$bookkeeping->code_tiers = '';
+    				$bookkeeping->label_compte = dol_trunc($companystatic->name, 16) . ' - ' . $invoicestatic->refsupplier . ' - ' . $langs->trans("VAT"). ' '.$def_tva[$key];
+    				$bookkeeping->numero_compte = $k;
+    				$bookkeeping->montant = $mt;
+    				$bookkeeping->sens = ($mt < 0) ? 'C' : 'D';
+    				$bookkeeping->debit = ($mt > 0) ? $mt : 0;
+    				$bookkeeping->credit = ($mt <= 0) ? $mt : 0;
+    				$bookkeeping->code_journal = $conf->global->ACCOUNTING_PURCHASE_JOURNAL;
+    				$bookkeeping->fk_user_author = $user->id;
+    
+    				$result = $bookkeeping->create($user);
+    				if ($result < 0) {
+    				    if ($bookkeeping->error == 'BookkeepingRecordAlreadyExists')	// Already exists
+    				    {
+    				        $error++;
+    				        $errorforline++;
+    				        //setEventMessages('Transaction for ('.$bookkeeping->doc_type.', '.$bookkeeping->doc_ref.', '.$bookkeeping->fk_docdet.') were already recorded', null, 'warnings');
+    				    }
+    				    else
+    				    {
+    				        $error++;
+    				        $errorforline++;
+    				        setEventMessages($bookkeeping->error, $bookkeeping->errors, 'errors');
+    				    }
+    				}
+    			}
+    		}
+        }
 
 		if (! $errorforline)
 		{
@@ -319,7 +364,7 @@ $form = new Form($db);
 $companystatic = new Fournisseur($db);
 
 // Export
-if ($action == 'export_csv') {
+/*if ($action == 'export_csv') {
 	$sep = $conf->global->ACCOUNTING_EXPORT_SEPARATORCSV;
 	$journal = $conf->global->ACCOUNTING_PURCHASE_JOURNAL;
 
@@ -437,6 +482,7 @@ if ($action == 'export_csv') {
 		}
 	}
 }
+*/
 
 if (empty($action) || $action == 'view') {
 
@@ -456,18 +502,19 @@ if (empty($action) || $action == 'view') {
 	}
 
 	$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);
-	report_header($nom, $nomlink, $period, $periodlink, $description, $builddate, $exportlink, array (
-			'action' => ''
-	));
+	
+	journalHead($nom, $nomlink, $period, $periodlink, $description, $builddate, $exportlink, array('action' => ''));
 
-	if ($conf->global->ACCOUNTING_EXPORT_MODELCSV != 1 && $conf->global->ACCOUNTING_EXPORT_MODELCSV != 2) {
+	/*if ($conf->global->ACCOUNTING_EXPORT_MODELCSV != 1 && $conf->global->ACCOUNTING_EXPORT_MODELCSV != 2) {
 		print '<input type="button" class="butActionRefused" style="float: right;" value="' . $langs->trans("Export") . '" disabled="disabled" title="' . $langs->trans('ExportNotSupported') . '"/>';
 	} else {
 		print '<input type="button" class="butAction" style="float: right;" value="' . $langs->trans("Export") . '" onclick="launch_export();" />';
-	}
+	}*/
 
+    print '<div class="tabsAction">';
 	print '<input type="button" class="butAction" value="' . $langs->trans("WriteBookKeeping") . '" onclick="writebookkeeping();" />';
-
+    print '</div>';
+    
 	print '
 	<script type="text/javascript">
 		function launch_export() {
@@ -485,7 +532,7 @@ if (empty($action) || $action == 'view') {
 	/*
 	 * Show result array
 	 */
-	print '<br><br>';
+	print '<br>';
 
 	$i = 0;
 	print "<table class=\"noborder\" width=\"100%\">";
@@ -562,11 +609,11 @@ if (empty($action) || $action == 'view') {
 				print "</tr>";
 			}
 		}
-		print '<tr class="oddeven">';
 
 		// Third party
 		foreach ( $tabttc[$key] as $k => $mt ) {
-			print "<td><!-- Thirdparty --></td>";
+		    print '<tr class="oddeven">';
+		    print "<td><!-- Thirdparty --></td>";
 		    print "<td>" . $date . "</td>";
 			print "<td>" . $invoicestatic->getNomUrl(1) . "</td>";
 			$companystatic->id = $tabcompany[$key]['id'];
@@ -585,8 +632,8 @@ if (empty($action) || $action == 'view') {
 			// print "</td>";
 			print '<td align="right">' . ($mt < 0 ? - price(- $mt) : '') . "</td>";
 			print '<td align="right">' . ($mt >= 0 ? price($mt) : '') . "</td>";
+		    print "</tr>";
 		}
-		print "</tr>";
 	}
 
 	print "</table>";

+ 140 - 97
htdocs/accountancy/journal/sellsjournal.php

@@ -100,7 +100,7 @@ $sql .= " JOIN " . MAIN_DB_PREFIX . "societe as s ON s.rowid = f.fk_soc";
 $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "c_tva as ct ON fd.tva_tx = ct.taux AND ct.fk_pays = '" . $idpays . "'";
 $sql .= " WHERE fd.fk_code_ventilation > 0";
 $sql .= " AND f.entity IN (".getEntity('facture', 0).')';    // We don't share object for accountancy
-$sql .= " AND f.fk_statut > 0";
+$sql .= " AND f.fk_statut > 0"; // TODO Facture annulée ?
 if (! empty($conf->global->FACTURE_DEPOSITS_ARE_JUST_PAYMENTS)) {
     $sql .= " AND f.type IN (" . Facture::TYPE_STANDARD . "," . Facture::TYPE_REPLACEMENT . "," . Facture::TYPE_CREDIT_NOTE . "," . Facture::TYPE_SITUATION . ")";
 } else {
@@ -124,10 +124,12 @@ if ($result) {
     $num = $db->num_rows($result);
     $i = 0;
 
+    $cptcli = (! empty($conf->global->ACCOUNTING_ACCOUNT_CUSTOMER)) ? $conf->global->ACCOUNTING_ACCOUNT_CUSTOMER : $langs->trans("CodeNotDef");
+    
     while ( $i < $num ) {
         $obj = $db->fetch_object($result);
+        
         // les variables
-        $cptcli = (! empty($conf->global->ACCOUNTING_ACCOUNT_CUSTOMER)) ? $conf->global->ACCOUNTING_ACCOUNT_CUSTOMER : $langs->trans("CodeNotDef");
         $compta_soc = (! empty($obj->code_compta)) ? $obj->code_compta : $cptcli;
 
         $compta_prod = $obj->compte;
@@ -164,23 +166,24 @@ if ($result) {
         $tabfac[$obj->rowid]["ref"] = $obj->facnumber;
         $tabfac[$obj->rowid]["type"] = $obj->type;
         $tabfac[$obj->rowid]["description"] = $obj->label_compte;
-        $tabfac[$obj->rowid]["fk_facturedet"] = $obj->fdid;
-        if (! isset($tabttc[$obj->rowid][$compta_soc]))
-            $tabttc[$obj->rowid][$compta_soc] = 0;
-            if (! isset($tabht[$obj->rowid][$compta_prod]))
-                $tabht[$obj->rowid][$compta_prod] = 0;
-                if (! isset($tabtva[$obj->rowid][$compta_tva]))
-                    $tabtva[$obj->rowid][$compta_tva] = 0;
-                    $tabttc[$obj->rowid][$compta_soc] += $obj->total_ttc * $situation_ratio;
-                    $tabht[$obj->rowid][$compta_prod] += $obj->total_ht * $situation_ratio;
-                    $tabtva[$obj->rowid][$compta_tva] += $obj->total_tva * $situation_ratio;
-                    $tabcompany[$obj->rowid] = array (
-                        'id' => $obj->socid,
-                        'name' => $obj->name,
-                        'code_client' => $obj->code_compta
-                    );
-
-                    $i ++;
+        //$tabfac[$obj->rowid]["fk_facturedet"] = $obj->fdid;
+       
+        // Avoid warnings
+        if (! isset($tabttc[$obj->rowid][$compta_soc])) $tabttc[$obj->rowid][$compta_soc] = 0;
+        if (! isset($tabht[$obj->rowid][$compta_prod])) $tabht[$obj->rowid][$compta_prod] = 0;
+        if (! isset($tabtva[$obj->rowid][$compta_tva])) $tabtva[$obj->rowid][$compta_tva] = 0;
+
+        $tabttc[$obj->rowid][$compta_soc] += $obj->total_ttc * $situation_ratio;
+        $tabht[$obj->rowid][$compta_prod] += $obj->total_ht * $situation_ratio;
+        $tabtva[$obj->rowid][$compta_tva] += $obj->total_tva * $situation_ratio;
+        $tabcompany[$obj->rowid] = array (
+            'id' => $obj->socid,
+            'name' => $obj->name,
+            'code_client' => $obj->code_client,
+            'code_compta' => $compta_soc
+        );
+
+        $i ++;
     }
 } else {
     dol_print_error($db);
@@ -191,7 +194,7 @@ if ($action == 'writebookkeeping') {
     $now = dol_now();
     $error = 0;
 
-    foreach ( $tabfac as $key => $val ) {
+    foreach ( $tabfac as $key => $val ) {   // Loop on each invoice
          
         $errorforline = 0;
 
@@ -211,97 +214,135 @@ if ($action == 'writebookkeeping') {
         $invoicestatic->id = $key;
         $invoicestatic->ref = (string) $val["ref"];
 
-        foreach ( $tabttc[$key] as $k => $mt ) {
-            $bookkeeping = new BookKeeping($db);
-            $bookkeeping->doc_date = $val["date"];
-            $bookkeeping->doc_ref = $val["ref"];
-            $bookkeeping->date_create = $now;
-            $bookkeeping->doc_type = 'customer_invoice';
-            $bookkeeping->fk_doc = $key;
-            $bookkeeping->fk_docdet = $val["fk_facturedet"];
-            $bookkeeping->code_tiers = $tabcompany[$key]['code_client'];
-            $bookkeeping->numero_compte = $conf->global->ACCOUNTING_ACCOUNT_CUSTOMER;
-            // $bookkeeping->label_compte = $tabcompany[$key]['name'];
-            $bookkeeping->label_compte = dol_trunc($companystatic->name, 16) . ' - ' . $invoicestatic->ref . ' - ' . $langs->trans("Code_tiers");
-            $bookkeeping->montant = $mt;
-            $bookkeeping->sens = ($mt >= 0) ? 'D' : 'C';
-            $bookkeeping->debit = ($mt >= 0) ? $mt : 0;
-            $bookkeeping->credit = ($mt < 0) ? $mt : 0;
-            $bookkeeping->code_journal = $conf->global->ACCOUNTING_SELL_JOURNAL;
-            $bookkeeping->fk_user_author = $user->id;
-
-            $result = $bookkeeping->create($user);
-            if ($result < 0) {
-                $error++;
-                $errorforline++;
-                setEventMessages($bookkeeping->error, $bookkeeping->errors, 'errors');
+        // Thirdparty
+        if (! $errorforline)
+        {
+            foreach ( $tabttc[$key] as $k => $mt ) {
+                if ($mt) {
+                    $bookkeeping = new BookKeeping($db);
+                    $bookkeeping->doc_date = $val["date"];
+                    $bookkeeping->doc_ref = $val["ref"];
+                    $bookkeeping->date_create = $now;
+                    $bookkeeping->doc_type = 'customer_invoice';
+                    $bookkeeping->fk_doc = $key;
+                    $bookkeeping->fk_docdet = 0;    // Useless, can be several lines that are source of this record to add
+                    $bookkeeping->code_tiers = $tabcompany[$key]['code_client'];
+                    $bookkeeping->numero_compte = $tabcompany[$key]['code_compta'];
+                    // $bookkeeping->label_compte = $tabcompany[$key]['name'];
+                    $bookkeeping->label_compte = dol_trunc($companystatic->name, 16) . ' - ' . $invoicestatic->ref . ' - ' . $langs->trans("Code_tiers");
+                    $bookkeeping->montant = $mt;
+                    $bookkeeping->sens = ($mt >= 0) ? 'D' : 'C';
+                    $bookkeeping->debit = ($mt >= 0) ? $mt : 0;
+                    $bookkeeping->credit = ($mt < 0) ? $mt : 0;
+                    $bookkeeping->code_journal = $conf->global->ACCOUNTING_SELL_JOURNAL;
+                    $bookkeeping->fk_user_author = $user->id;
+    
+                    $result = $bookkeeping->create($user);
+           			if ($result < 0) {
+                        if ($bookkeeping->error == 'BookkeepingRecordAlreadyExists')	// Already exists
+                        {
+                            $error++;
+                            $errorforline++;
+                            //setEventMessages('Transaction for ('.$bookkeeping->doc_type.', '.$bookkeeping->doc_ref.', '.$bookkeeping->fk_docdet.') were already recorded', null, 'warnings');
+                        }
+                        else
+                        {
+                            $error++;
+                            $errorforline++;
+                            setEventMessages($bookkeeping->error, $bookkeeping->errors, 'errors');
+                        }
+        			}
+                }
             }
         }
-
+        
         // Product / Service
-        foreach ( $tabht[$key] as $k => $mt ) {
-            if ($mt) {
-                // get compte id and label
-                $accountingaccount = new AccountingAccount($db);
-                if ($accountingaccount->fetch(null, $k, true)) {
+        if (! $errorforline)
+        {
+            foreach ( $tabht[$key] as $k => $mt ) {
+                if ($mt) {
+                    // get compte id and label
+                    $accountingaccount = new AccountingAccount($db);
+                    if ($accountingaccount->fetch(null, $k, true)) {
+                        $bookkeeping = new BookKeeping($db);
+                        $bookkeeping->doc_date = $val["date"];
+                        $bookkeeping->doc_ref = $val["ref"];
+                        $bookkeeping->date_create = $now;
+                        $bookkeeping->doc_type = 'customer_invoice';
+                        $bookkeeping->fk_doc = $key;
+                        $bookkeeping->fk_docdet = 0;    // Useless, can be several lines that are source of this record to add;
+                        $bookkeeping->code_tiers = '';
+                        $bookkeeping->numero_compte = $k;
+                        $bookkeeping->label_compte = dol_trunc($companystatic->name, 16) . ' - ' . $invoicestatic->ref . ' - ' . $accountingaccount->label;
+                        $bookkeeping->montant = $mt;
+                        $bookkeeping->sens = ($mt < 0) ? 'D' : 'C';
+                        $bookkeeping->debit = ($mt < 0) ? $mt : 0;
+                        $bookkeeping->credit = ($mt >= 0) ? $mt : 0;
+                        $bookkeeping->code_journal = $conf->global->ACCOUNTING_SELL_JOURNAL;
+                        $bookkeeping->fk_user_author = $user->id;
+    
+                        $result = $bookkeeping->create($user);
+            			if ($result < 0) {
+                            if ($bookkeeping->error == 'BookkeepingRecordAlreadyExists')	// Already exists
+                            {
+                                $error++;
+                                $errorforline++;
+                                //setEventMessages('Transaction for ('.$bookkeeping->doc_type.', '.$bookkeeping->doc_ref.', '.$bookkeeping->fk_docdet.') were already recorded', null, 'warnings');
+                            }
+                            else
+                            {
+                                $error++;
+                                $errorforline++;
+                                setEventMessages($bookkeeping->error, $bookkeeping->errors, 'errors');
+                            }
+            			}                        
+                    }
+                }
+            }
+        }
+        
+        // VAT
+        // var_dump($tabtva);
+        if (! $errorforline)
+        {
+            foreach ( $tabtva[$key] as $k => $mt ) {
+                if ($mt) {
                     $bookkeeping = new BookKeeping($db);
                     $bookkeeping->doc_date = $val["date"];
                     $bookkeeping->doc_ref = $val["ref"];
                     $bookkeeping->date_create = $now;
                     $bookkeeping->doc_type = 'customer_invoice';
                     $bookkeeping->fk_doc = $key;
-                    $bookkeeping->fk_docdet = $val["fk_facturedet"];
+                    $bookkeeping->fk_docdet = 0;    // Useless, can be several lines that are source of this record to add
                     $bookkeeping->code_tiers = '';
                     $bookkeeping->numero_compte = $k;
-                    $bookkeeping->label_compte = dol_trunc($companystatic->name, 16) . ' - ' . $invoicestatic->ref . ' - ' . $accountingaccount->label;
+                    $bookkeeping->label_compte = dol_trunc($companystatic->name, 16) . ' - ' . $invoicestatic->ref . ' - ' . $langs->trans("VAT").' '.$def_tva[$key];
                     $bookkeeping->montant = $mt;
                     $bookkeeping->sens = ($mt < 0) ? 'D' : 'C';
                     $bookkeeping->debit = ($mt < 0) ? $mt : 0;
                     $bookkeeping->credit = ($mt >= 0) ? $mt : 0;
                     $bookkeeping->code_journal = $conf->global->ACCOUNTING_SELL_JOURNAL;
                     $bookkeeping->fk_user_author = $user->id;
-
+    
                     $result = $bookkeeping->create($user);
                     if ($result < 0) {
-                        $error++;
-                        $errorforline++;
-                        setEventMessages($bookkeeping->error, $bookkeeping->errors, 'errors');
+           			    if ($bookkeeping->error == 'BookkeepingRecordAlreadyExists')	// Already exists
+        			    {
+        			        $error++;
+        			        $errorforline++;
+        			        //setEventMessages('Transaction for ('.$bookkeeping->doc_type.', '.$bookkeeping->doc_ref.', '.$bookkeeping->fk_docdet.') were already recorded', null, 'warnings');
+        			    }
+        			    else
+        			    {
+        			        $error++;
+        			        $errorforline++;
+        			        setEventMessages($bookkeeping->error, $bookkeeping->errors, 'errors');
+        			    }
                     }
                 }
             }
         }
 
-        // VAT
-        // var_dump($tabtva);
-        foreach ( $tabtva[$key] as $k => $mt ) {
-            if ($mt) {
-                $bookkeeping = new BookKeeping($db);
-                $bookkeeping->doc_date = $val["date"];
-                $bookkeeping->doc_ref = $val["ref"];
-                $bookkeeping->date_create = $now;
-                $bookkeeping->doc_type = 'customer_invoice';
-                $bookkeeping->fk_doc = $key;
-                $bookkeeping->fk_docdet = $val["fk_facturedet"];
-                $bookkeeping->code_tiers = '';
-                $bookkeeping->numero_compte = $k;
-                $bookkeeping->label_compte = dol_trunc($companystatic->name, 16) . ' - ' . $invoicestatic->ref . ' - ' . $langs->trans("VAT").' '.$def_tva[$key];
-                $bookkeeping->montant = $mt;
-                $bookkeeping->sens = ($mt < 0) ? 'D' : 'C';
-                $bookkeeping->debit = ($mt < 0) ? $mt : 0;
-                $bookkeeping->credit = ($mt >= 0) ? $mt : 0;
-                $bookkeeping->code_journal = $conf->global->ACCOUNTING_SELL_JOURNAL;
-                $bookkeeping->fk_user_author = $user->id;
-
-                $result = $bookkeeping->create($user);
-                if ($result < 0) {
-                    $error++;
-                    $errorforline++;
-                    setEventMessages($object->error, $object->errors, 'errors');
-                }
-            }
-        }
-
-
         if (! $errorforline)
         {
             $db->commit();
@@ -337,7 +378,7 @@ if ($action == 'writebookkeeping') {
 $form = new Form($db);
 
 // Export
-if ($action == 'export_csv') {
+/*if ($action == 'export_csv') {
 
     $sep = $conf->global->ACCOUNTING_EXPORT_SEPARATORCSV;
     $sell_journal = $conf->global->ACCOUNTING_SELL_JOURNAL;
@@ -457,6 +498,8 @@ if ($action == 'export_csv') {
         }
     }
 }
+*/
+
 
 if (empty($action) || $action == 'view') {
 
@@ -474,18 +517,18 @@ if (empty($action) || $action == 'view') {
 	else
 		$description .= $langs->trans("DepositsAreIncluded");
 	$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);
-	report_header($nom, $nomlink, $period, $periodlink, $description, $builddate, $exportlink, array (
-			'action' => ''
-	));
+	
+	journalHead($nom, $nomlink, $period, $periodlink, $description, $builddate, $exportlink, array('action' => ''));
 
-	if ($conf->global->ACCOUNTING_EXPORT_MODELCSV != 1 && $conf->global->ACCOUNTING_EXPORT_MODELCSV != 2) {
+	/*if ($conf->global->ACCOUNTING_EXPORT_MODELCSV != 1 && $conf->global->ACCOUNTING_EXPORT_MODELCSV != 2) {
 		print '<input type="button" class="butActionRefused" style="float: right;" value="' . $langs->trans("Export") . '" disabled="disabled" title="' . $langs->trans('ExportNotSupported') . '"/>';
 	} else {
 		print '<input type="button" class="butAction" style="float: right;" value="' . $langs->trans("Export") . '" onclick="launch_export();" />';
-	}
-
+	}*/
+    print '<div class="tabsAction">';
 	print '<input type="button" class="butAction" value="' . $langs->trans("WriteBookKeeping") . '" onclick="writebookkeeping();" />';
-
+    print '</div>';
+    
 	print '
 	<script type="text/javascript">
 		function launch_export() {
@@ -503,7 +546,7 @@ if (empty($action) || $action == 'view') {
 	/*
 	 * Show result array
 	 */
-	print '<br><br>';
+	print '<br>';
 
 	$i = 0;
 	print "<table class=\"noborder\" width=\"100%\">";
@@ -552,8 +595,8 @@ if (empty($action) || $action == 'view') {
 			print "<td>" . $companystatic->getNomUrl(0, 'customer', 16) . ' - ' . $invoicestatic->ref . ' - ' . $langs->trans("Code_tiers") . "</td>";
 			print "</td><td align='right'>" . ($mt >= 0 ? price($mt) : '') . "</td>";
 			print "<td align='right'>" . ($mt < 0 ? price(- $mt) : '') . "</td>";
+		    print "</tr>";
 		}
-		print "</tr>";
 
 		// Product / Service
 		foreach ( $tabht[$key] as $k => $mt ) {

+ 7 - 2
htdocs/accountancy/supplier/lines.php

@@ -44,6 +44,7 @@ $langs->load("productbatch");
 $account_parent = GETPOST('account_parent');
 $changeaccount = GETPOST('changeaccount');
 // Search Getpost
+$search_lineid = GETPOST('search_lineid', 'int');
 $search_ref = GETPOST('search_ref', 'alpha');
 $search_invoice = GETPOST('search_invoice', 'alpha');
 $search_label = GETPOST('search_label', 'alpha');
@@ -85,6 +86,7 @@ $formventilation = new FormVentilation($db);
 // Purge search criteria
 if (GETPOST("button_removefilter_x") || GETPOST("button_removefilter.x") || GETPOST("button_removefilter")) // All tests are required to be compatible with all browsers
 {
+    $search_lineid = '';
 	$search_ref = '';
 	$search_invoice = '';
 	$search_label = '';
@@ -148,7 +150,7 @@ print '<script type="text/javascript">
  * Supplier Invoice lines
  */
 $sql = "SELECT f.rowid as facid, f.ref as facnumber, f.ref_supplier, f.libelle as invoice_label, f.datef,";
-$sql.= " l.fk_product, l.description, l.total_ht , l.qty, l.rowid, l.tva_tx, aa.label, aa.account_number, ";
+$sql.= " l.rowid, l.fk_product, l.description, l.total_ht , l.qty, l.tva_tx, aa.label, aa.account_number, ";
 $sql.= " p.rowid as product_id, p.ref as product_ref, p.label as product_label, p.fk_product_type as type";
 $sql.= " FROM " . MAIN_DB_PREFIX . "facture_fourn as f";
 $sql.= " , " . MAIN_DB_PREFIX . "accounting_account as aa";
@@ -156,6 +158,9 @@ $sql.= " , " . MAIN_DB_PREFIX . "facture_fourn_det as l";
 $sql.= " LEFT JOIN " . MAIN_DB_PREFIX . "product as p ON p.rowid = l.fk_product";
 $sql.= " WHERE f.rowid = l.fk_facture_fourn and f.fk_statut >= 1 AND l.fk_code_ventilation <> 0 ";
 $sql.= " AND aa.rowid = l.fk_code_ventilation";
+if ($search_lineid) {
+    $sql .= natural_search("l.rowid", $search_lineid, 1);
+}
 if (strlen(trim($search_invoice))) {
 	$sql .= natural_search("f.ref", $search_invoice);
 }
@@ -240,7 +245,7 @@ if ($result) {
 	print '<table class="tagtable liste'.($moreforfilter?" listwithfilterbefore":"").'">'."\n";
 	
 	print '<tr class="liste_titre_filter">';
-    print '<td class="liste_titre"></td>';
+	print '<td class="liste_titre"><input type="text" class="flat maxwidth50" name="search_lineid" value="' . dol_escape_htmltag($search_lineid) . '""></td>';
 	print '<td class="liste_titre"><input type="text" class="flat maxwidth50" name="search_invoice" value="' . dol_escape_htmltag($search_invoice) . '"></td>';
 	print '<td class="liste_titre"></td>';
 	print '<td class="liste_titre"></td>';

+ 7 - 2
htdocs/accountancy/supplier/list.php

@@ -52,6 +52,7 @@ $toselect = GETPOST('toselect', 'array');
 $mesCasesCochees = GETPOST('toselect', 'array');
 
 // Search Getpost
+$search_lineid = GETPOST('search_lineid', 'int');
 $search_invoice = GETPOST('search_invoice', 'alpha');
 $search_ref = GETPOST('search_ref', 'alpha');
 $search_label = GETPOST('search_label', 'alpha');
@@ -101,6 +102,7 @@ if (! GETPOST('confirmmassaction') && $massaction != 'presend' && $massaction !=
 // Purge search criteria
 if (GETPOST("button_removefilter_x") || GETPOST("button_removefilter.x") || GETPOST("button_removefilter")) // All test are required to be compatible with all browsers
 {
+    $search_lineid = '';
     $search_ref = '';
     $search_invoice = '';    
     $search_label = '';
@@ -179,7 +181,7 @@ llxHeader('', $langs->trans("SuppliersVentilation"));
 
 // Supplier Invoice Lines
 $sql = "SELECT f.rowid as facid, f.ref, f.ref_supplier, f.libelle as invoice_label, f.datef,";
-$sql.= " l.fk_product, l.description, l.total_ht as price, l.rowid, l.fk_code_ventilation, l.product_type as type_l, l.tva_tx as tva_tx_line, ";
+$sql.= " l.rowid, l.fk_product, l.description, l.total_ht as price, l.fk_code_ventilation, l.product_type as type_l, l.tva_tx as tva_tx_line, ";
 $sql.= " p.rowid as product_id, p.ref as product_ref, p.label as product_label, p.fk_product_type as type, p.accountancy_code_buy as code_buy, p.tva_tx as tva_tx_prod,";
 $sql.= " aa.rowid as aarowid";
 $sql.= " FROM " . MAIN_DB_PREFIX . "facture_fourn as f";
@@ -191,6 +193,9 @@ $sql.= " WHERE f.fk_statut > 0 AND l.fk_code_ventilation <= 0";
 $sql.= " AND product_type <= 2";
 $sql.= " AND (accsys.rowid='" . $conf->global->CHARTOFACCOUNTS . "' OR p.accountancy_code_buy IS NULL OR p.accountancy_code_buy ='')";
 // Add search filter like
+if ($search_lineid) {
+    $sql .= natural_search("l.rowid", $search_lineid, 1);
+}
 if (strlen(trim($search_invoice))) {
     $sql .= natural_search("f.ref",$search_invoice);
 }
@@ -272,7 +277,7 @@ if ($result) {
 
 	// We add search filter
 	print '<tr class="liste_titre_filter">';
-	print '<td class="liste_titre"></td>';
+	print '<td class="liste_titre"><input type="text" class="flat maxwidth50" name="search_lineid" value="' . dol_escape_htmltag($search_lineid) . '""></td>';
 	print '<td class="liste_titre"><input type="text" class="flat maxwidth50" name="search_invoice" value="' . dol_escape_htmltag($search_invoice) . '"></td>';
 	print '<td class="liste_titre"></td>';
 	print '<td class="liste_titre"></td>';

+ 3 - 3
htdocs/adherents/subscription.php

@@ -89,14 +89,14 @@ if ($rowid)
     $caneditfieldmember=$user->rights->adherent->creer;
 }
 
+// Initialize technical object to manage hooks of thirdparties. Note that conf->hooks_modules contains array array
+$hookmanager->initHooks(array('subscription'));
+
 // PDF
 $hidedetails = (GETPOST('hidedetails', 'int') ? GETPOST('hidedetails', 'int') : (! empty($conf->global->MAIN_GENERATE_DOCUMENTS_HIDE_DETAILS) ? 1 : 0));
 $hidedesc = (GETPOST('hidedesc', 'int') ? GETPOST('hidedesc', 'int') : (! empty($conf->global->MAIN_GENERATE_DOCUMENTS_HIDE_DESC) ? 1 : 0));
 $hideref = (GETPOST('hideref', 'int') ? GETPOST('hideref', 'int') : (! empty($conf->global->MAIN_GENERATE_DOCUMENTS_HIDE_REF) ? 1 : 0));
 
-
-
-
 /*
  * 	Actions
  */

+ 2 - 3
htdocs/admin/agenda.php

@@ -144,13 +144,12 @@ print '<input type="hidden" name="action" value="save">';
 
 $head=agenda_prepare_head();
 
-dol_fiche_head($head, 'autoactions', $langs->trans("Agenda"), 0, 'action');
+dol_fiche_head($head, 'autoactions', $langs->trans("Agenda"), -1, 'action');
 
 print $langs->trans("AgendaAutoActionDesc")."<br>\n";
 print $langs->trans("OnlyActiveElementsAreShown").'<br>';
 print "<br>\n";
 
-$var=true;
 print '<table class="noborder" width="100%">';
 print '<tr class="liste_titre">';
 print '<td colspan="2">'.$langs->trans("ActionsEvents").'</td>';
@@ -180,7 +179,7 @@ if (! empty($triggers))
 			print '<td align="right" width="40">';
 			$key='MAIN_AGENDA_ACTIONAUTO_'.$trigger['code'];
 			$value=$conf->global->$key;
-			print '<input '.$bc[$var].' type="checkbox" name="'.$key.'" value="1"'.((($action=='selectall'||$value) && $action!="selectnone")?' checked':'').'>';
+			print '<input class="oddeven" type="checkbox" name="'.$key.'" value="1"'.((($action=='selectall'||$value) && $action!="selectnone")?' checked':'').'>';
 			print '</td></tr>'."\n";
 		}
 	}

+ 1 - 1
htdocs/admin/agenda_extrafields.php

@@ -75,7 +75,7 @@ print "<br>\n";
 
 $head=agenda_prepare_head();
 
-dol_fiche_head($head, 'attributes', $langs->trans("Agenda"), 0, 'action');
+dol_fiche_head($head, 'attributes', $langs->trans("Agenda"), -1, 'action');
 
 require DOL_DOCUMENT_ROOT.'/core/tpl/admin_extrafields_view.tpl.php';
 

+ 1 - 1
htdocs/admin/agenda_extsites.php

@@ -137,7 +137,7 @@ print '<input type="hidden" name="action" value="save">';
 
 $head=agenda_prepare_head();
 
-dol_fiche_head($head, 'extsites', $langs->trans("Agenda"), 0, 'action');
+dol_fiche_head($head, 'extsites', $langs->trans("Agenda"), -1, 'action');
 
 print $langs->trans("AgendaExtSitesDesc")."<br>\n";
 print "<br>\n";

+ 3 - 10
htdocs/admin/agenda_other.php

@@ -196,7 +196,7 @@ print "<br>\n";
 
 $head=agenda_prepare_head();
 
-dol_fiche_head($head, 'other', $langs->trans("Agenda"), 0, 'action');
+dol_fiche_head($head, 'other', $langs->trans("Agenda"), -1, 'action');
 
 
 /*
@@ -245,7 +245,6 @@ if ($conf->global->MAIN_FEATURES_LEVEL >= 2)
     
     clearstatcache();
     
-    $var=true;
     foreach ($dirmodels as $reldir)
     {
     	$dir = dol_buildpath($reldir."core/modules/action/doc/");
@@ -263,10 +262,9 @@ if ($conf->global->MAIN_FEATURES_LEVEL >= 2)
             			$classname = substr($file, 0, dol_strlen($file) -12);
             			
             			require_once $dir.'/'.$file;
-            			$module = new $classname($db, new ActionComm($db));
+            			$module = new $classname($db, new ActionComm($db));           			
             			
-            			
-            			print "<tr ".$bc[$var].">\n";
+            			print '<tr class="oddeven">'."\n";
             			print "<td>";
             			print (empty($module->name)?$name:$module->name);
             			print "</td>\n";
@@ -338,8 +336,6 @@ if ($conf->global->MAIN_FEATURES_LEVEL >= 2)
     print '</table><br>';
 }
 
-$var=true;
-
 print '<form action="'.$_SERVER["PHP_SELF"].'" name="agenda">';
 print '<input type="hidden" name="action" value="set">';
 
@@ -380,7 +376,6 @@ if (! empty($conf->global->AGENDA_USE_EVENT_TYPE))
 }
 
 // AGENDA_DEFAULT_FILTER_TYPE
-
 print '<tr class="oddeven">'."\n";
 print '<td>'.$langs->trans("AGENDA_DEFAULT_FILTER_TYPE").'</td>'."\n";
 print '<td align="center">&nbsp;</td>'."\n";
@@ -389,7 +384,6 @@ $formactions->select_type_actions($conf->global->AGENDA_DEFAULT_FILTER_TYPE, "AG
 print '</td></tr>'."\n";
 
 // AGENDA_DEFAULT_FILTER_STATUS
-
 print '<tr class="oddeven">'."\n";
 print '<td>'.$langs->trans("AGENDA_DEFAULT_FILTER_STATUS").'</td>'."\n";
 print '<td align="center">&nbsp;</td>'."\n";
@@ -398,7 +392,6 @@ $formactions->form_select_status_action('agenda', $conf->global->AGENDA_DEFAULT_
 print '</td></tr>'."\n";
 
 // AGENDA_DEFAULT_VIEW
-
 print '<tr class="oddeven">'."\n";
 print '<td>'.$langs->trans("AGENDA_DEFAULT_VIEW").'</td>'."\n";
 print '<td align="center">&nbsp;</td>'."\n";

+ 1 - 1
htdocs/admin/agenda_xcal.php

@@ -83,7 +83,7 @@ print '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
 
 $head=agenda_prepare_head();
 
-dol_fiche_head($head, 'xcal', $langs->trans("Agenda"), 0, 'action');
+dol_fiche_head($head, 'xcal', $langs->trans("Agenda"), -1, 'action');
 
 print $langs->trans("AgendaSetupOtherDesc")."<br>\n";
 print "<br>\n";

+ 1 - 3
htdocs/admin/bank.php

@@ -273,7 +273,6 @@ print "</tr>\n";
 
 clearstatcache();
 
-$var = true;
 foreach ($dirmodels as $reldir) 
 {
     foreach (array('', '/doc') as $valdir) {
@@ -305,8 +304,7 @@ foreach ($dirmodels as $reldir)
                                 $modulequalified = 0;
                             
                             if ($modulequalified) {
-                                $var = ! $var;
-                                print '<tr ' . $bc[$var] . '><td width="100">';
+                                print '<tr class="oddeven"><td width="100">';
                                 print(empty($module->name) ? $name : $module->name);
                                 print "</td><td>\n";
                                 if (method_exists($module, 'info'))

+ 2 - 1
htdocs/admin/clicktodial.php

@@ -91,7 +91,8 @@ print '</td></tr>';
 
 print '<tr class="oddeven"><td>';
 print $langs->trans("DefaultLink").'</td><td>';
-print '<input style="width: 90%" type="text" name="CLICKTODIAL_URL"'.($conf->global->CLICKTODIAL_USE_TEL_LINK_ON_PHONE_NUMBERS?' disabled="disabled"':'').' value="'.$conf->global->CLICKTODIAL_URL.'"><br>';
+print '<input class="quatrevingtpercent" type="text" id="CLICKTODIAL_URL" name="CLICKTODIAL_URL"'.($conf->global->CLICKTODIAL_USE_TEL_LINK_ON_PHONE_NUMBERS?' disabled="disabled"':'').' value="'.$conf->global->CLICKTODIAL_URL.'"><br>';
+print ajax_autoselect('CLICKTODIAL_URL');
 print '<br>';
 print $langs->trans("ClickToDialUrlDesc").'<br>';
 print $langs->trans("Example").':<br>http://myphoneserver/mypage?login=__LOGIN__&password=__PASS__&caller=__PHONEFROM__&called=__PHONETO__';

+ 13 - 23
htdocs/admin/company.php

@@ -3,7 +3,7 @@
  * Copyright (C) 2004-2013	Laurent Destailleur		<eldy@users.sourceforge.net>
  * Copyright (C) 2005-2012	Regis Houssin			<regis.houssin@capnetworks.com>
  * Copyright (C) 2010-2014	Juanjo Menent			<jmenent@2byte.es>
- * Copyright (C) 2011-2016	Philippe Grand			<philippe.grand@atoo-net.com>
+ * Copyright (C) 2011-2017	Philippe Grand			<philippe.grand@atoo-net.com>
  * Copyright (C) 2015       Alexandre Spangaro      <aspangaro.dolibarr@gmail.com>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -545,7 +545,6 @@ if ($action == 'edit' || $action == 'updateedit')
 	print '<tr class="liste_titre">';
 	print '<td class="titlefield">'.$langs->trans("FiscalYearInformation").'</td><td>'.$langs->trans("Value").'</td>';
 	print "</tr>\n";
-	$var=true;
 
 	
 	print '<tr class="oddeven"><td><label for="fiscalmonthstart">'.$langs->trans("FiscalMonthStart").'</label></td><td>';
@@ -561,10 +560,9 @@ if ($action == 'edit' || $action == 'updateedit')
 	print '<td class="titlefield">'.$langs->trans("VATManagement").'</td><td>'.$langs->trans("Description").'</td>';
 	print '<td align="right">&nbsp;</td>';
 	print "</tr>\n";
-	$var=true;
 
 	
-	print "<tr ".$bc[$var]."><td width=\"140\"><label><input type=\"radio\" name=\"optiontva\" id=\"use_vat\" value=\"1\"".(empty($conf->global->FACTURE_TVAOPTION)?"":" checked")."> ".$langs->trans("VATIsUsed")."</label></td>";
+	print "<tr class=\"oddeven\"><td width=\"140\"><label><input type=\"radio\" name=\"optiontva\" id=\"use_vat\" value=\"1\"".(empty($conf->global->FACTURE_TVAOPTION)?"":" checked")."> ".$langs->trans("VATIsUsed")."</label></td>";
 	print '<td colspan="2">';
 	print "<table>";
 	print "<tr><td><label for=\"use_vat\">".$langs->trans("VATIsUsedDesc")."</label></td></tr>";
@@ -573,7 +571,7 @@ if ($action == 'edit' || $action == 'updateedit')
 	print "</td></tr>\n";
 
 	
-	print "<tr ".$bc[$var]."><td width=\"140\"><label><input type=\"radio\" name=\"optiontva\" id=\"no_vat\" value=\"0\"".(empty($conf->global->FACTURE_TVAOPTION)?" checked":"")."> ".$langs->trans("VATIsNotUsed")."</label></td>";
+	print "<tr class=\"oddeven\"><td width=\"140\"><label><input type=\"radio\" name=\"optiontva\" id=\"no_vat\" value=\"0\"".(empty($conf->global->FACTURE_TVAOPTION)?" checked":"")."> ".$langs->trans("VATIsNotUsed")."</label></td>";
 	print '<td colspan="2">';
 	print "<table>";
 	print "<tr><td><label for=\"no_vat\">".$langs->trans("VATIsNotUsedDesc")."</label></td></tr>";
@@ -595,10 +593,9 @@ if ($action == 'edit' || $action == 'updateedit')
 		print '<td>'.$langs->transcountry("LocalTax1Management",$mysoc->country_code).'</td><td>'.$langs->trans("Description").'</td>';
 		print '<td align="right">&nbsp;</td>';
 		print "</tr>\n";
-		$var=true;
 		
 		// Note: When option is not set, it must not appears as set on on, because there is no default value for this option
-		print "<tr ".$bc[$var]."><td width=\"140\"><input type=\"radio\" name=\"optionlocaltax1\" id=\"lt1\" value=\"localtax1on\"".(($conf->global->FACTURE_LOCAL_TAX1_OPTION == '1' || $conf->global->FACTURE_LOCAL_TAX1_OPTION == "localtax1on")?" checked":"")."> ".$langs->transcountry("LocalTax1IsUsed",$mysoc->country_code)."</td>";
+		print "<tr class=\"oddeven\"><td width=\"140\"><input type=\"radio\" name=\"optionlocaltax1\" id=\"lt1\" value=\"localtax1on\"".(($conf->global->FACTURE_LOCAL_TAX1_OPTION == '1' || $conf->global->FACTURE_LOCAL_TAX1_OPTION == "localtax1on")?" checked":"")."> ".$langs->transcountry("LocalTax1IsUsed",$mysoc->country_code)."</td>";
 		print '<td colspan="2">';
 		print '<table class="nobordernopadding">';
 		print "<tr><td><label for=\"lt1\">".$langs->transcountry("LocalTax1IsUsedDesc",$mysoc->country_code)."</label></td></tr>";
@@ -620,7 +617,7 @@ if ($action == 'edit' || $action == 'updateedit')
 		print "</td></tr>\n";
 
 		
-		print "<tr ".$bc[$var]."><td width=\"140\"><input type=\"radio\" name=\"optionlocaltax1\" id=\"nolt1\" value=\"localtax1off\"".((empty($conf->global->FACTURE_LOCAL_TAX1_OPTION) || $conf->global->FACTURE_LOCAL_TAX1_OPTION == "localtax1off")?" checked":"")."> ".$langs->transcountry("LocalTax1IsNotUsed",$mysoc->country_code)."</td>";
+		print "<tr class=\"oddeven\"><td width=\"140\"><input type=\"radio\" name=\"optionlocaltax1\" id=\"nolt1\" value=\"localtax1off\"".((empty($conf->global->FACTURE_LOCAL_TAX1_OPTION) || $conf->global->FACTURE_LOCAL_TAX1_OPTION == "localtax1off")?" checked":"")."> ".$langs->transcountry("LocalTax1IsNotUsed",$mysoc->country_code)."</td>";
 		print '<td colspan="2">';
 		print "<table>";
 		print "<tr><td><label for=\"nolt1\">".$langs->transcountry("LocalTax1IsNotUsedDesc",$mysoc->country_code)."</label></td></tr>";
@@ -639,11 +636,10 @@ if ($action == 'edit' || $action == 'updateedit')
 		print '<td>'.$langs->transcountry("LocalTax2Management",$mysoc->country_code).'</td><td>'.$langs->trans("Description").'</td>';
 		print '<td align="right">&nbsp;</td>';
 		print "</tr>\n";
-		$var=true;
 
 		
 		// Note: When option is not set, it must not appears as set on on, because there is no default value for this option
-		print "<tr ".$bc[$var]."><td width=\"140\"><input type=\"radio\" name=\"optionlocaltax2\" id=\"lt2\" value=\"localtax2on\"".(($conf->global->FACTURE_LOCAL_TAX2_OPTION == '1' || $conf->global->FACTURE_LOCAL_TAX2_OPTION == "localtax2on")?" checked":"")."> ".$langs->transcountry("LocalTax2IsUsed",$mysoc->country_code)."</td>";
+		print "<tr class=\"oddeven\"><td width=\"140\"><input type=\"radio\" name=\"optionlocaltax2\" id=\"lt2\" value=\"localtax2on\"".(($conf->global->FACTURE_LOCAL_TAX2_OPTION == '1' || $conf->global->FACTURE_LOCAL_TAX2_OPTION == "localtax2on")?" checked":"")."> ".$langs->transcountry("LocalTax2IsUsed",$mysoc->country_code)."</td>";
 		print '<td colspan="2">';
 		print '<table class="nobordernopadding">';
 		print "<tr><td><label for=\"lt2\">".$langs->transcountry("LocalTax2IsUsedDesc",$mysoc->country_code)."</label></td></tr>";
@@ -662,7 +658,7 @@ if ($action == 'edit' || $action == 'updateedit')
 		print "</td></tr>\n";
 
 		
-		print "<tr ".$bc[$var]."><td width=\"140\"><input type=\"radio\" name=\"optionlocaltax2\" id=\"nolt2\" value=\"localtax2off\"".((empty($conf->global->FACTURE_LOCAL_TAX2_OPTION) || $conf->global->FACTURE_LOCAL_TAX2_OPTION == "localtax2off")?" checked":"")."> ".$langs->transcountry("LocalTax2IsNotUsed",$mysoc->country_code)."</td>";
+		print "<tr class=\"oddeven\"><td width=\"140\"><input type=\"radio\" name=\"optionlocaltax2\" id=\"nolt2\" value=\"localtax2off\"".((empty($conf->global->FACTURE_LOCAL_TAX2_OPTION) || $conf->global->FACTURE_LOCAL_TAX2_OPTION == "localtax2off")?" checked":"")."> ".$langs->transcountry("LocalTax2IsNotUsed",$mysoc->country_code)."</td>";
 		print '<td colspan="2">';
 		print "<table>";
 		print "<tr><td><label for=\"nolt2\">".$langs->transcountry("LocalTax2IsNotUsedDesc",$mysoc->country_code)."</label></td></tr>";
@@ -696,7 +692,6 @@ else
 
 	print '<table class="noborder" width="100%">';
 	print '<tr class="liste_titre"><td>'.$langs->trans("CompanyInfo").'</td><td>'.$langs->trans("Value").'</td></tr>';
-	$var=true;
 
 	
 	print '<tr class="oddeven"><td class="titlefield">'.$langs->trans("CompanyName").'</td><td>';
@@ -799,7 +794,6 @@ else
 	print '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
 	print '<table class="noborder" width="100%">';
 	print '<tr class="liste_titre"><td class="titlefield">'.$langs->trans("CompanyIds").'</td><td>'.$langs->trans("Value").'</td></tr>';
-	$var=true;
 
 	// Managing Director(s)
 	
@@ -965,7 +959,6 @@ else
 	print '<tr class="liste_titre">';
 	print '<td class="titlefield">'.$langs->trans("FiscalYearInformation").'</td><td>'.$langs->trans("Value").'</td>';
 	print "</tr>\n";
-	$var=true;
 
 	
 	print '<tr class="oddeven"><td>'.$langs->trans("FiscalMonthStart").'</td><td>';
@@ -983,10 +976,9 @@ else
 	print '<td>'.$langs->trans("VATManagement").'</td><td>'.$langs->trans("Description").'</td>';
 	print '<td align="right">&nbsp;</td>';
 	print "</tr>\n";
-	$var=true;
 
 	
-	print "<tr ".$bc[$var]."><td width=\"160\"><input ".$bc[$var]." type=\"radio\" name=\"optiontva\" id=\"use_vat\" disabled value=\"1\"".(empty($conf->global->FACTURE_TVAOPTION)?"":" checked")."> ".$langs->trans("VATIsUsed")."</td>";
+	print "<tr class=\"oddeven\"><td width=\"160\"><input class=\"oddeven\" type=\"radio\" name=\"optiontva\" id=\"use_vat\" disabled value=\"1\"".(empty($conf->global->FACTURE_TVAOPTION)?"":" checked")."> ".$langs->trans("VATIsUsed")."</td>";
 	print '<td colspan="2">';
 	print "<table>";
 	print "<tr><td><label for=\"use_vat\">".$langs->trans("VATIsUsedDesc")."</label></td></tr>";
@@ -995,7 +987,7 @@ else
 	print "</td></tr>\n";
 
 	
-	print "<tr ".$bc[$var]."><td width=\"160\"><input ".$bc[$var]." type=\"radio\" name=\"optiontva\" id=\"no_vat\" disabled value=\"0\"".(empty($conf->global->FACTURE_TVAOPTION)?" checked":"")."> ".$langs->trans("VATIsNotUsed")."</td>";
+	print "<tr class=\"oddeven\"><td width=\"160\"><input class=\"oddeven\" type=\"radio\" name=\"optiontva\" id=\"no_vat\" disabled value=\"0\"".(empty($conf->global->FACTURE_TVAOPTION)?" checked":"")."> ".$langs->trans("VATIsNotUsed")."</td>";
 	print '<td colspan="2">';
 	print "<table>";
 	print "<tr><td><label=\"no_vat\">".$langs->trans("VATIsNotUsedDesc")."</label></td></tr>";
@@ -1018,10 +1010,9 @@ else
 		print '<td>'.$langs->transcountry("LocalTax1Management",$mysoc->country_code).'</td><td>'.$langs->trans("Description").'</td>';
 		print '<td align="right">&nbsp;</td>';
 		print "</tr>\n";
-		$var=true;
 
 		
-		print "<tr ".$bc[$var]."><td width=\"160\"><input ".$bc[$var]." type=\"radio\" name=\"optionlocaltax1\" id=\"lt1\" disabled value=\"localtax1on\"".(($conf->global->FACTURE_LOCAL_TAX1_OPTION == '1' || $conf->global->FACTURE_LOCAL_TAX1_OPTION == "localtax1on")?" checked":"")."> ".$langs->transcountry("LocalTax1IsUsed",$mysoc->country_code)."</td>";
+		print "<tr class=\"oddeven\"><td width=\"160\"><input class=\"oddeven\" type=\"radio\" name=\"optionlocaltax1\" id=\"lt1\" disabled value=\"localtax1on\"".(($conf->global->FACTURE_LOCAL_TAX1_OPTION == '1' || $conf->global->FACTURE_LOCAL_TAX1_OPTION == "localtax1on")?" checked":"")."> ".$langs->transcountry("LocalTax1IsUsed",$mysoc->country_code)."</td>";
 		print '<td colspan="2">';
 		print "<table>";
 		print "<tr><td></label for=\"lt1\">".$langs->transcountry("LocalTax1IsUsedDesc",$mysoc->country_code)."</label></td></tr>";
@@ -1049,7 +1040,7 @@ else
 		print "</td></tr>\n";
 
 		
-		print "<tr ".$bc[$var]."><td width=\"160\"><input ".$bc[$var]." type=\"radio\" name=\"optionlocaltax1\" id=\"nolt1\" disabled value=\"localtax1off\"".((empty($conf->global->FACTURE_LOCAL_TAX1_OPTION) || $conf->global->FACTURE_LOCAL_TAX1_OPTION == "localtax1off")?" checked":"")."> ".$langs->transcountry("LocalTax1IsNotUsed",$mysoc->country_code)."</td>";
+		print "<tr class=\"oddeven\"><td width=\"160\"><input class=\"oddeven\" type=\"radio\" name=\"optionlocaltax1\" id=\"nolt1\" disabled value=\"localtax1off\"".((empty($conf->global->FACTURE_LOCAL_TAX1_OPTION) || $conf->global->FACTURE_LOCAL_TAX1_OPTION == "localtax1off")?" checked":"")."> ".$langs->transcountry("LocalTax1IsNotUsed",$mysoc->country_code)."</td>";
 		print '<td colspan="2">';
 		print "<table>";
 		print "<tr><td><label for=\"no_lt1\">".$langs->transcountry("LocalTax1IsNotUsedDesc",$mysoc->country_code)."</label></td></tr>";
@@ -1069,10 +1060,9 @@ else
 		print '<td>'.$langs->transcountry("LocalTax2Management",$mysoc->country_code).'</td><td>'.$langs->trans("Description").'</td>';
 		print '<td align="right">&nbsp;</td>';
 		print "</tr>\n";
-		$var=true;
 
 		
-		print "<tr ".$bc[$var]."><td width=\"160\"><input ".$bc[$var]." type=\"radio\" name=\"optionlocaltax2\" id=\"lt2\" disabled value=\"localtax2on\"".(($conf->global->FACTURE_LOCAL_TAX2_OPTION == '1' || $conf->global->FACTURE_LOCAL_TAX2_OPTION == "localtax2on")?" checked":"")."> ".$langs->transcountry("LocalTax2IsUsed",$mysoc->country_code)."</td>";
+		print "<tr class=\"oddeven\"><td width=\"160\"><input class=\"oddeven\" type=\"radio\" name=\"optionlocaltax2\" id=\"lt2\" disabled value=\"localtax2on\"".(($conf->global->FACTURE_LOCAL_TAX2_OPTION == '1' || $conf->global->FACTURE_LOCAL_TAX2_OPTION == "localtax2on")?" checked":"")."> ".$langs->transcountry("LocalTax2IsUsed",$mysoc->country_code)."</td>";
 		print '<td colspan="2">';
 		print "<table>";
 		print "<tr><td><label for=\"lt2\">".$langs->transcountry("LocalTax2IsUsedDesc",$mysoc->country_code)."</label></td></tr>";
@@ -1101,7 +1091,7 @@ else
 		print "</td></tr>\n";
 
 		
-		print "<tr ".$bc[$var]."><td width=\"160\"><input ".$bc[$var]." type=\"radio\" name=\"optionlocaltax2\" id=\"nolt2\" disabled value=\"localtax2off\"".((empty($conf->global->FACTURE_LOCAL_TAX2_OPTION) || $conf->global->FACTURE_LOCAL_TAX2_OPTION == "localtax2off")?" checked":"")."> ".$langs->transcountry("LocalTax2IsNotUsed",$mysoc->country_code)."</td>";
+		print "<tr class=\"oddeven\"><td width=\"160\"><input class=\"oddeven\" type=\"radio\" name=\"optionlocaltax2\" id=\"nolt2\" disabled value=\"localtax2off\"".((empty($conf->global->FACTURE_LOCAL_TAX2_OPTION) || $conf->global->FACTURE_LOCAL_TAX2_OPTION == "localtax2off")?" checked":"")."> ".$langs->transcountry("LocalTax2IsNotUsed",$mysoc->country_code)."</td>";
 		print '<td colspan="2">';
 		print "<table>";
 		print "<tr><td><label for=\"nolt2\">".$langs->transcountry("LocalTax2IsNotUsedDesc",$mysoc->country_code)."</label></td></tr>";

+ 4 - 5
htdocs/admin/compta.php

@@ -3,7 +3,7 @@
  * Copyright (C) 2004-2008 Laurent Destailleur  <eldy@users.sourceforge.net>
  * Copyright (C) 2005-2009 Regis Houssin        <regis.houssin@capnetworks.com>
  * Copyright (C) 2011-2013 Juanjo Menent	    <jmenent@2byte.es>
- * Copyright (C) 2013-2016 Philippe Grand	    <philippe.grand@atoo-net.com>
+ * Copyright (C) 2013-2017 Philippe Grand	    <philippe.grand@atoo-net.com>
  * Copyright (C) 2014      Marcos García        <marcosgdf@gmail.com>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -119,7 +119,7 @@ print '<table class="noborder" width="100%">';
 print '<tr class="liste_titre">';
 print '<td>'.$langs->trans('OptionMode').'</td><td>'.$langs->trans('Description').'</td>';
 print "</tr>\n";
-print '<tr '.$bc[false].'><td width="200"><input type="radio" name="accounting_mode" value="RECETTES-DEPENSES"'.($accounting_mode != 'CREANCES-DETTES' ? ' checked' : '').'> '.$langs->trans('OptionModeTrue').'</td>';
+print '<tr class="oddeven"><td width="200"><input type="radio" name="accounting_mode" value="RECETTES-DEPENSES"'.($accounting_mode != 'CREANCES-DETTES' ? ' checked' : '').'> '.$langs->trans('OptionModeTrue').'</td>';
 print '<td colspan="2">'.nl2br($langs->trans('OptionModeTrueDesc'));
 // Write info on way to count VAT
 //if (! empty($conf->global->MAIN_MODULE_COMPTABILITE))
@@ -133,7 +133,7 @@ print '<td colspan="2">'.nl2br($langs->trans('OptionModeTrueDesc'));
 //	//	print nl2br($langs->trans('OptionModeTrueInfoExpert'));
 //}
 print "</td></tr>\n";
-print '<tr '.$bc[true].'><td width="200"><input type="radio" name="accounting_mode" value="CREANCES-DETTES"'.($accounting_mode == 'CREANCES-DETTES' ? ' checked' : '').'> '.$langs->trans('OptionModeVirtual').'</td>';
+print '<tr class="oddeven"><td width="200"><input type="radio" name="accounting_mode" value="CREANCES-DETTES"'.($accounting_mode == 'CREANCES-DETTES' ? ' checked' : '').'> '.$langs->trans('OptionModeVirtual').'</td>';
 print '<td colspan="2">'.nl2br($langs->trans('OptionModeVirtualDesc'))."</td></tr>\n";
 
 print "</table>\n";
@@ -149,8 +149,7 @@ print "</tr>\n";
 foreach ($list as $key)
 {
 	
-
-	print '<tr '.$bc[$var].' class="value">';
+	print '<tr class="oddeven value">';
 
 	// Param
 	$libelle = $langs->trans($key);

+ 78 - 33
htdocs/admin/defaultvalues.php

@@ -37,7 +37,7 @@ if (!$user->admin) accessforbidden();
 $id=GETPOST('rowid','int');
 $action=GETPOST('action','alpha');
 
-$mode = GETPOST('mode')?GETPOST('mode'):'createform';   // 'createform', 'filters', 'sortorder'
+$mode = GETPOST('mode')?GETPOST('mode'):'createform';   // 'createform', 'filters', 'sortorder', 'focus'
 
 $limit = GETPOST("limit")?GETPOST("limit","int"):$conf->liste_limit;
 $sortfield = GETPOST("sortfield",'alpha');
@@ -84,6 +84,11 @@ if (GETPOST("button_removefilter_x") || GETPOST("button_removefilter.x") || GETP
     $search_array_options=array();
 }
 
+if ($action == 'setMAIN_ENABLE_DEFAULT_VALUES')
+{
+    if (GETPOST('value')) dolibarr_set_const($db, 'MAIN_ENABLE_DEFAULT_VALUES', 1, 'chaine', 0, '', $conf->entity);
+    else dolibarr_set_const($db, 'MAIN_ENABLE_DEFAULT_VALUES', 0, 'chaine', 0, '', $conf->entity);
+}
 
 if (($action == 'add' || (GETPOST('add') && $action != 'update')) || GETPOST('actionmodify'))
 {
@@ -185,6 +190,23 @@ print load_fiche_titre($langs->trans("DefaultValues"),'','title_setup');
 print $langs->trans("DefaultValuesDesc")."<br>\n";
 print "<br>\n";
 
+print $langs->trans("EnableDefaultValues").' ';
+if (empty($conf->global->MAIN_ENABLE_DEFAULT_VALUES))
+{
+    // Button off, click to enable
+    print '<a class="reposition" href="'.$_SERVER["PHP_SELF"].'?action=setMAIN_ENABLE_DEFAULT_VALUES&amp;value=1">';
+    print img_picto($langs->trans("Disabled"),'switch_off');
+    print '</a>';
+}
+else
+{
+    // Button on, click to disable
+    print '<a class="reposition" href="'.$_SERVER["PHP_SELF"].'?action=setMAIN_ENABLE_DEFAULT_VALUES&amp;value=0">';
+    print img_picto($langs->trans("Activated"),'switch_on');
+    print '</a>';
+}
+print "<br><br>\n";
+
 $param='&mode='.$mode;
 if (! empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) $param.='&contextpage='.$contextpage;
 if ($limit > 0 && $limit != $conf->liste_limit) $param.='&limit='.$limit;
@@ -210,6 +232,10 @@ if ($mode == 'sortorder')
 {
     print info_admin($langs->trans("WarningSettingSortOrder")).'<br>';
 }
+if ($mode == 'focus')
+{
+    print info_admin($langs->trans("FeatureNotYetAvailable")).'<br>';
+}
 
 print '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
 print '<input type="hidden" id="action" name="action" value="">';
@@ -217,11 +243,13 @@ print '<input type="hidden" id="mode" name="mode" value="'.dol_escape_htmltag($m
 
 print '<table class="noborder" width="100%">';
 print '<tr class="liste_titre">';
+// Page
 $texthelp=$langs->trans("PageUrlForDefaultValues");
 if ($mode == 'createform') $texthelp.=$langs->trans("PageUrlForDefaultValuesCreate", 'societe/card.php');
 else $texthelp.=$langs->trans("PageUrlForDefaultValuesList", 'societe/list.php');
 $texturl=$form->textwithpicto($langs->trans("Url"), $texthelp);
 print_liste_field_titre($texturl,$_SERVER["PHP_SELF"],'page,param','',$param,'',$sortfield,$sortorder);
+// Field
 $texthelp=$langs->trans("TheKeyIsTheNameOfHtmlField");
 if ($mode != 'sortorder') 
 {
@@ -233,26 +261,32 @@ else
     $textkey=$form->textwithpicto($langs->trans("Field"), $texthelp);
 }
 print_liste_field_titre($textkey,$_SERVER["PHP_SELF"],'param','',$param,'',$sortfield,$sortorder);
-if ($mode != 'sortorder')
-{
-    $texthelp=$langs->trans("FollowingConstantsWillBeSubstituted").'<br>';
-    // See list into GETPOST
-    $texthelp.='__USERID__<br>';
-    $texthelp.='__SUPERVISORID__<br>';
-    $texthelp.='__MYCOUNTRYID__<br>';
-    $texthelp.='__DAY__<br>';
-    $texthelp.='__MONTH__<br>';
-    $texthelp.='__YEAR__<br>';
-    if (! empty($conf->multicompany->enabled)) $texthelp.='__ENTITYID__<br>';
-    $textvalue=$form->textwithpicto($langs->trans("Value"), $texthelp, 1, 'help', '', 0, 2, '');
-}
-else
+// Value
+if ($mode != 'focus')
 {
-    $texthelp='ASC or DESC';
-    $textvalue=$form->textwithpicto($langs->trans("SortOrder"), $texthelp);
+    if ($mode != 'sortorder')
+    {
+        $texthelp=$langs->trans("FollowingConstantsWillBeSubstituted").'<br>';
+        // See list into GETPOST
+        $texthelp.='__USERID__<br>';
+        $texthelp.='__SUPERVISORID__<br>';
+        $texthelp.='__MYCOUNTRYID__<br>';
+        $texthelp.='__DAY__<br>';
+        $texthelp.='__MONTH__<br>';
+        $texthelp.='__YEAR__<br>';
+        if (! empty($conf->multicompany->enabled)) $texthelp.='__ENTITYID__<br>';
+        $textvalue=$form->textwithpicto($langs->trans("Value"), $texthelp, 1, 'help', '', 0, 2, '');
+    }
+    else
+    {
+        $texthelp='ASC or DESC';
+        $textvalue=$form->textwithpicto($langs->trans("SortOrder"), $texthelp);
+    }
+    print_liste_field_titre($textvalue, $_SERVER["PHP_SELF"], 'value', '', $param, '', $sortfield, $sortorder);
 }
-print_liste_field_titre($textvalue, $_SERVER["PHP_SELF"], 'value', '', $param, '', $sortfield, $sortorder);
+// Entity
 if (! empty($conf->multicompany->enabled) && !$user->entity) print_liste_field_titre($langs->trans("Entity"),$_SERVER["PHP_SELF"],'entity,page','',$param,'',$sortfield,$sortorder);
+// Actions
 print '<td align="center"></td>';
 print "</tr>\n";
 
@@ -261,15 +295,21 @@ print "</tr>\n";
 print "\n";
 
 print '<tr class="oddeven">';
+// Page
 print '<td>';
 print '<input type="text" class="flat minwidth200 maxwidthonsmartphone" name="defaulturl" value="">';
 print '</td>'."\n";
+// Field
 print '<td>';
 print '<input type="text" class="flat maxwidth100" name="defaultkey" value="">';
 print '</td>';
-print '<td>';
-print '<input type="text" class="flat maxwidthonsmartphone" name="defaultvalue" value="">';
-print '</td>';
+// Value
+if ($mode != 'focus')
+{
+    print '<td>';
+    print '<input type="text" class="flat maxwidthonsmartphone" name="defaultvalue" value="">';
+    print '</td>';
+}
 // Limit to superadmin
 if (! empty($conf->multicompany->enabled) && !$user->entity)
 {
@@ -311,28 +351,33 @@ if ($result)
 
 		print '<tr class="oddeven">';
 		
+		// Page
 		print '<td>';
 		if ($action != 'edit' || GETPOST('rowid') != $obj->rowid) print $obj->page;
 		else print '<input type="text" name="urlpage" value="'.dol_escape_htmltag($obj->page).'">';
 		print '</td>'."\n";
    	    
-		// Key
+		// Field
 		print '<td>';
 		if ($action != 'edit' || GETPOST('rowid') != $obj->rowid) print $obj->param;
 		else print '<input type="text" name="key" value="'.dol_escape_htmltag($obj->param).'">';
 		print '</td>'."\n";
 
 		// Value
-		print '<td>';
-		/*print '<input type="hidden" name="const['.$i.'][rowid]" value="'.$obj->rowid.'">';
-		print '<input type="hidden" name="const['.$i.'][lang]" value="'.$obj->lang.'">';
-		print '<input type="hidden" name="const['.$i.'][name]" value="'.$obj->transkey.'">';
-		print '<input type="text" id="value_'.$i.'" class="flat inputforupdate" size="30" name="const['.$i.'][value]" value="'.dol_escape_htmltag($obj->transvalue).'">';
-		*/
-		if ($action != 'edit' || GETPOST('rowid') != $obj->rowid) print $obj->value;
-		else print '<input type="text" name="value" value="'.dol_escape_htmltag($obj->value).'">';
-		print '</td>';
-
+		if ($mode != 'focus')
+		{
+    		print '<td>';
+    		/*print '<input type="hidden" name="const['.$i.'][rowid]" value="'.$obj->rowid.'">';
+    		print '<input type="hidden" name="const['.$i.'][lang]" value="'.$obj->lang.'">';
+    		print '<input type="hidden" name="const['.$i.'][name]" value="'.$obj->transkey.'">';
+    		print '<input type="text" id="value_'.$i.'" class="flat inputforupdate" size="30" name="const['.$i.'][value]" value="'.dol_escape_htmltag($obj->transvalue).'">';
+    		*/
+    		if ($action != 'edit' || GETPOST('rowid') != $obj->rowid) print $obj->value;
+    		else print '<input type="text" name="value" value="'.dol_escape_htmltag($obj->value).'">';
+    		print '</td>';
+		}
+		
+		// Actions
 		print '<td align="center">';
 		if ($action != 'edit' || GETPOST('rowid') != $obj->rowid)
 		{
@@ -349,7 +394,7 @@ if ($result)
 		    print '<input type="submit" class="button" name="actioncancel" value="'.$langs->trans("Cancel").'">';
 		}
 		print '</td>';
-		
+        
 		print "</tr>\n";
 		print "\n";
 		$i++;

+ 14 - 12
htdocs/admin/dict.php

@@ -918,10 +918,19 @@ if (empty($id))
 print "<br>\n";
 
 
+$param = '&id='.$id;
+if ($search_country_id > 0) $param.= '&search_country_id='.$search_country_id;
+if ($search_code != '')     $param.= '&search_code='.urlencode($search_country_id);
+$paramwithsearch = $param;
+if ($sortorder) $paramwithsearch.= '&sortorder='.$sortorder;
+if ($sortfield) $paramwithsearch.= '&sortfield='.$sortfield;
+if (GETPOST('from')) $paramwithsearch.= '&from='.GETPOST('from','alpha');
+
+
 // Confirmation de la suppression de la ligne
 if ($action == 'delete')
 {
-    print $form->formconfirm($_SERVER["PHP_SELF"].'?'.($page?'page='.$page.'&':'').'sortfield='.$sortfield.'&sortorder='.$sortorder.'&rowid='.$rowid.'&code='.urlencode($_GET["code"]).'&id='.$id, $langs->trans('DeleteLine'), $langs->trans('ConfirmDeleteLine'), 'confirm_delete','',0,1);
+    print $form->formconfirm($_SERVER["PHP_SELF"].'?'.($page?'page='.$page.'&':'').'rowid='.$rowid.'&code='.urlencode($_GET["code"]).$paramwithsearch, $langs->trans('DeleteLine'), $langs->trans('ConfirmDeleteLine'), 'confirm_delete','',0,1);
 }
 //var_dump($elementList);
 
@@ -1073,7 +1082,7 @@ if ($id)
         print '</tr>';
 
         // Line to enter new values
-        print '<tr class="oddeven nodrag nodrop nohover">';
+        print '<!-- line to add new entry --><tr class="oddeven nodrag nodrop nohover">';
 
         $obj = new stdClass();
         // If data was already input, we define them in obj to populate input fields.
@@ -1134,14 +1143,6 @@ if ($id)
         $num = $db->num_rows($resql);
         $i = 0;
 
-        $param = '&id='.$id;
-        if ($search_country_id > 0) $param.= '&search_country_id='.$search_country_id;
-        if ($search_code != '')     $param.= '&search_code='.urlencode($search_country_id);
-        $paramwithsearch = $param;
-        if ($sortorder) $paramwithsearch.= '&sortorder='.$sortorder;
-        if ($sortfield) $paramwithsearch.= '&sortfield='.$sortfield;
-        if (GETPOST('from')) $paramwithsearch.= '&from='.GETPOST('from','alpha');
-        
         // There is several pages
         if ($num > $listlimit)
         {
@@ -1814,13 +1815,14 @@ function fieldList($fieldlist, $obj='', $tabname='', $context='')
 			if ($fieldlist[$field]=='affect') $class='maxwidth50';
 			if ($fieldlist[$field]=='delay') $class='maxwidth50';
 			if ($fieldlist[$field]=='position') $class='maxwidth50';
-			if ($fieldlist[$field]=='libelle') $class='quatrevingtpercent';
+			if ($fieldlist[$field]=='libelle' || $fieldlist[$field]=='label') $class='quatrevingtpercent';
 			if ($fieldlist[$field]=='tracking') $class='quatrevingtpercent';
 			if ($fieldlist[$field]=='sortorder' || $fieldlist[$field]=='sens' || $fieldlist[$field]=='category_type') $class='maxwidth50';
 			print '<td class="'.$classtd.'">';
 			$transfound=0;
 			if (in_array($fieldlist[$field], array('label','libelle')))
 			{
+			    $transkey='';
 			    // Special case for labels
 			    if ($tabname == MAIN_DB_PREFIX.'c_civility') {
 			        $transkey="Civility".strtoupper($obj->code);
@@ -1829,7 +1831,7 @@ function fieldList($fieldlist, $obj='', $tabname='', $context='')
 			        $langs->load("bills");
 			        $transkey="PaymentCondition".strtoupper($obj->code);
 			    }
-			    if ($langs->trans($transkey) != $transkey)
+			    if ($transkey && $langs->trans($transkey) != $transkey)
 			    {
 			        $transfound=1;
 			        print $form->textwithpicto($langs->trans($transkey), $langs->trans("GoIntoTranslationMenuToChangeThis"));

+ 1 - 1
htdocs/admin/events.php

@@ -105,7 +105,7 @@ foreach ($eventstolog as $key => $arr)
 		print '<td>';
 		$key='MAIN_LOGEVENTS_'.$arr['id'];
 		$value=$conf->global->$key;
-		print '<input '.$bc[$var].' type="checkbox" name="'.$key.'" value="1"'.($value?' checked':'').'>';
+		print '<input class="oddeven" type="checkbox" name="'.$key.'" value="1"'.($value?' checked':'').'>';
 		print '</td></tr>'."\n";
 	}
 }

+ 1 - 1
htdocs/admin/expensereport.php

@@ -230,7 +230,7 @@ print load_fiche_titre($langs->trans("ExpenseReportsSetup"),$linkback,'title_set
 
 $head=expensereport_admin_prepare_head();
 
-dol_fiche_head($head, 'expensereport', $langs->trans("ExpenseReports"), 0, 'trip');
+dol_fiche_head($head, 'expensereport', $langs->trans("ExpenseReports"), -1, 'trip');
 
 // Interventions numbering model
 /*

+ 1 - 1
htdocs/admin/expensereport_extrafields.php

@@ -74,7 +74,7 @@ print load_fiche_titre($langs->trans("ExpenseReportsSetup"),$linkback,'title_set
 
 $head = expensereport_admin_prepare_head();
 
-dol_fiche_head($head, 'attributes', $langs->trans("ExpenseReports"), 0, 'trip');
+dol_fiche_head($head, 'attributes', $langs->trans("ExpenseReports"), -1, 'trip');
 
 require DOL_DOCUMENT_ROOT.'/core/tpl/admin_extrafields_view.tpl.php';
 

+ 3 - 8
htdocs/admin/fichinter.php

@@ -6,7 +6,7 @@
  * Copyright (C) 2005-2014 Regis Houssin                <regis.houssin@capnetworks.com>
  * Copyright (C) 2008      Raphael Bertrand (Resultic)  <raphael.bertrand@resultic.fr>
  * Copyright (C) 2011-2013 Juanjo Menent			    <jmenent@2byte.es>
- * Copyright (C) 2011-2015 Philippe Grand			    <philippe.grand@atoo-net.com>
+ * Copyright (C) 2011-2017 Philippe Grand			    <philippe.grand@atoo-net.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -265,7 +265,7 @@ print load_fiche_titre($langs->trans("InterventionsSetup"),$linkback,'title_setu
 
 $head=fichinter_admin_prepare_head();
 
-dol_fiche_head($head, 'ficheinter', $langs->trans("Interventions"), 0, 'intervention');
+dol_fiche_head($head, 'ficheinter', $langs->trans("Interventions"), -1, 'intervention');
 
 // Interventions numbering model
 
@@ -291,7 +291,6 @@ foreach ($dirmodels as $reldir)
 		$handle = opendir($dir);
 		if (is_resource($handle))
 		{
-			$var=true;
 
 			while (($file = readdir($handle))!==false)
 			{
@@ -410,7 +409,6 @@ print "</tr>\n";
 
 clearstatcache();
 
-$var=true;
 foreach ($dirmodels as $reldir)
 {
 	$dir = dol_buildpath($reldir."core/modules/fichinter/doc/");
@@ -532,7 +530,6 @@ print '<td>'.$langs->trans("Parameter").'</td>';
 print '<td align="center" width="60">'.$langs->trans("Value").'</td>';
 print "<td>&nbsp;</td>\n";
 print "</tr>\n";
-$var=true;
 
 $substitutionarray=pdf_getSubstitutionArray($langs);
 $substitutionarray['__(AnyTranslationKey)__']=$langs->trans("Translation");
@@ -540,7 +537,6 @@ $htmltext = '<i>'.$langs->trans("AvailableVariables").':<br>';
 foreach($substitutionarray as $key => $val)	$htmltext.=$key.'<br>';
 $htmltext.='</i>';
 
-$var=! $var;
 print '<form action="'.$_SERVER["PHP_SELF"].'" method="post">';
 print '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
 print '<input type="hidden" name="action" value="set_FICHINTER_FREE_TEXT">';
@@ -590,11 +586,10 @@ print '</td><td align="right">';
 print '<input type="submit" class="button" value="'.$langs->trans("Modify").'">';
 print "</td></tr>\n";
 // Use services duration
-$var = !$var;
 print '<form action="' . $_SERVER["PHP_SELF"] . '" method="post">';
 print '<input type="hidden" name="token" value="' . $_SESSION['newtoken'] . '">';
 print '<input type="hidden" name="action" value="set_FICHINTER_USE_SERVICE_DURATION">';
-print '<tr ' . $bc[$var] . '>';
+print '<tr class="oddeven">';
 print '<td>';
 print $langs->trans("UseServicesDurationOnFichinter");
 print '</td>';

+ 0 - 44
htdocs/admin/ihm.php

@@ -50,18 +50,6 @@ $action = GETPOST('action');
 
 if (! defined("MAIN_MOTD")) define("MAIN_MOTD","");
 
-// List of supported permanent search area
-$searchform=array();
-/* deprecated
-if (empty($conf->use_javascript_ajax))
-{
-    $searchform=array("MAIN_SEARCHFORM_SOCIETE", "MAIN_SEARCHFORM_CONTACT", "MAIN_SEARCHFORM_PRODUITSERVICE", "MAIN_SEARCHFORM_ADHERENT", "MAIN_SEARCHFORM_PROJECT", "MAIN_SEARCHFORM_EMPLOYEE");
-    $searchformconst=array($conf->global->MAIN_SEARCHFORM_SOCIETE,$conf->global->MAIN_SEARCHFORM_CONTACT,$conf->global->MAIN_SEARCHFORM_PRODUITSERVICE,$conf->global->MAIN_SEARCHFORM_ADHERENT,$conf->global->MAIN_SEARCHFORM_PROJECT,$conf->global->MAIN_SEARCHFORM_EMPLOYEE);
-    $searchformtitle=array($langs->trans("Companies"), $langs->trans("Contacts"), $langs->trans("ProductsAndServices"), $langs->trans("Members"), $langs->trans("Projects"), $langs->trans("Users"));
-    $searchformmodule=array('Module1Name','Module1Name','Module50Name','Module310Name','Module400Name');
-}
-*/
-
 
 /*
  * Action
@@ -275,21 +263,6 @@ if ($action == 'edit')	// Edit
     show_theme(null,1);
     print '<br>';
 
-    // List of permanent supported search box
-    if (! empty($searchform))
-    {
-        print '<table summary="search" class="noborder" width="100%">';
-        print '<tr class="liste_titre"><td class="titlefield">'.$langs->trans("PermanentLeftSearchForm").'</td><td colspan="2">'.$langs->trans("Activated").'</td></tr>';
-        foreach ($searchform as $key => $value)
-        {
-            print '<tr><td class="titlefield">'.$searchformtitle[$key].'</td><td colspan="2">';
-            print $form->selectyesno($searchform[$key],$searchformconst[$key],1);
-            print '</td></tr>';
-        }
-        print '</table>';
-        print '<br>';
-    }
-    
     // Other
     print '<table summary="edit" class="noborder" width="100%">';
     print '<tr class="liste_titre"><td class="titlefield">'.$langs->trans("Parameters").'</td><td>'.$langs->trans("Value").'</td>';
@@ -476,23 +449,6 @@ else	// Show
     print '<br>';
 
 
-    // List of search forms to show
-    if (! empty($searchform))
-    {
-        print '<table class="noborder" width="100%">';
-        print '<tr class="liste_titre"><td class="titlefield">'.$langs->trans("PermanentLeftSearchForm").'</td><td>'.$langs->trans("Activated").'</td><td>&nbsp;</td></tr>';
-        foreach ($searchform as $key => $value)
-        {
-            
-            print '<tr class="oddeven"><td class="titlefield">'.$searchformtitle[$key].'</td><td>'.yn($searchformconst[$key]).'</td>';
-    		print '<td align="left">';
-    		if (! empty($searchformmodule[$key])) print $langs->trans("IfModuleEnabled",$langs->transnoentitiesnoconv($searchformmodule[$key]));
-            print '</td></tr>';
-        }
-        print '</table>';
-        print '<br>';
-    }
-
     // Other
     print '<table class="noborder" width="100%">';
     print '<tr class="liste_titre"><td class="titlefield">'.$langs->trans("Parameters").'</td><td colspan="2">'.$langs->trans("Value").'</td></tr>';

+ 1 - 3
htdocs/admin/loan.php

@@ -96,9 +96,7 @@ print "</tr>\n";
 
 foreach ($list as $key)
 {
-	
-
-	print '<tr '.$bc[$var].' class="value">';
+	print '<tr class="oddeven value">';
 
 	// Param
 	$label = $langs->trans($key); 

+ 19 - 12
htdocs/admin/mails_templates.php

@@ -4,7 +4,7 @@
  * Copyright (C) 2004       Benoit Mortier          <benoit.mortier@opensides.be>
  * Copyright (C) 2005-2012  Regis Houssin           <regis.houssin@capnetworks.com>
  * Copyright (C) 2010-2016  Juanjo Menent           <jmenent@2byte.es>
- * Copyright (C) 2011-2015  Philippe Grand          <philippe.grand@atoo-net.com>
+ * Copyright (C) 2011-2017  Philippe Grand          <philippe.grand@atoo-net.com>
  * Copyright (C) 2011       Remy Younes             <ryounes@gmail.com>
  * Copyright (C) 2012-2015  Marcos García           <marcosgdf@gmail.com>
  * Copyright (C) 2012       Christophe Battarel     <christophe.battarel@ltairis.fr>
@@ -118,17 +118,17 @@ require_once DOL_DOCUMENT_ROOT.'/core/class/html.formmail.class.php';
 $formmail=new FormMail($db);
 if (empty($conf->global->MAIN_EMAIL_TEMPLATES_FOR_OBJECT_LINES))
 {
-    $tmp=$formmail->getAvailableSubstitKey('form');
+    $tmp=FormMail::getAvailableSubstitKey('formemail');
     $tmp['__(AnyTransKey)__']='__(AnyTransKey)__';
     $helpsubstit = $langs->trans("AvailableVariables").':<br>'.implode('<br>', $tmp);
     $helpsubstitforlines = $langs->trans("AvailableVariables").':<br>'.implode('<br>', $tmp);
 }
 else
 {
-    $tmp=$formmail->getAvailableSubstitKey('formwithlines');
+    $tmp=FormMail::getAvailableSubstitKey('formemailwithlines');
     $tmp['__(AnyTransKey)__']='__(AnyTransKey)__';
     $helpsubstit = $langs->trans("AvailableVariables").':<br>'.implode('<br>', $tmp);
-    $tmp=$formmail->getAvailableSubstitKey('formforlines');
+    $tmp=FormMail::getAvailableSubstitKey('formemailforlines');
     $helpsubstitforlines = $langs->trans("AvailableVariables").':<br>'.implode('<br>', $tmp);
 }
 
@@ -484,7 +484,11 @@ if ($action != 'edit')
         {
             print '<td align="'.$align.'">';
         	if (! empty($tabhelp[$id][$value]) && preg_match('/^http(s*):/i',$tabhelp[$id][$value])) print '<a href="'.$tabhelp[$id][$value].'" target="_blank">'.$valuetoshow.' '.img_help(1,$valuetoshow).'</a>';
-        	else if (! empty($tabhelp[$id][$value])) print $form->textwithpicto($valuetoshow,$tabhelp[$id][$value]);
+        	else if (! empty($tabhelp[$id][$value])) 
+        	{
+        	    if (in_array($value, array('topic'))) print $form->textwithpicto($valuetoshow, $tabhelp[$id][$value], 1, 'help', '', 0, 2, $value);   // Tooltip on click
+        	    else print $form->textwithpicto($valuetoshow, $tabhelp[$id][$value], 1, 'help', '', 0, 2);                             // Tooltip on hover
+        	}
         	else print $valuetoshow;
             print '</td>';
          }
@@ -539,8 +543,8 @@ if ($action != 'edit')
     foreach ($fieldsforcontent as $tmpfieldlist)
     {
         print '<tr class="impair nodrag nodrop nohover"><td colspan="5">';
-        if ($tmpfieldlist == 'content') print '<strong>'.$form->textwithpicto($langs->trans("Content"),$tabhelp[$id][$tmpfieldlist]).'</strong><br>';
-        if ($tmpfieldlist == 'content_lines') print '<strong>'.$form->textwithpicto($langs->trans("ContentForLines"),$tabhelp[$id][$tmpfieldlist]).'</strong><br>';
+        if ($tmpfieldlist == 'content') print '<strong>'.$form->textwithpicto($langs->trans("Content"), $tabhelp[$id][$tmpfieldlist], 1, 'help', '', 0, 2, $tmpfieldlist).'</strong><br>';
+        if ($tmpfieldlist == 'content_lines') print '<strong>'.$form->textwithpicto($langs->trans("ContentForLines"), $tabhelp[$id][$tmpfieldlist], 1, 'help', '', 0, 2, $tmpfieldlist).'</strong><br>';
     
         if ($context != 'hide')
         {
@@ -624,7 +628,11 @@ if ($resql)
         // Affiche nom du champ
         if ($showfield)
         {
-            if (! empty($tabhelp[$id][$value])) $valuetoshow = $form->textwithpicto($valuetoshow,$tabhelp[$id][$value]);
+            if (! empty($tabhelp[$id][$value])) 
+            {
+                if (in_array($value, array('topic'))) $valuetoshow = $form->textwithpicto($valuetoshow, $tabhelp[$id][$value], 1, 'help', '', 0, 2);   // Tooltip on hover
+                else $valuetoshow = $form->textwithpicto($valuetoshow, $tabhelp[$id][$value], 1, 'help', '', 0, 2);                             // Tooltip on hover
+            }
             print getTitleFieldOfList($valuetoshow, 0, $_SERVER["PHP_SELF"], ($sortable?$fieldlist[$field]:''), ($page?'page='.$page.'&':''), $param, "align=".$align, $sortfield, $sortorder);
         }
     }
@@ -651,11 +659,10 @@ if ($resql)
         // Lines with values
         while ($i < $num)
         {
-            $var = ! $var;
 
             $obj = $db->fetch_object($resql);
             //print_r($obj);
-            print '<tr '.$bc[$var].' id="rowid-'.$obj->rowid.'">';
+            print '<tr class="oddeven" id="rowid-'.$obj->rowid.'">';
             if ($action == 'edit' && ($rowid == (! empty($obj->rowid)?$obj->rowid:$obj->code)))
             {
                 $tmpaction='edit';
@@ -689,7 +696,7 @@ if ($resql)
                     // Show value for field
                     if ($showfield) {
                 
-                        print '</tr><tr '.$bc[$var].' nohover tr-'.$tmpfieldlist.'-'.$rowid.' "><td colspan="5">'; // To create an artificial CR for the current tr we are on
+                        print '</tr><tr class="oddeven" nohover tr-'.$tmpfieldlist.'-'.$rowid.' "><td colspan="5">'; // To create an artificial CR for the current tr we are on
                         $okforextended = true;
                         if (empty($conf->global->FCKEDITOR_ENABLE_MAIL))
                             $okforextended = false;
@@ -781,7 +788,7 @@ if ($resql)
                     // Show value for field
                     if ($showfield) {
                         
-                        print '</tr><tr '.$bc[$var].' nohover tr-'.$tmpfieldlist.'-'.$i.' "><td colspan="5">'; // To create an artificial CR for the current tr we are on
+                        print '</tr><tr class="oddeven" nohover tr-'.$tmpfieldlist.'-'.$i.' "><td colspan="5">'; // To create an artificial CR for the current tr we are on
                         $okforextended = true;
                         if (empty($conf->global->FCKEDITOR_ENABLE_MAIL))
                             $okforextended = false;

+ 18 - 0
htdocs/admin/modulehelp.php

@@ -330,6 +330,24 @@ if ($mode == 'desc')
     else $text.=$langs->trans("Disabled");
     $text.='<br>';
 
+    $tmp = $objMod->getLastActivationInfo();
+    $authorid = $tmp['authorid'];
+    if ($authorid > 0)
+    {
+        $tmpuser = new User($db);
+        $tmpuser->fetch($authorid);
+        $text.='<strong>'.$langs->trans("LastActivationAuthor").':</strong> ';
+        $text.= $tmpuser->getNomUrl(1);
+        $text.='<br>';
+    }
+    $ip = $tmp['ip'];
+    if ($ip)
+    {
+        $text.='<strong>'.$langs->trans("LastActivationIP").':</strong> ';
+        $text.= $ip;
+        $text.='<br>';
+    }    
+    
     $moduledesclong=$objMod->getDescLong();
     if ($moduledesclong) $text.='<br><hr><div class="moduledesclong">'.$moduledesclong.'<div>';
 }

+ 17 - 15
htdocs/admin/modules.php

@@ -402,9 +402,9 @@ if ($nbofactivatedmodules <= 1) $moreinfo .= ' '.img_warning($langs->trans("YouM
 print load_fiche_titre($langs->trans("ModulesSetup"),$moreinfo,'title_setup');
 
 // Start to show page
-if ($mode=='common')      print $langs->trans("ModulesDesc")."<br>\n";
-if ($mode=='marketplace') print $langs->trans("ModulesMarketPlaceDesc")."<br>\n";
-if ($mode=='deploy')      print $langs->trans("ModulesDeployDesc", $langs->transnoentitiesnoconv("AvailableModules"))."<br>\n";
+if ($mode=='common')      print '<span class="opacitymedium">'.$langs->trans("ModulesDesc")."</span><br>\n";
+if ($mode=='marketplace') print '<span class="opacitymedium">'.$langs->trans("ModulesMarketPlaceDesc")."</span><br>\n";
+if ($mode=='deploy')      print '<span class="opacitymedium">'.$langs->trans("ModulesDeployDesc", $langs->transnoentitiesnoconv("AvailableModules"))."</span><br>\n";
 
 
 $h = 0;
@@ -428,8 +428,6 @@ $h++;
 print "<br>\n";
 
 
-$var=true;
-
 if ($mode == 'common')
 {
     
@@ -642,7 +640,8 @@ if ($mode == 'common')
         {
         	$disableSetup = 0;
 
-        	print '<td class="center valignmiddle" width="80px">';
+        	// Link enable/disabme
+        	print '<td class="center valignmiddle" width="60px">';
         	if (! empty($arrayofwarnings[$modName]))
 	        {
                 print '<!-- This module has a warning to show when we activate it (note: your country is '.$mysoc->country_code.') -->'."\n";
@@ -664,12 +663,12 @@ if ($mode == 'common')
         	}
         	print '</td>'."\n";
 
-        	// Config link
+        	// Link config
         	if (! empty($objMod->config_page_url) && !$disableSetup)
         	{
         		if (is_array($objMod->config_page_url))
         		{
-        			print '<td class="tdsetuppicto right" width="40px"">';
+        			print '<td class="tdsetuppicto right" width="60px">';
         			$i=0;
         			foreach ($objMod->config_page_url as $page)
         			{
@@ -695,22 +694,23 @@ if ($mode == 'common')
         		}
         		else if (preg_match('/^([^@]+)@([^@]+)$/i',$objMod->config_page_url,$regs))
         		{
-        			print '<td class="tdsetuppicto right valignmiddle" width="80px"><a href="'.dol_buildpath('/'.$regs[2].'/admin/'.$regs[1],1).'" title="'.$langs->trans("Setup").'">'.img_picto($langs->trans("Setup"),"setup",'style="padding-right: 6px"').'</a></td>';
+        			print '<td class="tdsetuppicto right valignmiddle" width="60px"><a href="'.dol_buildpath('/'.$regs[2].'/admin/'.$regs[1],1).'" title="'.$langs->trans("Setup").'">'.img_picto($langs->trans("Setup"),"setup",'style="padding-right: 6px"').'</a></td>';
         		}
         		else
         		{
-        			print '<td class="tdsetuppicto right valignmiddle" width="80px"><a href="'.$objMod->config_page_url.'" title="'.$langs->trans("Setup").'">'.img_picto($langs->trans("Setup"),"setup",'style="padding-right: 6px"').'</a></td>';
+        			print '<td class="tdsetuppicto right valignmiddle" width="60px"><a href="'.$objMod->config_page_url.'" title="'.$langs->trans("Setup").'">'.img_picto($langs->trans("Setup"),"setup",'style="padding-right: 6px"').'</a></td>';
         		}
         	}
         	else
         	{
-        		print '<td class="tdsetuppicto right valignmiddle" width="80px">'.img_picto($langs->trans("NothingToSetup"),"setup",'class="opacitytransp" style="padding-right: 6px"').'</td>';
+        		print '<td class="tdsetuppicto right valignmiddle" width="60px">'.img_picto($langs->trans("NothingToSetup"),"setup",'class="opacitytransp" style="padding-right: 6px"').'</td>';
         	}
 
         }
         else	// Module not yet activated
 		{
-        	print '<td class="center valignmiddle" width="80px">';
+		    // Link enable/disable
+        	print '<td class="center valignmiddle" width="60px">';
 		    if (! empty($objMod->always_enabled))
         	{
         		// Should never happened
@@ -756,7 +756,9 @@ if ($mode == 'common')
 	        	print "</a>\n";
         	}
         	print "</td>\n";
-        	print '<td class="tdsetuppicto right valignmiddle" width="80px">'.img_picto($langs->trans("NothingToSetup"),"setup",'class="opacitytransp" style="padding-right: 6px"').'</td>';
+        	
+        	// Link config
+        	print '<td class="tdsetuppicto right valignmiddle" width="60px">'.img_picto($langs->trans("NothingToSetup"),"setup",'class="opacitytransp" style="padding-right: 6px"').'</td>';
         }
 
         print "</tr>\n";
@@ -782,7 +784,7 @@ if ($mode == 'marketplace')
     print '</tr>';
 
     
-    print "<tr ".$bc[$var].">\n";
+    print "<tr class=\"oddeven\">\n";
     $url='https://www.dolistore.com';
     print '<td align="left"><a href="'.$url.'" target="_blank" rel="external"><img border="0" class="imgautosize imgmaxwidth180" src="'.DOL_URL_ROOT.'/theme/dolistore_logo.png"></a></td>';
     print '<td>'.$langs->trans("DoliStoreDesc").'</td>';
@@ -790,7 +792,7 @@ if ($mode == 'marketplace')
     print '</tr>';
 
     
-    print "<tr ".$bc[$var].">\n";
+    print "<tr class=\"oddeven\">\n";
     $url='https://partners.dolibarr.org';
     print '<td align="left"><a href="'.$url.'" target="_blank" rel="external"><img border="0" class="imgautosize imgmaxwidth180" src="'.DOL_URL_ROOT.'/theme/dolibarr_preferred_partner_int.png"></a></td>';
     print '<td>'.$langs->trans("DoliPartnersDesc").'</td>';

+ 4 - 9
htdocs/admin/oauth.php

@@ -93,7 +93,6 @@ print $langs->trans("ListOfSupportedOauthProviders").'<br><br>';
 
 print '<table class="noborder" width="100%">';
 
-$var = true;
 $i=0;
 
 foreach ($list as $key)
@@ -116,31 +115,27 @@ foreach ($list as $key)
     if ($supported)
     {
         $redirect_uri=$urlwithroot.'/core/modules/oauth/'.$supportedoauth2array[$key[0]].'_oauthcallback.php';
-        $var = !$var;
-        print '<tr '.$bc[$var].' class="value">';
+        print '<tr class="oddeven value">';
         print '<td>'.$langs->trans("UseTheFollowingUrlAsRedirectURI").'</td>';
         print '<td><input style="width: 80%" type"text" name="uri'.$key[0].'" value="'.$redirect_uri.'">';
         print '</td></tr>';
     }
     else
     {
-        $var = !$var;
-        print '<tr '.$bc[$var].' class="value">';
+        print '<tr class="oddeven value">';
         print '<td>'.$langs->trans("UseTheFollowingUrlAsRedirectURI").'</td>';
         print '<td>'.$langs->trans("FeatureNotYetSupported").'</td>';
         print '</td></tr>';
     }
         
     // Api Id
-    $var = !$var;
-    print '<tr '.$bc[$var].' class="value">';
+    print '<tr class="oddeven value">';
     print '<td><label for="'.$key[1].'">'.$langs->trans($key[1]).'</label></td>';
     print '<td><input type="text" size="100" id="'.$key[1].'" name="'.$key[1].'" value="'.$conf->global->{$key[1]}.'">';
     print '</td></tr>';
 
     // Api Secret
-    $var = !$var;
-    print '<tr '.$bc[$var].' class="value">';
+    print '<tr class="oddeven value">';
     print '<td><label for="'.$key[2].'">'.$langs->trans($key[2]).'</label></td>';
     print '<td><input type="password" size="100" id="'.$key[2].'" name="'.$key[2].'" value="'.$conf->global->{$key[2]}.'">';
     print '</td></tr>';

+ 47 - 7
htdocs/admin/pdf.php

@@ -42,15 +42,25 @@ $langs->load("members");
 if (! $user->admin) accessforbidden();
 
 $action = GETPOST('action','alpha');
+$cancel = GETPOST('cancel','alpha');
+
 
 /*
  * Actions
  */
 
+if ($cancel) {
+    $action='';
+}
+
 if ($action == 'update')
 {
 	dolibarr_set_const($db, "MAIN_PDF_FORMAT",    $_POST["MAIN_PDF_FORMAT"],'chaine',0,'',$conf->entity);
-
+	
+	dolibarr_set_const($db, "MAIN_PDF_MARGIN_LEFT",    $_POST["MAIN_PDF_MARGIN_LEFT"],'chaine',0,'',$conf->entity);
+	dolibarr_set_const($db, "MAIN_PDF_MARGIN_RIGHT",   $_POST["MAIN_PDF_MARGIN_RIGHT"],'chaine',0,'',$conf->entity);
+	dolibarr_set_const($db, "MAIN_PDF_MARGIN_TOP",     $_POST["MAIN_PDF_MARGIN_TOP"],'chaine',0,'',$conf->entity);
+	dolibarr_set_const($db, "MAIN_PDF_MARGIN_BOTTOM",  $_POST["MAIN_PDF_MARGIN_BOTTOM"],'chaine',0,'',$conf->entity);
 
     dolibarr_set_const($db, "MAIN_PROFID1_IN_ADDRESS",    $_POST["MAIN_PROFID1_IN_ADDRESS"],'chaine',0,'',$conf->entity);
 	dolibarr_set_const($db, "MAIN_PROFID2_IN_ADDRESS",    $_POST["MAIN_PROFID2_IN_ADDRESS"],'chaine',0,'',$conf->entity);
@@ -133,7 +143,20 @@ if ($action == 'edit')	// Edit
     print $formadmin->select_paper_format($selected,'MAIN_PDF_FORMAT');
     print '</td></tr>';
 
-	print '</table>';
+    print '<tr class="oddeven"><td>'.$langs->trans("MAIN_PDF_MARGIN_LEFT").'</td><td>';
+    print '<input type="text" class="maxwidth50" name="MAIN_PDF_MARGIN_LEFT" value="'.(empty($conf->global->MAIN_PDF_MARGIN_LEFT)?10:$conf->global->MAIN_PDF_MARGIN_LEFT).'">';
+    print '</td></tr>';
+    print '<tr class="oddeven"><td>'.$langs->trans("MAIN_PDF_MARGIN_RIGHT").'</td><td>';
+    print '<input type="text" class="maxwidth50" name="MAIN_PDF_MARGIN_RIGHT" value="'.(empty($conf->global->MAIN_PDF_MARGIN_RIGHT)?10:$conf->global->MAIN_PDF_MARGIN_RIGHT).'">';
+    print '</td></tr>';
+    print '<tr class="oddeven"><td>'.$langs->trans("MAIN_PDF_MARGIN_TOP").'</td><td>';
+    print '<input type="text" class="maxwidth50" name="MAIN_PDF_MARGIN_TOP" value="'.(empty($conf->global->MAIN_PDF_MARGIN_TOP)?10:$conf->global->MAIN_PDF_MARGIN_TOP).'">';
+    print '</td></tr>';
+    print '<tr class="oddeven"><td>'.$langs->trans("MAIN_PDF_MARGIN_BOTTOM").'</td><td>';
+    print '<input type="text" class="maxwidth50" name="MAIN_PDF_MARGIN_BOTTOM" value="'.(empty($conf->global->MAIN_PDF_MARGIN_BOTTOM)?10:$conf->global->MAIN_PDF_MARGIN_BOTTOM).'">';
+    print '</td></tr>';
+    
+    print '</table>';
 
 	print '<br>';
 
@@ -270,7 +293,9 @@ if ($action == 'edit')	// Edit
 	print '</table>';
 
     print '<br><div class="center">';
-    print '<input class="button" type="submit" value="'.$langs->trans("Save").'">';
+    print '<input class="button" type="submit" name="save" value="'.$langs->trans("Save").'">';
+    print ' &nbsp; ';
+    print '<input class="button" type="submit" name="cancel" value="'.$langs->trans("Cancel").'">';
     print '</div>';
 
     print '</form>';
@@ -281,8 +306,9 @@ else	// Show
     $var=true;
 
     // Misc options
-    print load_fiche_titre($langs->trans("DictionaryPaperFormat"),'','').'<br>';
-	$var=true;
+    print load_fiche_titre($langs->trans("DictionaryPaperFormat"),'','');
+	
+    
     print '<table summary="more" class="noborder" width="100%">';
     print '<tr class="liste_titre"><td>'.$langs->trans("Parameter").'</td><td width="200px">'.$langs->trans("Value").'</td></tr>';
 
@@ -314,11 +340,25 @@ else	// Show
     print $pdfformatlabel;
     print '</td></tr>';
 
+    print '<tr class="oddeven"><td>'.$langs->trans("MAIN_PDF_MARGIN_LEFT").'</td><td>';
+    print empty($conf->global->MAIN_PDF_MARGIN_LEFT)?10:$conf->global->MAIN_PDF_MARGIN_LEFT;
+    print '</td></tr>';
+    print '<tr class="oddeven"><td>'.$langs->trans("MAIN_PDF_MARGIN_RIGHT").'</td><td>';
+    print empty($conf->global->MAIN_PDF_MARGIN_RIGHT)?10:$conf->global->MAIN_PDF_MARGIN_RIGHT;
+    print '</td></tr>';
+    print '<tr class="oddeven"><td>'.$langs->trans("MAIN_PDF_MARGIN_TOP").'</td><td>';
+    print empty($conf->global->MAIN_PDF_MARGIN_TOP)?10:$conf->global->MAIN_PDF_MARGIN_TOP;
+    print '</td></tr>';
+    print '<tr class="oddeven"><td>'.$langs->trans("MAIN_PDF_MARGIN_BOTTOM").'</td><td>';
+    print empty($conf->global->MAIN_PDF_MARGIN_BOTTOM)?10:$conf->global->MAIN_PDF_MARGIN_BOTTOM;
+    print '</td></tr>';
+    
+    
 	print '</table>';
 
 	print '<br>';
 
-	print load_fiche_titre($langs->trans("PDFAddressForging"),'','').'<br>';
+	print load_fiche_titre($langs->trans("PDFAddressForging"),'','');
     print '<table class="noborder" width="100%">';
     print '<tr class="liste_titre"><td>'.$langs->trans("Parameter").'</td><td width="200px">'.$langs->trans("Value").'</td></tr>';
 
@@ -405,7 +445,7 @@ else	// Show
     print '<br>';
 
     // Other
-    print load_fiche_titre($langs->trans("Other"),'','').'<br>';
+    print load_fiche_titre($langs->trans("Other"),'','');
 	$var=true;
     print '<table summary="more" class="noborder" width="100%">';
     print '<tr class="liste_titre"><td>'.$langs->trans("Parameter").'</td><td width="200px" colspan="2">'.$langs->trans("Value").'</td></tr>';

+ 1 - 3
htdocs/admin/perms.php

@@ -140,7 +140,6 @@ if ($result)
 {
     $num	= $db->num_rows($result);
     $i		= 0;
-    $var	= True;
     $oldmod	= "";
 
     while ($i < $num)
@@ -187,8 +186,7 @@ if ($result)
         }
 
         
-        print '<tr '. $bc[$var].'>';
-
+        print '<tr class="oddeven">';
         print '<td>'.img_object('',$picto).' '.$objMod->getName();
         print '<a name="'.$objMod->getName().'">&nbsp;</a>';
 

+ 1 - 1
htdocs/admin/salaries.php

@@ -99,7 +99,7 @@ foreach ($list as $key)
 {
 	
 
-	print '<tr '.$bc[$var].' class="value">';
+	print '<tr class="oddeven value">';
 
 	// Param
 	$label = $langs->trans($key);

+ 57 - 0
htdocs/admin/stock.php

@@ -149,6 +149,7 @@ if (! empty($conf->productbatch->enabled))
 //if (! empty($conf->global->STOCK_CALCULATE_ON_VALIDATE_ORDER) || ! empty($conf->global->STOCK_CALCULATE_ON_SHIPMENT))
 //{
 print info_admin($langs->trans("IfYouUsePointOfSaleCheckModule"));
+print '<br>';
 //}
 
 // Title rule for stock decrease
@@ -432,6 +433,61 @@ if ($virtualdiffersfromphysical)
 }
 
 
+print '<br />';
+if ($conf->global->MAIN_FEATURES_LEVEL >= 2)
+{
+	$var=false;
+	print '<table class="noborder" width="100%">';
+	print '<tr class="liste_titre">';
+	print '<td>'.$langs->trans("Inventory").'</td>'."\n";
+	print '<td align="center" width="20">&nbsp;</td>';
+	print '<td align="center" width="100">&nbsp;</td>'."\n";
+	
+	// Example with a yes / no select
+	$var=!$var;
+	print '<tr '.$bc[$var].'>';
+	print '<td>'.$langs->trans("INVENTORY_DISABLE_VIRTUAL").'</td>';
+	print '<td align="center" width="20">&nbsp;</td>';
+	print '<td align="right" width="300">';
+	print '<form method="POST" action="'.$_SERVER['PHP_SELF'].'">';
+	print '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
+	print '<input type="hidden" name="action" value="set_INVENTORY_DISABLE_VIRTUAL">';
+	print $form->selectyesno("INVENTORY_DISABLE_VIRTUAL",$conf->global->INVENTORY_DISABLE_VIRTUAL,1);
+	print '<input type="submit" class="button" value="'.$langs->trans("Modify").'">';
+	print '</form>';
+	print '</td></tr>';
+	
+	// Example with a yes / no select
+	$var=!$var;
+	print '<tr '.$bc[$var].'>';
+	print '<td>'.$langs->trans("INVENTORY_USE_MIN_PA_IF_NO_LAST_PA").'</td>';
+	print '<td align="center" width="20">&nbsp;</td>';
+	print '<td align="right" width="300">';
+	print '<form method="POST" action="'.$_SERVER['PHP_SELF'].'">';
+	print '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
+	print '<input type="hidden" name="action" value="set_INVENTORY_USE_MIN_PA_IF_NO_LAST_PA">';
+	print $form->selectyesno("INVENTORY_USE_MIN_PA_IF_NO_LAST_PA",$conf->global->INVENTORY_USE_MIN_PA_IF_NO_LAST_PA,1);
+	print '<input type="submit" class="button" value="'.$langs->trans("Modify").'">';
+	print '</form>';
+	print '</td></tr>';
+	
+	// Example with a yes / no select
+	$var=!$var;
+	print '<tr '.$bc[$var].'>';
+	print '<td>'.$langs->trans("INVENTORY_USE_INVENTORY_DATE_FROM_DATEMVT").'</td>';
+	print '<td align="center" width="20">&nbsp;</td>';
+	print '<td align="right" width="300">';
+	print '<form method="POST" action="'.$_SERVER['PHP_SELF'].'">';
+	print '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
+	print '<input type="hidden" name="action" value="set_INVENTORY_USE_INVENTORY_DATE_FROM_DATEMVT">';
+	print $form->selectyesno("INVENTORY_USE_INVENTORY_DATE_FROM_DATEMVT",$conf->global->INVENTORY_USE_INVENTORY_DATE_FROM_DATEMVT,1);
+	print '<input type="submit" class="button" value="'.$langs->trans("Modify").'">';
+	print '</form>';
+	print '</td></tr>';
+	
+	print '</table>';
+}
+
 $var=true;
 print '<table class="noborder" width="100%">';
 
@@ -508,6 +564,7 @@ if ($conf->global->PRODUIT_SOUSPRODUITS)
 
 print '</table>';
 
+
 llxFooter();
 
 $db->close();

+ 3 - 4
htdocs/admin/supplier_invoice.php

@@ -5,7 +5,7 @@
  * Copyright (C) 2004      Sebastien Di Cintio     <sdicintio@ressource-toi.org>
  * Copyright (C) 2004      Benoit Mortier          <benoit.mortier@opensides.be>
  * Copyright (C) 2010-2013 Juanjo Menent           <jmenent@2byte.es>
- * Copyright (C) 2011-2015 Philippe Grand          <philippe.grand@atoo-net.com>
+ * Copyright (C) 2011-2017 Philippe Grand          <philippe.grand@atoo-net.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -205,7 +205,7 @@ print "<br>";
 
 $head = supplierorder_admin_prepare_head();
 
-dol_fiche_head($head, 'invoice', $langs->trans("Suppliers"), 0, 'company');
+dol_fiche_head($head, 'invoice', $langs->trans("Suppliers"), -1, 'company');
 
 
 // Supplier invoice numbering module
@@ -361,7 +361,6 @@ foreach ($dirmodels as $reldir)
 
     if (is_dir($dir))
     {
-        $var=true;
 
         $handle=opendir($dir);
 
@@ -379,7 +378,7 @@ foreach ($dirmodels as $reldir)
 	                $module = new $classname($db, new FactureFournisseur($db));
 
                     
-                    print "<tr ".$bc[$var].">\n";
+                    print "<tr class=\"oddeven\">\n";
                     print "<td>";
 	                print (empty($module->name)?$name:$module->name);
 	                print "</td>\n";

+ 3 - 4
htdocs/admin/supplier_order.php

@@ -5,7 +5,7 @@
  * Copyright (C) 2004      Sebastien Di Cintio     <sdicintio@ressource-toi.org>
  * Copyright (C) 2004      Benoit Mortier          <benoit.mortier@opensides.be>
  * Copyright (C) 2010-2013 Juanjo Menent           <jmenent@2byte.es>
- * Copyright (C) 2011-2015 Philippe Grand          <philippe.grand@atoo-net.com>
+ * Copyright (C) 2011-2017 Philippe Grand          <philippe.grand@atoo-net.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -234,7 +234,7 @@ print "<br>";
 
 $head = supplierorder_admin_prepare_head();
 
-dol_fiche_head($head, 'order', $langs->trans("Suppliers"), 0, 'company');
+dol_fiche_head($head, 'order', $langs->trans("Suppliers"), -1, 'company');
 
 
 // Supplier order numbering module
@@ -382,7 +382,6 @@ print '</tr>'."\n";
 
 clearstatcache();
 
-$var=true;
 foreach ($dirmodels as $reldir)
 {
 	$dir = dol_buildpath($reldir."core/modules/supplier_order/pdf/");
@@ -403,7 +402,7 @@ foreach ($dirmodels as $reldir)
 	                $module = new $classname($db, new CommandeFournisseur($db));
 
                     
-                    print "<tr ".$bc[$var].">\n";
+                    print "<tr class=\"oddeven\">\n";
                     print "<td>";
 	                print (empty($module->name)?$name:$module->name);
 	                print "</td>\n";

+ 12 - 15
htdocs/admin/supplier_payment.php

@@ -65,7 +65,7 @@ if ($action == 'updateMask')
     }
 }else  if ($action == 'setmod')
 {
-    dolibarr_set_const($db, "SUPPLIER_PAYMENT_ADDON",$value,'chaine',0,'',$conf->entity);
+    dolibarr_set_const($db, "SUPPLIER_PAYMENT_ADDON", $value, 'chaine', 0, '', $conf->entity);
 }
 
 // define constants for models generator that need parameters
@@ -138,7 +138,7 @@ else if ($action == 'specimen')
 	$dirmodels=array_merge(array('/'),(array) $conf->modules_parts['models']);
 	foreach($dirmodels as $reldir)
 	{
-	    $file=dol_buildpath($reldir."core/modules/supplier_payment/pdf/pdf_".$modele.".modules.php",0);
+	    $file=dol_buildpath($reldir."core/modules/supplier_payment/doc/pdf_".$modele.".modules.php",0);
     	if (file_exists($file))
     	{
     		$filefound=1;
@@ -188,7 +188,7 @@ print load_fiche_titre($langs->trans("SupplierPaymentSetup"),$linkback,'title_se
 print "<br>";
 
 $head = supplierorder_admin_prepare_head();
-dol_fiche_head($head, 'supplierpayment', $langs->trans("Suppliers"), 0, 'company');
+dol_fiche_head($head, 'supplierpayment', $langs->trans("Suppliers"), -1, 'company');
 
 /*
  *  Numbering module
@@ -198,12 +198,6 @@ if (empty($conf->global->SUPPLIER_PAYMENT_ADDON)) $conf->global->SUPPLIER_PAYMEN
     
 print load_fiche_titre($langs->trans("PaymentsNumberingModule"), '', '');
 
-/*
- *  Document templates generators
- */
-print '<br>';
-print load_fiche_titre($langs->trans("BillsPDFModules"),'','');
-
 // Load array def with activated templates
 $def = array();
 $sql = "SELECT nom";
@@ -349,6 +343,12 @@ foreach ($dirmodels as $reldir)
 print '</table>';
 
 
+/*
+ *  Document templates generators
+ */
+print '<br>';
+print load_fiche_titre($langs->trans("PaymentsPDFModules"),'','');
+
 print '<table class="noborder" width="100%">'."\n";
 print '<tr class="liste_titre">'."\n";
 print '<td width="100">'.$langs->trans("Name").'</td>'."\n";
@@ -363,11 +363,10 @@ clearstatcache();
 
 foreach ($dirmodels as $reldir)
 {
-	$dir = dol_buildpath($reldir."core/modules/supplier_payment/pdf/");
+	$dir = dol_buildpath($reldir."core/modules/supplier_payment/doc/");
 
     if (is_dir($dir))
     {
-        $var=true;
 
         $handle=opendir($dir);
 
@@ -385,7 +384,7 @@ foreach ($dirmodels as $reldir)
 	                $module = new $classname($db, new PaiementFourn($db));
 
                     
-                    print "<tr ".$bc[$var].">\n";
+                    print "<tr class=\"oddeven\">\n";
                     print "<td>";
 	                print (empty($module->name)?$name:$module->name);
 	                print "</td>\n";
@@ -441,8 +440,6 @@ foreach ($dirmodels as $reldir)
                     $htmltooltip.='<br>'.$langs->trans("Width").'/'.$langs->trans("Height").': '.$module->page_largeur.'/'.$module->page_hauteur;
                     $htmltooltip.='<br><br><u>'.$langs->trans("FeaturesSupported").':</u>';
                     $htmltooltip.='<br>'.$langs->trans("Logo").': '.yn($module->option_logo,1,1);
-                    $htmltooltip.='<br>'.$langs->trans("PaymentMode").': '.yn($module->option_modereg,1,1);
-                    $htmltooltip.='<br>'.$langs->trans("PaymentConditions").': '.yn($module->option_condreg,1,1);
                     print '<td align="center">';
                     print $form->textwithpicto('',$htmltooltip,1,0);
                     print '</td>';
@@ -459,7 +456,7 @@ foreach ($dirmodels as $reldir)
     }
 }
 
-print '</table><br>';
+print '</table>';
 
 dol_fiche_end();
 

+ 1 - 1
htdocs/admin/supplierinvoice_extrafields.php

@@ -79,7 +79,7 @@ print "<br>\n";
 
 $head = supplierorder_admin_prepare_head();
 
-dol_fiche_head($head, 'supplierinvoice', $langs->trans("Suppliers"), 0, 'company');
+dol_fiche_head($head, 'supplierinvoice', $langs->trans("Suppliers"), -1, 'company');
 
 require DOL_DOCUMENT_ROOT.'/core/tpl/admin_extrafields_view.tpl.php';
 

+ 1 - 1
htdocs/admin/supplierinvoicedet_extrafields.php

@@ -79,7 +79,7 @@ print "<br>\n";
 
 $head = supplierorder_admin_prepare_head();
 
-dol_fiche_head($head, 'supplierinvoicedet', $langs->trans("Suppliers"), 0, 'company');
+dol_fiche_head($head, 'supplierinvoicedet', $langs->trans("Suppliers"), -1, 'company');
 
 require DOL_DOCUMENT_ROOT.'/core/tpl/admin_extrafields_view.tpl.php';
 

+ 1 - 1
htdocs/admin/supplierorder_extrafields.php

@@ -75,7 +75,7 @@ print "<br>\n";
 
 $head = supplierorder_admin_prepare_head();
 
-dol_fiche_head($head, 'supplierorder', $langs->trans("Suppliers"), 0, 'company');
+dol_fiche_head($head, 'supplierorder', $langs->trans("Suppliers"), -1, 'company');
 
 require DOL_DOCUMENT_ROOT.'/core/tpl/admin_extrafields_view.tpl.php';
 

+ 1 - 1
htdocs/admin/supplierorderdet_extrafields.php

@@ -76,7 +76,7 @@ print "<br>\n";
 
 $head = supplierorder_admin_prepare_head();
 
-dol_fiche_head($head, 'supplierorderdet', $langs->trans("Suppliers"), 0, 'company');
+dol_fiche_head($head, 'supplierorderdet', $langs->trans("Suppliers"), -1, 'company');
 
 require DOL_DOCUMENT_ROOT.'/core/tpl/admin_extrafields_view.tpl.php';
 

+ 14 - 8
htdocs/admin/syslog.php

@@ -40,7 +40,7 @@ $action = GETPOST("action");
 $syslogModules = array();
 $activeModules = array();
 
-if (defined('SYSLOG_HANDLERS')) $activeModules = json_decode(constant('SYSLOG_HANDLERS'));
+if (! empty($conf->global->SYSLOG_HANDLERS)) $activeModules = json_decode($conf->global->SYSLOG_HANDLERS);
 
 $dirsyslogs = array_merge(array('/core/modules/syslog/'), $conf->modules_parts['syslog']);
 foreach ($dirsyslogs as $reldir) {
@@ -88,7 +88,8 @@ if ($action == 'set')
 
 	$newActiveModules = array();
 	$selectedModules = (isset($_POST['SYSLOG_HANDLERS']) ? $_POST['SYSLOG_HANDLERS'] : array());
-	//var_dump($selectedModules);
+	
+	// Save options of handler
 	foreach ($syslogModules as $syslogHandler)
 	{
 		if (in_array($syslogHandler, $syslogModules))
@@ -101,7 +102,7 @@ if ($action == 'set')
 				if (isset($_POST[$option['constant']]))
 				{
 					$_POST[$option['constant']] = trim($_POST[$option['constant']]);
-					dolibarr_del_const($db, $option['constant'], 0);
+					dolibarr_del_const($db, $option['constant'], -1);
 					dolibarr_set_const($db, $option['constant'], $_POST[$option['constant']], 'chaine',0, '', 0);
 				}
 			}
@@ -109,7 +110,9 @@ if ($action == 'set')
 	}
 
 	$activeModules = $newActiveModules;
-	dolibarr_set_const($db, 'SYSLOG_HANDLERS', json_encode($activeModules), 'chaine',0,'',0);
+
+    dolibarr_del_const($db, 'SYSLOG_HANDLERS', -1);  // To be sure ther is not a setup into another entity	
+    dolibarr_set_const($db, 'SYSLOG_HANDLERS', json_encode($activeModules), 'chaine',0,'',0);
 
 	// Check configuration
 	foreach ($activeModules as $modulename) {
@@ -194,7 +197,6 @@ print '<tr class="liste_titre">';
 print '<td>'.$langs->trans("Type").'</td><td>'.$langs->trans("Value").'</td>';
 print '<td align="right" colspan="2"><input type="submit" class="button" '.$option.' value="'.$langs->trans("Modify").'"></td>';
 print "</tr>\n";
-$var=true;
 
 foreach ($syslogModules as $moduleName)
 {
@@ -207,7 +209,7 @@ foreach ($syslogModules as $moduleName)
 	
 	print '<tr class="oddeven">';
 	print '<td width="140">';
-	print '<input '.$bc[$var].' type="checkbox" name="SYSLOG_HANDLERS[]" value="'.$moduleName.'" '.(in_array($moduleName, $activeModules) ? 'checked' : '').($moduleactive <= 0 ? 'disabled' : '').'> ';
+	print '<input class="oddeven" type="checkbox" name="SYSLOG_HANDLERS[]" value="'.$moduleName.'" '.(in_array($moduleName, $activeModules) ? 'checked' : '').($moduleactive <= 0 ? 'disabled' : '').'> ';
 	print $module->getName();
 	print '</td>';
 
@@ -217,8 +219,12 @@ foreach ($syslogModules as $moduleName)
 	{
 		foreach ($setuparray as $option)
 		{
-			if (isset($_POST[$option['constant']])) $value=$_POST[$option['constant']];
-			else if (defined($option['constant'])) $value = constant($option['constant']);
+		    $tmpoption=$option['constant'];
+		    if (! empty($tmpoption))
+		    {
+    			if (isset($_POST[$tmpoption])) $value=$_POST[$tmpoption];
+    			else if (! empty($conf->global->$tmpoption)) $value = $conf->global->$tmpoption;
+		    }
 			else $value = (isset($option['default']) ? $option['default'] : '');
 
 			print $option['name'].': <input type="text" class="flat" name="'.$option['constant'].'" value="'.$value.'"'.(isset($option['attr']) ? ' '.$option['attr'] : '').'>';

+ 5 - 5
htdocs/admin/taxes.php

@@ -136,10 +136,10 @@ else
     print '<tr class="liste_titre">';
     print '<td colspan="2">'.$langs->trans('OptionVatMode').'</td><td>'.$langs->trans('Description').'</td>';
     print "</tr>\n";
-    print '<tr '.$bc[false].'><td width="200"><input type="radio" name="tax_mode" value="0"'.($tax_mode != 1 ? ' checked' : '').'> '.$langs->trans('OptionVATDefault').'</td>';
+    print '<tr class="oddeven"><td width="200"><input type="radio" name="tax_mode" value="0"'.($tax_mode != 1 ? ' checked' : '').'> '.$langs->trans('OptionVATDefault').'</td>';
     print '<td colspan="2">'.nl2br($langs->trans('OptionVatDefaultDesc'));
     print "</td></tr>\n";
-    print '<tr '.$bc[true].'><td width="200"><input type="radio" name="tax_mode" value="1"'.($tax_mode == 1 ? ' checked' : '').'> '.$langs->trans('OptionVATDebitOption').'</td>';
+    print '<tr class="oddeven"><td width="200"><input type="radio" name="tax_mode" value="1"'.($tax_mode == 1 ? ' checked' : '').'> '.$langs->trans('OptionVATDebitOption').'</td>';
     print '<td colspan="2">'.nl2br($langs->trans('OptionVatDebitOptionDesc'))."</td></tr>\n";
 
     print "</table>\n";
@@ -152,7 +152,7 @@ else
     print '<tr class="liste_titre"><td>&nbsp;</td><td>'.$langs->trans("Buy").'</td><td>'.$langs->trans("Sell").'</td></tr>';
 
     // Products
-    print '<tr '.$bc[false].'><td>'.$langs->trans("Product").'</td>';
+    print '<tr class="oddeven"><td>'.$langs->trans("Product").'</td>';
     print '<td>';
     print $langs->trans("OnDelivery");
     print ' ('.$langs->trans("SupposedToBeInvoiceDate").')';
@@ -163,7 +163,7 @@ else
     print '</td></tr>';
 
     // Services
-    print '<tr '.$bc[true].'><td>'.$langs->trans("Services").'</td>';
+    print '<tr class="oddeven"><td>'.$langs->trans("Services").'</td>';
     print '<td>';
     if ($tax_mode == 0)
     {
@@ -206,7 +206,7 @@ foreach ($list as $key)
 {
 	
 
-	print '<tr '.$bc[$var].' class="value">';
+	print '<tr class="oddeven value">';
 
 	// Param
 	$label = $langs->trans($key); 

+ 2 - 2
htdocs/admin/user.php

@@ -167,7 +167,7 @@ print load_fiche_titre($langs->trans("UsersSetup"),$linkback,'title_setup');
 
 $head=user_admin_prepare_head();
 
-dol_fiche_head($head,'card', $langs->trans("MenuUsersAndGroups"), 0, 'user');
+dol_fiche_head($head,'card', $langs->trans("MenuUsersAndGroups"), -1, 'user');
 
 print '<table class="noborder" width="100%">';
 print '<tr class="liste_titre">';
@@ -205,7 +205,7 @@ print '</td></tr>';
 
 print '</table>';
 
-
+print '<br>';
 
 $dirmodels=array_merge(array('/'),(array) $conf->modules_parts['models']);
 

+ 1 - 1
htdocs/admin/usergroup.php

@@ -151,7 +151,7 @@ print load_fiche_titre($langs->trans("UsersSetup"),$linkback,'title_setup');
 
 $head=user_admin_prepare_head();
 
-dol_fiche_head($head,'usergroupcard', $langs->trans("MenuUsersAndGroups"), 0, 'user');
+dol_fiche_head($head,'usergroupcard', $langs->trans("MenuUsersAndGroups"), -1, 'user');
 
 
 $dirmodels=array_merge(array('/'),(array) $conf->modules_parts['models']);

+ 0 - 2
htdocs/admin/websites.php

@@ -441,7 +441,6 @@ if ($id)
     {
         $num = $db->num_rows($resql);
         $i = 0;
-        $var=true;
         if ($num)
         {
             print '<br>';
@@ -499,7 +498,6 @@ if ($id)
             // Lines with values
             while ($i < $num)
             {
-                $var = ! $var;
 
                 $obj = $db->fetch_object($resql);
                 //print_r($obj);

+ 1 - 2
htdocs/admin/workflow.php

@@ -120,8 +120,7 @@ foreach($workflowcodes as $key => $params)
 		$oldfamily = $family;
    	}
 
-   	$var = !$var;
-   	print "<tr ".$bc[$var].">\n";
+   	print "<tr class=\"oddeven\">\n";
    	print "<td>".img_object('', $picto).$langs->trans('desc'.$key);
    	if (! empty($params['warning']))
    	{

+ 2 - 0
htdocs/api/class/api.class.php

@@ -90,6 +90,8 @@ class DolibarrApi
         // Remove linkedObjects. We should already have linkedObjectIds that avoid huge responses
         unset($object->linkedObjects);
         
+        unset($object->fields);
+        
         unset($object->oldline);
         
         unset($object->error);

+ 1 - 1
htdocs/api/class/api_login.class.php

@@ -102,7 +102,7 @@ class Login
 			'success' => array(
 				'code' => 200,
 				'token' => $token,
-				'message' => 'Welcome ' . $login.($reset?' - Token is new':' - This is your token (generated by a previous call)')
+				'message' => 'Welcome ' . $login.($reset?' - Token is new':' - This is your token (generated by a previous call). You can use it to make any REST API call, or enter it into the DOLAPIKEY field to use the Dolibarr API explorer.')
 			)
 		);
 	}

+ 16 - 5
htdocs/bookmarks/bookmarks.lib.php

@@ -62,14 +62,15 @@ function printBookmarksList($aDb, $aLangs)
     */
 	$ret.= '<div class="menu_top"></div>'."\n";
 
-	$ret.= '<form id="actionbookmark" name="actionbookmark" method="POST" action="">';
+	$ret.= '<!-- form with POST method by default --><form id="actionbookmark" name="actionbookmark" method="POST" action="">';
 	$ret.= '<select name="bookmark" id="boxbookmark" class="flat boxcombo vmenusearchselectcombo">';
 	$ret.= '<option hidden value="listbookmarks" class="optiongrey" selected rel="'.DOL_URL_ROOT.'/bookmarks/list.php">'.$langs->trans('Bookmarks').'</option>';
-    $ret.= '<option value="listbookmark" class="optionblue" rel="'.dol_escape_js(DOL_URL_ROOT.'/bookmarks/list.php').'">'.dol_escape_htmltag($user->rights->bookmark->creer ? $langs->trans('EditBookmarks') : $langs->trans('ListOfBookmarks')).'...</option>';
+    $ret.= '<option value="listbookmark" class="optionblue" rel="'.dol_escape_htmltag(DOL_URL_ROOT.'/bookmarks/list.php').'">'.dol_escape_htmltag($user->rights->bookmark->creer ? $langs->trans('EditBookmarks') : $langs->trans('ListOfBookmarks')).'...</option>';
+	// Url to go on create new bookmark page
 	if ($user->rights->bookmark->creer)
 	{
     	$urltoadd=DOL_URL_ROOT.'/bookmarks/card.php?action=create&amp;urlsource='.urlencode($url).'&amp;url='.urlencode($url);
-    	$ret.= '<option value="newbookmark" class="optionblue" rel="'.dol_escape_js($urltoadd).'">'.dol_escape_htmltag($langs->trans('AddThisPageToBookmarks')).'...</option>';
+    	$ret.= '<option value="newbookmark" class="optionblue" rel="'.dol_escape_htmltag($urltoadd).'">'.dol_escape_htmltag($langs->trans('AddThisPageToBookmarks')).'...</option>';
 	}
 	// Menu with all bookmarks
 	if (! empty($conf->global->BOOKMARKS_SHOW_IN_MENU))
@@ -84,7 +85,7 @@ function printBookmarksList($aDb, $aLangs)
 			while ($i < $conf->global->BOOKMARKS_SHOW_IN_MENU && $obj = $db->fetch_object($resql))
 			{
 				//$ret.='<div class="menu_contenu">';
-			    $ret.='<option name="bookmark'.$obj->rowid.'" value="'.$obj->rowid.'" '.($obj->target == 1?' target="_blank"':'').' rel="'.dol_escape_js($obj->url).'">'.img_picto('','object_bookmark').' '.$obj->title.'</option>';
+			    $ret.='<option name="bookmark'.$obj->rowid.'" value="'.$obj->rowid.'" '.($obj->target == 1?' target="_blank"':'').' rel="'.dol_escape_htmltag($obj->url).'">'.img_picto('','object_bookmark').' '.$obj->title.'</option>';
 				/*$ret.='<a class="vsmenu" title="'.$obj->title.'" href="'.$obj->url.'"'.($obj->target == 1?' target="_blank"':'').'>';
 				if (empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) $ret.=' '.img_object('','bookmark').' ';
 				$ret.= dol_trunc($obj->title, 20).'</a><br>';*/
@@ -109,9 +110,19 @@ function printBookmarksList($aDb, $aLangs)
 	            var urlselected = jQuery("#boxbookmark option:selected").attr("rel");
 	            var urltarget = jQuery("#boxbookmark option:selected").attr("target");
 	            if (! urltarget) { urltarget=""; }
-	            console.log("We change select bookmark. We choose "+urlselected+" with target "+urltarget);
                 jQuery("form#actionbookmark").attr("target",urltarget);
 	            jQuery("form#actionbookmark").attr("action",urlselected);
+	    
+	            console.log("We change select bookmark. We choose urlselected="+urlselected+" with target="+urltarget);
+	            
+	            // Method is POST for internal link, GET for external
+	            if (urlselected.startsWith(\'http\'))
+	            {
+	                var newmethod=\'GET\';
+	                jQuery("form#actionbookmark").attr("method",newmethod);
+	                console.log("We change method to newmethod="+newmethod);
+	            }
+	    
 	            jQuery("#actionbookmark").submit();
 	       });';
 	$ret.='})</script>';

+ 4 - 4
htdocs/categories/index.php

@@ -125,7 +125,7 @@ if ($catname || $id > 0)
 		print '</span>';
 		print "</td>\n";
 		print "\t\t<td>";
-		print $cat->description;
+		print dolGetFirstLineOfText($cat->description);
 		print "</td>\n";
 		print "\t</tr>\n";
 	}
@@ -162,7 +162,7 @@ foreach($fulltree as $key => $val)
 	'rowid'=>$val['rowid'],
 	'fk_menu'=>$val['fk_parent'],
 	'entry'=>'<table class="nobordernopadding centpercent"><tr><td><span class="noborderoncategories" '.($categstatic->color?' style="background: #'.$categstatic->color.';"':' style="background: #aaa"').'>'.$li.'</span></td>'.
-	'<td width="50%">'.dolGetFirstLineOfText($desc).'</td>'.
+	//'<td width="50%">'.dolGetFirstLineOfText($desc).'</td>'.
 	'<td align="right" width="20px;"><a href="'.DOL_URL_ROOT.'/categories/viewcat.php?id='.$val['id'].'&type='.$type.'">'.img_view().'</a></td>'.
 	'</tr></table>'
 	);
@@ -181,13 +181,13 @@ $nbofentries=(count($data) - 1);
 
 if ($nbofentries > 0)
 {
-	print '<tr '.$bc[0].'><td colspan="3">';
+	print '<tr class="pair"><td colspan="3">';
 	tree_recur($data,$data[0],0);
 	print '</td></tr>';
 }
 else
 {
-	print '<tr '.$bc[0].'>';
+	print '<tr class="pair">';
 	print '<td colspan="3"><table class="nobordernopadding"><tr class="nobordernopadding"><td>'.img_picto_common('','treemenu/branchbottom.gif').'</td>';
 	print '<td valign="middle">';
 	print $langs->trans("NoCategoryYet");

+ 4 - 6
htdocs/comm/action/card.php

@@ -337,7 +337,7 @@ if ($action == 'add')
 				unset($_SESSION['assignedtouser']);
 
 				$moreparam='';
-				if ($user->id != $object->userownerid) $moreparam="usertodo=-1";	// We force to remove filter so created record is visible when going back to per user view.
+				if ($user->id != $object->userownerid) $moreparam="filtert=-1";	// We force to remove filter so created record is visible when going back to per user view.
 
 				$db->commit();
 				if (! empty($backtopage))
@@ -706,7 +706,7 @@ if ($action == 'create')
 		if (GETPOST('complete') == '0' || GETPOST("afaire") == 1) $percent='0';
 		else if (GETPOST('complete') == 100 || GETPOST("afaire") == 2) $percent=100;
 	}
-	$formactions->form_select_status_action('formaction',$percent,1,'complete');
+	$formactions->form_select_status_action('formaction', $percent, 1, 'complete', 0, 0, 'maxwidth200');
 	print '</td></tr>';
 
     // Location
@@ -1428,7 +1428,7 @@ if ($id > 0)
 				} else {
 					$value = $object->array_options["options_" . $key];
 				}
-				print '<tr><td width="30%">'.$label.'</td><td>';
+				print '<tr><td class="titlefield">'.$label.'</td><td>';
 				print $extrafields->showOutputField($key,$value);
 				print "</td></tr>\n";
 			}
@@ -1491,7 +1491,7 @@ if ($id > 0)
 	{
 		if (empty($conf->global->AGENDA_DISABLE_BUILDDOC))
 		{
-			print '<div style="clear:both;">&nbsp;<br><br></div><div class="fichecenter"><div class="fichehalfleft">';
+			print '<div style="clear:both;"></div><div class="fichecenter"><div class="fichehalfleft">';
             print '<a name="builddoc"></a>'; // ancre
 
             /*
@@ -1512,8 +1512,6 @@ if ($id > 0)
 
 
 			print '</div></div></div>';
-
-            print '<div style="clear:both;">&nbsp;</div>';
 	    }
 	}
 }

+ 2 - 17
htdocs/comm/action/index.php

@@ -43,8 +43,8 @@ if (! isset($conf->global->AGENDA_MAX_EVENTS_DAY_VIEW)) $conf->global->AGENDA_MA
 if (empty($conf->global->AGENDA_EXT_NB)) $conf->global->AGENDA_EXT_NB=5;
 $MAXAGENDA=$conf->global->AGENDA_EXT_NB;
 
-$filter=GETPOST("filter",'',3);
-$filtert = GETPOST("usertodo","int",3)?GETPOST("usertodo","int",3):GETPOST("filtert","int",3);
+$filter = GETPOST("filter",'',3);
+$filtert = GETPOST("filtert","int",3);
 $usergroup = GETPOST("usergroup","int",3);
 $showbirthday = empty($conf->use_javascript_ajax)?GETPOST("showbirthday","int"):1;
 
@@ -1155,21 +1155,6 @@ else    // View by day
     echo '</table>';
 }
 
-
-/* TODO Export
- print '
-<a href="" id="actionagenda_ical_link"><img src="'.DOL_URL_ROOT.'/theme/common/ical.gif" border="0"/></a>
-<a href="" id="actionagenda_vcal_link"><img src="'.DOL_URL_ROOT.'/theme/common/vcal.gif" border="0"/></a>
-<a href="" id="actionagenda_rss_link"><img src="'.DOL_URL_ROOT.'/theme/common/rss.gif"  border="0"/></a>
-
-<script>
-$("#actionagenda_rss_link").attr("href","/public/agenda/agendaexport.php?format=rss&type=ActionAgenda&exportkey=dolibarr&token="+getToken()+"&status="+getStatus()+"&userasked="+getUserasked()+"&usertodo="+getUsertodo()+"&userdone="+getUserdone()+"&year="+getYear()+"&month="+getMonth()+"&day="+getDay()+"&showbirthday="+getShowbirthday()+"&action="+getAction()+"&projectid="+getProjectid()+"");
-$("#actionagenda_ical_link").attr("href","/public/agenda/agendaexport.php?format=ical&type=ActionAgenda&exportkey=dolibarr&token="+getToken()+"&status="+getStatus()+"&userasked="+getUserasked()+"&usertodo="+getUsertodo()+"&userdone="+getUserdone()+"&year="+getYear()+"&month="+getMonth()+"&day="+getDay()+"&showbirthday="+getShowbirthday()+"&action="+getAction()+"&projectid="+getProjectid()+"");
-$("#actionagenda_vcal_link").attr("href","/public/agenda/agendaexport.php?format=vcal&type=ActionAgenda&exportkey=dolibarr&token="+getToken()+"&status="+getStatus()+"&userasked="+getUserasked()+"&usertodo="+getUsertodo()+"&userdone="+getUserdone()+"&year="+getYear()+"&month="+getMonth()+"&day="+getDay()+"&showbirthday="+getShowbirthday()+"&action="+getAction()+"&projectid="+getProjectid()+"");
-</script>
-';
-*/
-
 llxFooter();
 
 $db->close();

+ 2 - 2
htdocs/comm/action/listactions.php

@@ -64,8 +64,8 @@ $dateend=dol_mktime(0, 0, 0, GETPOST('dateendmonth'), GETPOST('dateendday'), GET
 if ($status == ''   && ! isset($_GET['status']) && ! isset($_POST['status'])) $status=(empty($conf->global->AGENDA_DEFAULT_FILTER_STATUS)?'':$conf->global->AGENDA_DEFAULT_FILTER_STATUS);
 if (empty($action) && ! isset($_GET['action']) && ! isset($_POST['action'])) $action=(empty($conf->global->AGENDA_DEFAULT_VIEW)?'show_month':$conf->global->AGENDA_DEFAULT_VIEW);
 
-$filter=GETPOST("filter",'',3);
-$filtert = GETPOST("usertodo","int",3)?GETPOST("usertodo","int",3):GETPOST("filtert","int",3);
+$filter = GETPOST("filter",'',3);
+$filtert = GETPOST("filtert","int",3);
 $usergroup = GETPOST("usergroup","int",3);
 $showbirthday = empty($conf->use_javascript_ajax)?GETPOST("showbirthday","int"):1;
 

+ 4 - 4
htdocs/comm/action/pertype.php

@@ -38,8 +38,8 @@ if (! empty($conf->projet->enabled)) require_once DOL_DOCUMENT_ROOT.'/core/class
 
 if (! isset($conf->global->AGENDA_MAX_EVENTS_DAY_VIEW)) $conf->global->AGENDA_MAX_EVENTS_DAY_VIEW=3;
 
-$filter=GETPOST("filter",'',3);
-$filtert = GETPOST("usertodo","int",3)?GETPOST("usertodo","int",3):GETPOST("filtert","int",3);
+$filter = GETPOST("filter",'',3);
+$filtert = GETPOST("filtert","int",3);
 $usergroup = GETPOST("usergroup","int",3);
 //if (! ($usergroup > 0) && ! ($filtert > 0)) $filtert = $user->id;
 //$showbirthday = empty($conf->use_javascript_ajax)?GETPOST("showbirthday","int"):1;
@@ -250,7 +250,7 @@ $picto='calendarweek';
 $nav.=' &nbsp; <form name="dateselect" action="'.$_SERVER["PHP_SELF"].'?action=show_peruser'.$param.'">';
 $nav.='<input type="hidden" name="token" value="' . $_SESSION ['newtoken'] . '">';
 $nav.='<input type="hidden" name="action" value="' . $action . '">';
-$nav.='<input type="hidden" name="usertodo" value="' . $filtert . '">';
+$nav.='<input type="hidden" name="filtert" value="' . $filtert . '">';
 $nav.='<input type="hidden" name="usergroup" value="' . $usergroup . '">';
 $nav.='<input type="hidden" name="actioncode" value="' . $actioncode . '">';
 $nav.='<input type="hidden" name="resourceid" value="' . $resourceid . '">';
@@ -714,7 +714,7 @@ jQuery(document).ready(function() {
 		else if (ids.indexOf(",") > -1)	/* There is several events */
 		{
 			/* alert(\'several events\'); */
-			url = "'.DOL_URL_ROOT.'/comm/action/listactions.php?usertodo="+userid+"&dateselectyear="+year+"&dateselectmonth="+month+"&dateselectday="+day;
+			url = "'.DOL_URL_ROOT.'/comm/action/listactions.php?filtert="+userid+"&dateselectyear="+year+"&dateselectmonth="+month+"&dateselectday="+day;
 			window.location.href = url;
 		}
 		else	/* One event */

+ 4 - 5
htdocs/comm/action/peruser.php

@@ -38,8 +38,8 @@ if (! empty($conf->projet->enabled)) require_once DOL_DOCUMENT_ROOT.'/core/class
 
 if (! isset($conf->global->AGENDA_MAX_EVENTS_DAY_VIEW)) $conf->global->AGENDA_MAX_EVENTS_DAY_VIEW=3;
 
-$filter=GETPOST("filter",'',3);
-$filtert = GETPOST("usertodo","int",3)?GETPOST("usertodo","int",3):GETPOST("filtert","int",3);
+$filter = GETPOST("filter",'',3);
+$filtert = GETPOST("filtert","int",3);
 $usergroup = GETPOST("usergroup","int",3);
 //if (! ($usergroup > 0) && ! ($filtert > 0)) $filtert = $user->id;
 //$showbirthday = empty($conf->use_javascript_ajax)?GETPOST("showbirthday","int"):1;
@@ -252,7 +252,7 @@ $picto='calendarweek';
 $nav.=' &nbsp; <form name="dateselect" action="'.$_SERVER["PHP_SELF"].'?action=show_peruser'.$param.'">';
 $nav.='<input type="hidden" name="token" value="' . $_SESSION ['newtoken'] . '">';
 $nav.='<input type="hidden" name="action" value="' . $action . '">';
-$nav.='<input type="hidden" name="usertodo" value="' . $filtert . '">';
+$nav.='<input type="hidden" name="filtert" value="' . $filtert . '">';
 $nav.='<input type="hidden" name="usergroup" value="' . $usergroup . '">';
 $nav.='<input type="hidden" name="actioncode" value="' . $actioncode . '">';
 $nav.='<input type="hidden" name="resourceid" value="' . $resourceid . '">';
@@ -663,7 +663,6 @@ else
 	if ($usergroup > 0)	$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."usergroup_user as ug ON u.rowid = ug.fk_user";
 	$sql.= " WHERE u.statut = 1 AND u.entity IN (".getEntity('user',1).")";
 	if ($usergroup > 0)	$sql.= " AND ug.fk_usergroup = ".$usergroup;
-	//if (GETPOST("usertodo","int",3) > 0) $sql.=" AND u.rowid = ".GETPOST("usertodo","int",3);
 	//print $sql;
 	$resql=$db->query($sql);
 	if ($resql)
@@ -816,7 +815,7 @@ jQuery(document).ready(function() {
 		else if (ids.indexOf(",") > -1)	/* There is several events */
 		{
 			/* alert(\'several events\'); */
-			url = "'.DOL_URL_ROOT.'/comm/action/listactions.php?usertodo="+userid+"&dateselectyear="+year+"&dateselectmonth="+month+"&dateselectday="+day;
+			url = "'.DOL_URL_ROOT.'/comm/action/listactions.php?filtert="+userid+"&dateselectyear="+year+"&dateselectmonth="+month+"&dateselectday="+day;
 			window.location.href = url;
 		}
 		else	/* One event */

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

@@ -1057,7 +1057,7 @@ else
 			// Print mail content
 			print load_fiche_titre($langs->trans("EMail"), $form->textwithpicto($langs->trans("AvailableVariables"), $htmltext, 1, 'help', '', 0, 2, 'emailsubstitionhelp'), 'title_generic');
 			
-			dol_fiche_head('');
+			dol_fiche_head('', '', '', -1);
 			
 			print '<table class="border" width="100%">';
 

+ 27 - 24
htdocs/comm/mailing/cibles.php

@@ -161,6 +161,7 @@ if ($_POST["button_removefilter"])
 	$search_lastname='';
 	$search_firstname='';
 	$search_email='';
+	$search_dest_status='';
 }
 
 
@@ -399,7 +400,7 @@ if ($object->fetch($id) >= 0)
 	if ($search_lastname)    $sql.= " AND mc.lastname    LIKE '%".$db->escape($search_lastname)."%'";
 	if ($search_firstname) $sql.= " AND mc.firstname LIKE '%".$db->escape($search_firstname)."%'";
 	if ($search_email)  $sql.= " AND mc.email  LIKE '%".$db->escape($search_email)."%'";
-	if (!empty($search_dest_status)) $sql.= " AND mc.statut=".$db->escape($search_dest_status)." ";
+	if ($search_dest_status != '' && $search_dest_status >= -1) $sql.= " AND mc.statut=".$db->escape($search_dest_status)." ";
 	$sql .= $db->order($sortfield,$sortorder);
 
 	// Count total nb of records
@@ -411,7 +412,7 @@ if ($object->fetch($id) >= 0)
 	}
 	//$nbtotalofrecords=$object->nbemail;     // nbemail is a denormalized field storing nb of targets
 	$sql .= $db->plimit($limit+1, $offset);
-
+	
 	$resql=$db->query($sql);
 	if ($resql)
 	{
@@ -446,29 +447,12 @@ if ($object->fetch($id) >= 0)
 		print '<input type="hidden" name="limit" value="'.$limit.'">';
 		
 
-		if ($page)			$param.= "&amp;page=".$page;
+		if ($page)	$param.= "&amp;page=".$page;
+		
 		print '<table class="noborder" width="100%">';
-		print '<tr class="liste_titre">';
-		print_liste_field_titre($langs->trans("EMail"),$_SERVER["PHP_SELF"],"mc.email",$param,"","",$sortfield,$sortorder);
-		print_liste_field_titre($langs->trans("Lastname"),$_SERVER["PHP_SELF"],"mc.lastname",$param,"","",$sortfield,$sortorder);
-		print_liste_field_titre($langs->trans("Firstname"),$_SERVER["PHP_SELF"],"mc.firstname",$param,"","",$sortfield,$sortorder);
-		print_liste_field_titre($langs->trans("OtherInformations"),$_SERVER["PHP_SELF"],"",$param,"","",$sortfield,$sortorder);
-		print_liste_field_titre($langs->trans("Source"),$_SERVER["PHP_SELF"],"",$param,"",'align="center"',$sortfield,$sortorder);
-		// Date sending
-		if ($object->statut < 2)
-		{
-			print_liste_field_titre('');
-		}
-		else
-		{
-			print_liste_field_titre($langs->trans("DateSending"),$_SERVER["PHP_SELF"],"mc.date_envoi",$param,'','align="center"',$sortfield,$sortorder);
-		}
-		print_liste_field_titre($langs->trans("Status"),$_SERVER["PHP_SELF"],"mc.statut",$param,'','align="right"',$sortfield,$sortorder);
-		print_liste_field_titre('',$_SERVER["PHP_SELF"],"",'','','',$sortfield,$sortorder,'maxwidthsearch ');
-		print '</tr>';
-
+		
 		// Ligne des champs de filtres
-		print '<tr class="liste_titre">';
+		print '<tr class="liste_titre_filter">';
 		// EMail
 		print '<td class="liste_titre">';
 		print '<input class="flat maxwidth100" type="text" name="search_email" value="'.dol_escape_htmltag($search_email).'">';
@@ -489,7 +473,7 @@ if ($object->fetch($id) >= 0)
 		print '<td class="liste_titre">';
 		print '&nbsp';
 		print '</td>';
-
+		
 		// Date sending
 		print '<td class="liste_titre">';
 		print '&nbsp';
@@ -504,6 +488,25 @@ if ($object->fetch($id) >= 0)
 		print $searchpitco;
 		print '</td>';
 		print '</tr>';
+		
+		print '<tr class="liste_titre">';
+		print_liste_field_titre($langs->trans("EMail"),$_SERVER["PHP_SELF"],"mc.email",$param,"","",$sortfield,$sortorder);
+		print_liste_field_titre($langs->trans("Lastname"),$_SERVER["PHP_SELF"],"mc.lastname",$param,"","",$sortfield,$sortorder);
+		print_liste_field_titre($langs->trans("Firstname"),$_SERVER["PHP_SELF"],"mc.firstname",$param,"","",$sortfield,$sortorder);
+		print_liste_field_titre($langs->trans("OtherInformations"),$_SERVER["PHP_SELF"],"",$param,"","",$sortfield,$sortorder);
+		print_liste_field_titre($langs->trans("Source"),$_SERVER["PHP_SELF"],"",$param,"",'align="center"',$sortfield,$sortorder);
+		// Date sending
+		if ($object->statut < 2)
+		{
+			print_liste_field_titre('');
+		}
+		else
+		{
+			print_liste_field_titre($langs->trans("DateSending"),$_SERVER["PHP_SELF"],"mc.date_envoi",$param,'','align="center"',$sortfield,$sortorder);
+		}
+		print_liste_field_titre($langs->trans("Status"),$_SERVER["PHP_SELF"],"mc.statut",$param,'','align="right"',$sortfield,$sortorder);
+		print_liste_field_titre('',$_SERVER["PHP_SELF"],"",'','','',$sortfield,$sortorder,'maxwidthsearch ');
+		print '</tr>';
 
 		$i = 0;
 

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

@@ -80,8 +80,8 @@ class Mailing extends CommonObject
 		$this->statuts[2] = 'MailingStatusSentPartialy';
 		$this->statuts[3] = 'MailingStatusSentCompletely';
 
-		$this->statut_dest[0] = 'MailingStatusNotSent';
 		$this->statut_dest[-1] = 'MailingStatusError';
+		$this->statut_dest[0] = 'MailingStatusNotSent';
 		$this->statut_dest[1] = 'MailingStatusSent';
 		$this->statut_dest[2] = 'MailingStatusRead';
 		$this->statut_dest[3] = 'MailingStatusReadAndUnsubscribe';    // Read but ask to not be contacted anymore

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

@@ -497,7 +497,10 @@ if (empty($reshook))
 											$array_options = $lines[$i]->array_options;
 										}
 
-										$result = $object->addline($desc, $lines[$i]->subprice, $lines[$i]->qty, $lines[$i]->tva_tx, $lines[$i]->localtax1_tx, $lines[$i]->localtax2_tx, $lines[$i]->fk_product, $lines[$i]->remise_percent, 'HT', 0, $lines[$i]->info_bits, $product_type, $lines[$i]->rang, $lines[$i]->special_code, $fk_parent_line, $lines[$i]->fk_fournprice, $lines[$i]->pa_ht, $label, $date_start, $date_end, $array_options, $lines[$i]->fk_unit);
+										$tva_tx = $lines[$i]->tva_tx;
+										if (! empty($lines[$i]->vat_src_code) && ! preg_match('/\(/', $tva_tx)) $tva_tx .= ' ('.$lines[$i]->vat_src_code.')';
+										
+										$result = $object->addline($desc, $lines[$i]->subprice, $lines[$i]->qty, $tva_tx, $lines[$i]->localtax1_tx, $lines[$i]->localtax2_tx, $lines[$i]->fk_product, $lines[$i]->remise_percent, 'HT', 0, $lines[$i]->info_bits, $product_type, $lines[$i]->rang, $lines[$i]->special_code, $fk_parent_line, $lines[$i]->fk_fournprice, $lines[$i]->pa_ht, $label, $date_start, $date_end, $array_options, $lines[$i]->fk_unit);
 
 										if ($result > 0) {
 											$lineid = $result;

+ 9 - 7
htdocs/comm/propal/class/api_proposals.class.php

@@ -16,9 +16,10 @@
  * along with this program. If not, see <http://www.gnu.org/licenses/>.
  */
 
- use Luracast\Restler\RestException;
+use Luracast\Restler\RestException;
+
+require_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php';
 
- require_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php';
 
 /**
  * API class for orders
@@ -260,12 +261,9 @@ class Proposals extends DolibarrApi
                         $request_data->localtax2_tx,
                         $request_data->fk_product,
                         $request_data->remise_percent,
-                        $request_data->info_bits,
-                        $request_data->fk_remise_except,
                         'HT',
                         0,
-                        $request_data->date_start,
-                        $request_data->date_end,
+                        $request_data->info_bits,
                         $request_data->product_type,
                         $request_data->rang,
                         $request_data->special_code,
@@ -273,10 +271,14 @@ class Proposals extends DolibarrApi
                         $request_data->fk_fournprice,
                         $request_data->pa_ht,
                         $request_data->label,
+                        $request_data->date_start,
+                        $request_data->date_end,
                         $request_data->array_options,
                         $request_data->fk_unit,
                         $this->element,
-                        $request_data->id
+                        $request_data->id,
+                        $request_data->pu_ht_devise,
+                        $request_data->fk_remise_except
       );
 
       if ($updateRes > 0) {

+ 132 - 104
htdocs/comm/propal/class/propal.class.php

@@ -187,7 +187,7 @@ class Propal extends CommonObject
 	/**
 	 * Billed or processed quote
 	 */
-	const STATUS_BILLED = 4;
+	const STATUS_BILLED = 4;   // Todo rename into STATUS_CLOSE ?
 
     /**
      *	Constructor
@@ -253,6 +253,8 @@ class Propal extends CommonObject
             $tva_tx = get_default_tva($mysoc,$this->thirdparty,$prod->id);
             $tva_npr = get_default_npr($mysoc,$this->thirdparty,$prod->id);
             if (empty($tva_tx)) $tva_npr=0;
+            $vat_src_code = '';     // May be defined into tva_tx
+            
             $localtax1_tx = get_localtax($tva_tx,1,$mysoc,$this->thirdparty,$tva_npr);
             $localtax2_tx = get_localtax($tva_tx,2,$mysoc,$this->thirdparty,$tva_npr);
 
@@ -273,6 +275,7 @@ class Propal extends CommonObject
             $line->qty=$qty;
             $line->subprice=$price;
             $line->remise_percent=$remise_percent;
+            $line->vat_src_code=$vat_src_code;
             $line->tva_tx=$tva_tx;
 	        $line->fk_unit=$prod->fk_unit;
 			if ($tva_npr) $line->info_bits = 1;
@@ -315,6 +318,7 @@ class Propal extends CommonObject
             $line->fk_propal=$this->id;
             $line->fk_remise_except=$remise->id;
             $line->desc=$remise->description;   	// Description ligne
+            $line->vat_src_code=$remise->vat_src_code;
             $line->tva_tx=$remise->tva_tx;
             $line->subprice=-$remise->amount_ht;
             $line->fk_product=0;					// Id produit predefined
@@ -391,15 +395,16 @@ class Propal extends CommonObject
      * 		@param 		string		$fk_unit 			Code of the unit to use. Null to use the default one
      *      @param		string		$origin				'order', ...
      *      @param		int			$origin_id			Id of origin object
-     *    	@return    	int         	    			>0 if OK, <0 if KO
      * 		@param		double		$pu_ht_devise		Unit price in currency
+     * 		@param		int    		$fk_remise_except	Id discount if line is from a discount
+     *    	@return    	int         	    			>0 if OK, <0 if KO
      *    	@see       	add_product
      */
-	function addline($desc, $pu_ht, $qty, $txtva, $txlocaltax1=0.0, $txlocaltax2=0.0, $fk_product=0, $remise_percent=0.0, $price_base_type='HT', $pu_ttc=0.0, $info_bits=0, $type=0, $rang=-1, $special_code=0, $fk_parent_line=0, $fk_fournprice=0, $pa_ht=0, $label='',$date_start='', $date_end='',$array_options=0, $fk_unit=null, $origin='', $origin_id=0, $pu_ht_devise = 0)
+	function addline($desc, $pu_ht, $qty, $txtva, $txlocaltax1=0.0, $txlocaltax2=0.0, $fk_product=0, $remise_percent=0.0, $price_base_type='HT', $pu_ttc=0.0, $info_bits=0, $type=0, $rang=-1, $special_code=0, $fk_parent_line=0, $fk_fournprice=0, $pa_ht=0, $label='',$date_start='', $date_end='',$array_options=0, $fk_unit=null, $origin='', $origin_id=0, $pu_ht_devise=0, $fk_remise_except=0)
     {
     	global $mysoc, $conf, $langs;
 
-        dol_syslog(get_class($this)."::addline propalid=$this->id, desc=$desc, pu_ht=$pu_ht, qty=$qty, txtva=$txtva, fk_product=$fk_product, remise_except=$remise_percent, price_base_type=$price_base_type, pu_ttc=$pu_ttc, info_bits=$info_bits, type=$type");
+        dol_syslog(get_class($this)."::addline propalid=$this->id, desc=$desc, pu_ht=$pu_ht, qty=$qty, txtva=$txtva, fk_product=$fk_product, remise_except=$remise_percent, price_base_type=$price_base_type, pu_ttc=$pu_ttc, info_bits=$info_bits, type=$type, fk_remise_except=".$fk_remise_except);
         include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
 
         // Clean parameters
@@ -515,6 +520,8 @@ class Propal extends CommonObject
 			$this->line->localtax1_type = $localtaxes_type[0];
 			$this->line->localtax2_type = $localtaxes_type[2];
             $this->line->fk_product=$fk_product;
+            $this->line->product_type=$type;
+            $this->line->fk_remise_except=$fk_remise_except;
             $this->line->remise_percent=$remise_percent;
             $this->line->subprice=$pu_ht;
             $this->line->rang=$rangtouse;
@@ -524,7 +531,6 @@ class Propal extends CommonObject
             $this->line->total_localtax1=$total_localtax1;
             $this->line->total_localtax2=$total_localtax2;
             $this->line->total_ttc=$total_ttc;
-            $this->line->product_type=$type;
             $this->line->special_code=$special_code;
             $this->line->fk_parent_line=$fk_parent_line;
             $this->line->fk_unit=$fk_unit;
@@ -698,7 +704,8 @@ class Propal extends CommonObject
             $this->line->label				= $label;
             $this->line->desc				= $desc;
             $this->line->qty				= $qty;
-            $this->line->product_type			= $type;
+            $this->line->product_type		= $type;
+            $this->line->vat_src_code		= $vat_src_code;
             $this->line->tva_tx				= $txtva;
             $this->line->localtax1_tx		= $txlocaltax1;
             $this->line->localtax2_tx		= $txlocaltax2;
@@ -708,7 +715,6 @@ class Propal extends CommonObject
             $this->line->subprice			= $pu_ht;
             $this->line->info_bits			= $info_bits;
 
-            $this->line->vat_src_code		= $vat_src_code;
             $this->line->total_ht			= $total_ht;
             $this->line->total_tva			= $total_tva;
             $this->line->total_localtax1	= $total_localtax1;
@@ -1301,7 +1307,7 @@ class Propal extends CommonObject
                 $this->note                 = $obj->note_private; // TODO deprecated
                 $this->note_private         = $obj->note_private;
                 $this->note_public          = $obj->note_public;
-                $this->statut               = $obj->fk_statut;
+                $this->statut               = (int) $obj->fk_statut;
                 $this->statut_libelle       = $obj->statut_label;
 
                 $this->datec                = $this->db->jdate($obj->datec); // TODO deprecated
@@ -1366,103 +1372,14 @@ class Propal extends CommonObject
                 $this->lines = array();
 
                 /*
-                 * Lignes propales liees a un produit ou non
+                 * Lines
                  */
-                $sql = "SELECT d.rowid, d.fk_propal, d.fk_parent_line, d.label as custom_label, d.description, d.price, d.tva_tx, d.localtax1_tx, d.localtax2_tx, d.qty, d.fk_remise_except, d.remise_percent, d.subprice, d.fk_product,";
-				$sql.= " d.info_bits, d.total_ht, d.total_tva, d.total_localtax1, d.total_localtax2, d.total_ttc, d.fk_product_fournisseur_price as fk_fournprice, d.buy_price_ht as pa_ht, d.special_code, d.rang, d.product_type,";
-	            $sql.= " d.fk_unit,";
-                $sql.= ' p.ref as product_ref, p.description as product_desc, p.fk_product_type, p.label as product_label,';
-                $sql.= ' d.date_start, d.date_end';
-				$sql.= ' ,d.fk_multicurrency, d.multicurrency_code, d.multicurrency_subprice, d.multicurrency_total_ht, d.multicurrency_total_tva, d.multicurrency_total_ttc';
-                $sql.= " FROM ".MAIN_DB_PREFIX."propaldet as d";
-                $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."product as p ON d.fk_product = p.rowid";
-                $sql.= " WHERE d.fk_propal = ".$this->id;
-                $sql.= " ORDER by d.rang";
-
-                $result = $this->db->query($sql);
-                if ($result)
-                {
-                	require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
-                	$extrafieldsline=new ExtraFields($this->db);
-                	$line = new PropaleLigne($this->db);
-                	$extralabelsline=$extrafieldsline->fetch_name_optionals_label($line->table_element,true);
-
-                    $num = $this->db->num_rows($result);
-                    $i = 0;
-
-                    while ($i < $num)
-                    {
-                        $objp                   = $this->db->fetch_object($result);
-
-                        $line                   = new PropaleLigne($this->db);
-
-                        $line->rowid			= $objp->rowid; //Deprecated
-                        $line->id				= $objp->rowid;
-                        $line->fk_propal		= $objp->fk_propal;
-                        $line->fk_parent_line	= $objp->fk_parent_line;
-                        $line->product_type     = $objp->product_type;
-                        $line->label            = $objp->custom_label;
-                        $line->desc             = $objp->description;  // Description ligne
-                        $line->qty              = $objp->qty;
-                        $line->tva_tx           = $objp->tva_tx;
-                        $line->localtax1_tx		= $objp->localtax1_tx;
-                        $line->localtax2_tx		= $objp->localtax2_tx;
-                        $line->subprice         = $objp->subprice;
-                        $line->fk_remise_except = $objp->fk_remise_except;
-                        $line->remise_percent   = $objp->remise_percent;
-                        $line->price            = $objp->price;		// TODO deprecated
-
-                        $line->info_bits        = $objp->info_bits;
-                        $line->total_ht         = $objp->total_ht;
-                        $line->total_tva        = $objp->total_tva;
-                        $line->total_localtax1	= $objp->total_localtax1;
-                        $line->total_localtax2	= $objp->total_localtax2;
-                        $line->total_ttc        = $objp->total_ttc;
-      					$line->fk_fournprice 	= $objp->fk_fournprice;
-						$marginInfos			= getMarginInfos($objp->subprice, $objp->remise_percent, $objp->tva_tx, $objp->localtax1_tx, $objp->localtax2_tx, $line->fk_fournprice, $objp->pa_ht);
-						$line->pa_ht 			= $marginInfos[0];
-						$line->marge_tx			= $marginInfos[1];
-						$line->marque_tx		= $marginInfos[2];
-                        $line->special_code     = $objp->special_code;
-                        $line->rang             = $objp->rang;
-
-                        $line->fk_product       = $objp->fk_product;
-
-                        $line->ref				= $objp->product_ref;		// TODO deprecated
-                        $line->product_ref		= $objp->product_ref;
-                        $line->libelle			= $objp->product_label;		// TODO deprecated
-                        $line->product_label	= $objp->product_label;
-                        $line->product_desc     = $objp->product_desc; 		// Description produit
-                        $line->fk_product_type  = $objp->fk_product_type;
-	                    $line->fk_unit          = $objp->fk_unit;
-
-                        $line->date_start  		= $this->db->jdate($objp->date_start);
-                        $line->date_end  		= $this->db->jdate($objp->date_end);
-
-						// Multicurrency
-						$line->fk_multicurrency 		= $objp->fk_multicurrency;
-						$line->multicurrency_code 		= $objp->multicurrency_code;
-						$line->multicurrency_subprice 	= $objp->multicurrency_subprice;
-						$line->multicurrency_total_ht 	= $objp->multicurrency_total_ht;
-						$line->multicurrency_total_tva 	= $objp->multicurrency_total_tva;
-						$line->multicurrency_total_ttc 	= $objp->multicurrency_total_ttc;
-
-                        $line->fetch_optionals($line->id,$extralabelsline);
-
-                        $this->lines[$i]        = $line;
-                        //dol_syslog("1 ".$line->fk_product);
-                        //print "xx $i ".$this->lines[$i]->fk_product;
-                        $i++;
-                    }
-                    $this->db->free($result);
-                }
-                else
+                $result=$this->fetch_lines();
+                if ($result < 0)
                 {
-                    $this->error=$this->db->lasterror();
-                    return -1;
+                    return -3;
                 }
 
-
                 return 1;
             }
 
@@ -1475,6 +1392,114 @@ class Propal extends CommonObject
             return -1;
         }
     }
+	
+	/**
+	 * Load array lines
+	 * 
+	 * @param		int		$only_product	Return only physical products
+	 * @return		int						<0 if KO, >0 if OK
+	 */
+	function fetch_lines($only_product=0)
+	{
+		$this->lines=array();
+		
+		$sql = 'SELECT d.rowid, d.fk_propal, d.fk_parent_line, d.label as custom_label, d.description, d.price, d.vat_src_code, d.tva_tx, d.localtax1_tx, d.localtax2_tx, d.qty, d.fk_remise_except, d.remise_percent, d.subprice, d.fk_product,';
+		$sql.= ' d.info_bits, d.total_ht, d.total_tva, d.total_localtax1, d.total_localtax2, d.total_ttc, d.fk_product_fournisseur_price as fk_fournprice, d.buy_price_ht as pa_ht, d.special_code, d.rang, d.product_type,';
+		$sql.= ' d.fk_unit,';
+		$sql.= ' p.ref as product_ref, p.description as product_desc, p.fk_product_type, p.label as product_label,';
+		$sql.= ' d.date_start, d.date_end';
+		$sql.= ' ,d.fk_multicurrency, d.multicurrency_code, d.multicurrency_subprice, d.multicurrency_total_ht, d.multicurrency_total_tva, d.multicurrency_total_ttc';
+		$sql.= ' FROM '.MAIN_DB_PREFIX.'propaldet as d';
+		$sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON (d.fk_product = p.rowid)';
+		$sql.= ' WHERE d.fk_propal = '.$this->id;
+		if ($only_product) $sql .= ' AND p.fk_product_type = 0';
+		$sql.= ' ORDER by d.rang';
+
+		dol_syslog(get_class($this)."::fetch_lines", LOG_DEBUG);
+		$result = $this->db->query($sql);
+		if ($result)
+		{
+			require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
+
+			$num = $this->db->num_rows($result);
+			
+			$i = 0;
+			while ($i < $num)
+			{
+				$objp                   = $this->db->fetch_object($result);
+
+				$line                   = new PropaleLigne($this->db);
+
+				$line->rowid			= $objp->rowid; //Deprecated
+				$line->id				= $objp->rowid;
+				$line->fk_propal		= $objp->fk_propal;
+				$line->fk_parent_line	= $objp->fk_parent_line;
+				$line->product_type     = $objp->product_type;
+				$line->label            = $objp->custom_label;
+				$line->desc             = $objp->description;  // Description ligne
+				$line->qty              = $objp->qty;
+				$line->vat_src_code     = $objp->vat_src_code;
+				$line->tva_tx           = $objp->tva_tx;
+				$line->localtax1_tx		= $objp->localtax1_tx;
+				$line->localtax2_tx		= $objp->localtax2_tx;
+				$line->subprice         = $objp->subprice;
+				$line->fk_remise_except = $objp->fk_remise_except;
+				$line->remise_percent   = $objp->remise_percent;
+				$line->price            = $objp->price;		// TODO deprecated
+
+				$line->info_bits        = $objp->info_bits;
+				$line->total_ht         = $objp->total_ht;
+				$line->total_tva        = $objp->total_tva;
+				$line->total_localtax1	= $objp->total_localtax1;
+				$line->total_localtax2	= $objp->total_localtax2;
+				$line->total_ttc        = $objp->total_ttc;
+				$line->fk_fournprice 	= $objp->fk_fournprice;
+				$marginInfos			= getMarginInfos($objp->subprice, $objp->remise_percent, $objp->tva_tx, $objp->localtax1_tx, $objp->localtax2_tx, $line->fk_fournprice, $objp->pa_ht);
+				$line->pa_ht 			= $marginInfos[0];
+				$line->marge_tx			= $marginInfos[1];
+				$line->marque_tx		= $marginInfos[2];
+				$line->special_code     = $objp->special_code;
+				$line->rang             = $objp->rang;
+
+				$line->fk_product       = $objp->fk_product;
+
+				$line->ref				= $objp->product_ref;		// TODO deprecated
+				$line->product_ref		= $objp->product_ref;
+				$line->libelle			= $objp->product_label;		// TODO deprecated
+				$line->product_label	= $objp->product_label;
+				$line->product_desc     = $objp->product_desc; 		// Description produit
+				$line->fk_product_type  = $objp->fk_product_type;
+				$line->fk_unit          = $objp->fk_unit;
+
+				$line->date_start  		= $this->db->jdate($objp->date_start);
+				$line->date_end  		= $this->db->jdate($objp->date_end);
+
+				// Multicurrency
+				$line->fk_multicurrency 		= $objp->fk_multicurrency;
+				$line->multicurrency_code 		= $objp->multicurrency_code;
+				$line->multicurrency_subprice 	= $objp->multicurrency_subprice;
+				$line->multicurrency_total_ht 	= $objp->multicurrency_total_ht;
+				$line->multicurrency_total_tva 	= $objp->multicurrency_total_tva;
+				$line->multicurrency_total_ttc 	= $objp->multicurrency_total_ttc;
+
+				$line->fetch_optionals();
+
+				$this->lines[$i]        = $line;
+				//dol_syslog("1 ".$line->fk_product);
+				//print "xx $i ".$this->lines[$i]->fk_product;
+				$i++;
+			}
+			
+			$this->db->free($result);
+			
+			return 1;
+		}
+		else
+		{
+			$this->error=$this->db->lasterror();
+			return -3;
+		}
+	}
 
     /**
      *	Update value of extrafields on the proposal
@@ -3326,8 +3351,10 @@ class Propal extends CommonObject
      */
     function getLinesArray()
     {
-        // For other object, here we call fetch_lines. But fetch_lines does not exists on proposal
-
+        // TODO Duplicate with fetch_lines ? Wich one to keep ?
+        
+        $this->lines = array();
+        
         $sql = 'SELECT pt.rowid, pt.label as custom_label, pt.description, pt.fk_product, pt.fk_remise_except,';
         $sql.= ' pt.qty, pt.vat_src_code, pt.tva_tx, pt.remise_percent, pt.subprice, pt.info_bits,';
         $sql.= ' pt.total_ht, pt.total_tva, pt.total_ttc, pt.fk_product_fournisseur_price as fk_fournprice, pt.buy_price_ht as pa_ht, pt.special_code, pt.localtax1_tx, pt.localtax2_tx,';
@@ -3591,7 +3618,7 @@ class PropaleLigne  extends CommonObjectLine
      */
 	function fetch($rowid)
 	{
-		$sql = 'SELECT pd.rowid, pd.fk_propal, pd.fk_parent_line, pd.fk_product, pd.label as custom_label, pd.description, pd.price, pd.qty, pd.tva_tx,';
+		$sql = 'SELECT pd.rowid, pd.fk_propal, pd.fk_parent_line, pd.fk_product, pd.label as custom_label, pd.description, pd.price, pd.qty, pd.vat_src_code, pd.tva_tx,';
 		$sql.= ' pd.remise, pd.remise_percent, pd.fk_remise_except, pd.subprice,';
 		$sql.= ' pd.info_bits, pd.total_ht, pd.total_tva, pd.total_ttc, pd.fk_product_fournisseur_price as fk_fournprice, pd.buy_price_ht as pa_ht, pd.special_code, pd.rang,';
 		$sql.= ' pd.fk_unit,';
@@ -3617,6 +3644,7 @@ class PropaleLigne  extends CommonObjectLine
 			$this->qty				= $objp->qty;
 			$this->price			= $objp->price;		// deprecated
 			$this->subprice			= $objp->subprice;
+			$this->vat_src_code		= $objp->vat_src_code;
 			$this->tva_tx			= $objp->tva_tx;
 			$this->remise			= $objp->remise;    // deprecated
 			$this->remise_percent	= $objp->remise_percent;

+ 2 - 2
htdocs/comm/propal/contact.php

@@ -130,12 +130,12 @@ else if ($action == 'deletecontact' && $user->rights->propale->creer)
 		dol_print_error($db);
 	}
 }
-
+/*
 else if ($action == 'setaddress' && $user->rights->propale->creer)
 {
 	$result=$object->setDeliveryAddress($_POST['fk_address']);
 	if ($result < 0) dol_print_error($db,$object->error);
-}
+}*/
 
 
 /*

+ 4 - 1
htdocs/commande/card.php

@@ -377,7 +377,10 @@ if (empty($reshook))
 									$array_options = $lines[$i]->array_options;
 								}
 
-								$result = $object->addline($desc, $lines[$i]->subprice, $lines[$i]->qty, $lines[$i]->tva_tx, $lines[$i]->localtax1_tx, $lines[$i]->localtax2_tx, $lines[$i]->fk_product, $lines[$i]->remise_percent, $lines[$i]->info_bits, $lines[$i]->fk_remise_except, 'HT', 0, $date_start, $date_end, $product_type, $lines[$i]->rang, $lines[$i]->special_code, $fk_parent_line, $lines[$i]->fk_fournprice, $lines[$i]->pa_ht, $label, $array_options, $lines[$i]->fk_unit, $object->origin, $lines[$i]->rowid);
+								$tva_tx = $lines[$i]->tva_tx;
+								if (! empty($lines[$i]->vat_src_code) && ! preg_match('/\(/', $tva_tx)) $tva_tx .= ' ('.$lines[$i]->vat_src_code.')';
+								
+								$result = $object->addline($desc, $lines[$i]->subprice, $lines[$i]->qty, $tva_tx, $lines[$i]->localtax1_tx, $lines[$i]->localtax2_tx, $lines[$i]->fk_product, $lines[$i]->remise_percent, $lines[$i]->info_bits, $lines[$i]->fk_remise_except, 'HT', 0, $date_start, $date_end, $product_type, $lines[$i]->rang, $lines[$i]->special_code, $fk_parent_line, $lines[$i]->fk_fournprice, $lines[$i]->pa_ht, $label, $array_options, $lines[$i]->fk_unit, $object->origin, $lines[$i]->rowid);
 
 								if ($result < 0) {
 									$error++;

+ 12 - 4
htdocs/commande/class/commande.class.php

@@ -1103,6 +1103,7 @@ class Commande extends CommonOrder
             $line->desc              = $object->lines[$i]->desc;
             $line->price             = $object->lines[$i]->price;
             $line->subprice          = $object->lines[$i]->subprice;
+            $line->vat_src_code      = $object->lines[$i]->vat_src_code;
             $line->tva_tx            = $object->lines[$i]->tva_tx;
             $line->localtax1_tx      = $object->lines[$i]->localtax1_tx;
             $line->localtax2_tx      = $object->lines[$i]->localtax2_tx;
@@ -1466,7 +1467,8 @@ class Commande extends CommonOrder
             $tva_tx = get_default_tva($mysoc,$this->thirdparty,$prod->id);
             $tva_npr = get_default_npr($mysoc,$this->thirdparty,$prod->id);
             if (empty($tva_tx)) $tva_npr=0;
-
+            $vat_src_code = '';     // May be defined into tva_tx
+            
             $localtax1_tx=get_localtax($tva_tx,1,$this->thirdparty,$mysoc,$tva_npr);
             $localtax2_tx=get_localtax($tva_tx,2,$this->thirdparty,$mysoc,$tva_npr);
 
@@ -1485,6 +1487,7 @@ class Commande extends CommonOrder
             $line->qty=$qty;
             $line->subprice=$price;
             $line->remise_percent=$remise_percent;
+            $line->vat_src_code=$vat_src_code;
             $line->tva_tx=$tva_tx;
             $line->localtax1_tx=$localtax1_tx;
             $line->localtax2_tx=$localtax2_tx;
@@ -1703,6 +1706,7 @@ class Commande extends CommonOrder
             $line->fk_commande=$this->id;
             $line->fk_remise_except=$remise->id;
             $line->desc=$remise->description;   	// Description ligne
+            $line->vat_src_code=$remise->vat_src_code;
             $line->tva_tx=$remise->tva_tx;
             $line->subprice=-$remise->amount_ht;
             $line->price=-$remise->amount_ht;
@@ -1758,7 +1762,7 @@ class Commande extends CommonOrder
         $this->lines=array();
 
         $sql = 'SELECT l.rowid, l.fk_product, l.fk_parent_line, l.product_type, l.fk_commande, l.label as custom_label, l.description, l.price, l.qty, l.vat_src_code, l.tva_tx,';
-        $sql.= ' l.localtax1_tx, l.localtax2_tx, l.fk_remise_except, l.remise_percent, l.subprice, l.fk_product_fournisseur_price as fk_fournprice, l.buy_price_ht as pa_ht, l.rang, l.info_bits, l.special_code,';
+        $sql.= ' l.localtax1_tx, l.localtax2_tx, l.localtax1_type, l.localtax2_type, l.fk_remise_except, l.remise_percent, l.subprice, l.fk_product_fournisseur_price as fk_fournprice, l.buy_price_ht as pa_ht, l.rang, l.info_bits, l.special_code,';
         $sql.= ' l.total_ht, l.total_ttc, l.total_tva, l.total_localtax1, l.total_localtax2, l.date_start, l.date_end,';
 	    $sql.= ' l.fk_unit,';
 		$sql.= ' l.fk_multicurrency, l.multicurrency_code, l.multicurrency_subprice, l.multicurrency_total_ht, l.multicurrency_total_tva, l.multicurrency_total_ttc,';
@@ -1795,9 +1799,11 @@ class Commande extends CommonOrder
 
                 $line->vat_src_code     = $objp->vat_src_code; 
                 $line->tva_tx           = $objp->tva_tx;
-                $line->localtax1_tx     = $objp->localtax1_tx;
+	            $line->localtax1_tx     = $objp->localtax1_tx;
                 $line->localtax2_tx     = $objp->localtax2_tx;
-                $line->total_ht         = $objp->total_ht;
+	            $line->localtax1_type	= $objp->localtax1_type;
+	            $line->localtax2_type	= $objp->localtax2_type;
+	            $line->total_ht         = $objp->total_ht;
                 $line->total_ttc        = $objp->total_ttc;
                 $line->total_tva        = $objp->total_tva;
                 $line->total_localtax1  = $objp->total_localtax1;
@@ -3806,6 +3812,7 @@ class OrderLine extends CommonOrderLine
             $this->qty              = $objp->qty;
             $this->price            = $objp->price;
             $this->subprice         = $objp->subprice;
+            $this->vat_src_code     = $objp->vat_src_code;
             $this->tva_tx           = $objp->tva_tx;
             $this->localtax1_tx		= $objp->localtax1_tx;
             $this->localtax2_tx		= $objp->localtax2_tx;
@@ -4117,6 +4124,7 @@ class OrderLine extends CommonOrderLine
 		$sql = "UPDATE ".MAIN_DB_PREFIX."commandedet SET";
 		$sql.= " description='".$this->db->escape($this->desc)."'";
 		$sql.= " , label=".(! empty($this->label)?"'".$this->db->escape($this->label)."'":"null");
+		$sql.= " , vat_src_code=".(! empty($this->vat_src_code)?"'".$this->db->escape($this->vat_src_code)."'":"''");
 		$sql.= " , tva_tx=".price2num($this->tva_tx);
 		$sql.= " , localtax1_tx=".price2num($this->localtax1_tx);
 		$sql.= " , localtax2_tx=".price2num($this->localtax2_tx);

+ 3 - 2
htdocs/commande/contact.php

@@ -107,13 +107,14 @@ else if ($action == 'deletecontact' && $user->rights->commande->creer)
 		dol_print_error($db);
 	}
 }
-
+/*
 else if ($action == 'setaddress' && $user->rights->commande->creer)
 {
 	$object->fetch($id);
 	$result=$object->setDeliveryAddress($_POST['fk_address']);
 	if ($result < 0) dol_print_error($db,$object->error);
-}
+}*/
+
 
 /*
  * View

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

@@ -1,11 +1,11 @@
 <?php
 /* Copyright (C) 2002-2003	Rodolphe Quiedeville	<rodolphe@quiedeville.org>
- * Copyright (C) 2003		Jean-Louis Bergamo	<jlb@j1b.org>
- * Copyright (C) 2004-2016	Laurent Destailleur	<eldy@users.sourceforge.net>
- * Copyright (C) 2005-2009	Regis Houssin		<regis.houssin@capnetworks.com>
- * Copyright (C) 2014-2016	Alexandre Spangaro	<aspangaro.dolibarr@gmail.com>
- * Copyright (C) 2015       Jean-François Ferry	<jfefe@aternatik.fr>
- * Copyright (C) 2016       Marcos García       <marcosgdf@gmail.com>
+ * Copyright (C) 2003		Jean-Louis Bergamo		<jlb@j1b.org>
+ * Copyright (C) 2004-2016	Laurent Destailleur		<eldy@users.sourceforge.net>
+ * Copyright (C) 2005-2009	Regis Houssin			<regis.houssin@capnetworks.com>
+ * Copyright (C) 2014-2017	Alexandre Spangaro		<aspangaro@zendsi.com>
+ * Copyright (C) 2015		Jean-François Ferry		<jfefe@aternatik.fr>
+ * Copyright (C) 2016		Marcos García			<marcosgdf@gmail.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -35,8 +35,8 @@ require_once DOL_DOCUMENT_ROOT . '/core/class/html.formbank.class.php';
 require_once DOL_DOCUMENT_ROOT . '/compta/bank/class/account.class.php';
 require_once DOL_DOCUMENT_ROOT . '/core/class/extrafields.class.php';
 if (! empty($conf->categorie->enabled)) require_once DOL_DOCUMENT_ROOT . '/categories/class/categorie.class.php';
-if (! empty($conf->accounting->enabled)) require_once DOL_DOCUMENT_ROOT . '/core/lib/accounting.lib.php';
 if (! empty($conf->accounting->enabled)) require_once DOL_DOCUMENT_ROOT . '/accountancy/class/html.formventilation.class.php';
+if (! empty($conf->accounting->enabled)) require_once DOL_DOCUMENT_ROOT . '/accountancy/class/accountingaccount.class.php';
 
 $langs->load("banks");
 $langs->load("bills");
@@ -664,7 +664,10 @@ else
 		print '<tr class="liste_titre_add"><td class="titlefield">'.$langs->trans("AccountancyCode").'</td>';
 		print '<td>';
 		if (! empty($conf->accounting->enabled)) {
-		    print length_accountg($object->account_number).'</td></tr>';
+			$accountingaccount = new AccountingAccount($db);
+			$accountingaccount->fetch('',$object->account_number);
+
+			print $accountingaccount->getNomUrl(0,1,1,'',1);
 		} else {
 		    print $object->account_number;
 		}
@@ -683,13 +686,11 @@ else
 		
 		print '</table>';
 
-		
 		print '</div>';
 		print '<div class="fichehalfright">';
 		print '<div class="ficheaddleft">';
 		print '<div class="underbanner clearboth"></div>';
 
-
 		print '<table class="border centpercent">';
 		
         // Categories
@@ -703,8 +704,7 @@ else
 		print '<td>'.dol_htmlentitiesbr($object->comment).'</td></tr>';
 
 		print '</table>';
-		
-		
+
 		if ($object->type == Account::TYPE_SAVINGS || $object->type == Account::TYPE_CURRENT)
 		{
 		    print '<br>';

+ 21 - 3
htdocs/compta/bank/index.php

@@ -33,6 +33,7 @@ require_once DOL_DOCUMENT_ROOT.'/compta/bank/class/account.class.php';
 $langs->load("banks");
 $langs->load("categories");
 $langs->load("accountancy");
+$langs->load("compta");
 
 $action=GETPOST('action','alpha');
 $massaction=GETPOST('massaction','alpha');
@@ -87,6 +88,7 @@ $arrayfields=array(
     'b.label'=>array('label'=>$langs->trans("Label"), 'checked'=>1),
     'b.number'=>array('label'=>$langs->trans("AccountIdShort"), 'checked'=>1),
     'b.account_number'=>array('label'=>$langs->trans("AccountAccounting"), 'checked'=>$conf->accountancy->enabled),
+    'b.accountancy_journal'=>array('label'=>$langs->trans("AccountancyJournal"), 'checked'=>$conf->accountancy->enabled),
     'toreconcile'=>array('label'=>$langs->trans("TransactionsToConciliate"), 'checked'=>1),
     'b.datec'=>array('label'=>$langs->trans("DateCreation"), 'checked'=>0, 'position'=>500),
     'b.tms'=>array('label'=>$langs->trans("DateModificationShort"), 'checked'=>0, 'position'=>500),
@@ -139,7 +141,7 @@ $title=$langs->trans('BankAccounts');
 // Load array of financial accounts (opened by default)
 $accounts = array();
 
-$sql  = "SELECT rowid, label, courant, rappro, account_number, datec as date_creation, tms as date_update";
+$sql  = "SELECT rowid, label, courant, rappro, account_number, accountancy_journal, datec as date_creation, tms as date_update";
 // Add fields from extrafields
 foreach ($extrafields->attribute_label as $key => $val) $sql.=($extrafields->attribute_type[$key] != 'separate' ? ",ef.".$key.' as options_'.$key : '');
 // Add fields from hooks
@@ -286,6 +288,7 @@ print '<div class="div-table-responsive">';
 print '<table class="tagtable liste'.($moreforfilter?" listwithfilterbefore":"").'">'."\n";
 
 print '<tr class="liste_titre_filter">';
+
 // Ref
 if (! empty($arrayfields['b.ref']['checked']))
 {
@@ -306,19 +309,25 @@ if (! empty($arrayfields['accountype']['checked']))
     print '<td class="liste_titre">';
     print '</td>';
 }
-// Number
+// Bank number
 if (! empty($arrayfields['b.number']['checked']))
 {
     print '<td class="liste_titre">';
     print '<input class="flat" size="6" type="text" name="search_number" value="'.$search_number.'">';
     print '</td>';
 }
-// Number
+// Account number
 if (! empty($arrayfields['b.account_number']['checked']))
 {
     print '<td class="liste_titre">';
     print '</td>';
 }
+// Accountancy journal
+if (! empty($arrayfields['b.accountancy_journal']['checked']))
+{
+    print '<td class="liste_titre">';
+    print '</td>';
+}
 // Transactions to reconcile
 if (! empty($arrayfields['toreconcile']['checked']))
 {
@@ -394,6 +403,7 @@ if (! empty($arrayfields['b.label']['checked']))          print_liste_field_titr
 if (! empty($arrayfields['accountype']['checked']))       print_liste_field_titre($arrayfields['accountype']['label'],$_SERVER["PHP_SELF"],'','',$param,'',$sortfield,$sortorder);
 if (! empty($arrayfields['b.number']['checked']))         print_liste_field_titre($arrayfields['b.number']['label'],$_SERVER["PHP_SELF"],'b.number','',$param,'',$sortfield,$sortorder);
 if (! empty($arrayfields['b.account_number']['checked'])) print_liste_field_titre($arrayfields['b.account_number']['label'],$_SERVER["PHP_SELF"],'b.account_number','',$param,'',$sortfield,$sortorder);
+if (! empty($arrayfields['b.accountancy_journal']['checked'])) print_liste_field_titre($arrayfields['b.accountancy_journal']['label'],$_SERVER["PHP_SELF"],'b.accountancy_journal','',$param,'',$sortfield,$sortorder);
 if (! empty($arrayfields['toreconcile']['checked']))      print_liste_field_titre($arrayfields['toreconcile']['label'],$_SERVER["PHP_SELF"],'','',$param,'align="center"',$sortfield,$sortorder);
 // Extra fields
 if (is_array($extrafields->attribute_label) && count($extrafields->attribute_label))
@@ -482,6 +492,14 @@ foreach ($accounts as $key=>$type)
 	    if (! $i) $totalarray['nbfield']++;
     }
     
+    // Accountancy journal
+    if (! empty($arrayfields['b.accountancy_journal']['checked']))
+    {
+        include_once DOL_DOCUMENT_ROOT.'/core/lib/accounting.lib.php';
+        print '<td>'.length_accountg($acc->accountancy_journal).'</td>';
+	    if (! $i) $totalarray['nbfield']++;
+    }
+    
     // Transactions to reconcile
     if (! empty($arrayfields['toreconcile']['checked']))
     {

+ 26 - 34
htdocs/compta/facture/card.php

@@ -611,7 +611,9 @@ if (empty($reshook))
 		{
 			$db->begin();
 
-			// Boucle sur chaque taux de tva
+			$amount_ht = $amount_tva = $amount_ttc = array();
+			
+			// Loop on each vat rate
 			$i = 0;
 			foreach ($object->lines as $line)
 			{
@@ -630,20 +632,19 @@ if (empty($reshook))
 				$discount->description = '(CREDIT_NOTE)';
 			elseif ($object->type == Facture::TYPE_DEPOSIT)
 				$discount->description = '(DEPOSIT)';
-			elseif ($object->type == Facture::TYPE_STANDARD)
+			elseif ($object->type == Facture::TYPE_STANDARD || $object->type == Facture::TYPE_REPLACEMENT || $object->type == Facture::TYPE_SITUATION)
 				$discount->description = '(EXCESS RECEIVED)';
 			else {
 				setEventMessages($langs->trans('CantConvertToReducAnInvoiceOfThisType'), null, 'errors');
 			}
-			$discount->tva_tx = abs($object->total_ttc);
 			$discount->fk_soc = $object->socid;
 			$discount->fk_facture_source = $object->id;
 
 			$error = 0;
 			
-			if ($object->type == Facture::TYPE_STANDARD) {
-				
-				// If we're on a standard invoice, we have to get excess received to create it in TTC wuthout VAT
+			if ($object->type == Facture::TYPE_STANDARD || $object->type == Facture::TYPE_REPLACEMENT || $object->type == Facture::TYPE_SITUATION) 
+			{
+				// If we're on a standard invoice, we have to get excess received to create a discount in TTC without VAT
 				
 				$sql = 'SELECT SUM(pf.amount) as total_paiements
 						FROM llx_c_paiement as c, llx_paiement_facture as pf, llx_paiement as p
@@ -663,8 +664,9 @@ if (empty($reshook))
 					$error++;
 				}
 				
-			} else {
-			
+			}
+			if ($object->type == Facture::TYPE_CREDIT_NOTE || $object->type == Facture::TYPE_DEPOSIT)
+			{
 				foreach ($amount_ht as $tva_tx => $xxx)
 				{
 					$discount->amount_ht = abs($amount_ht[$tva_tx]);
@@ -871,19 +873,6 @@ if (empty($reshook))
 	                    $object->addline($langs->trans('invoiceAvoirLineWithPaymentRestAmount'),$remain_to_pay,1,0,0,0,0,0,'','','TTC');
 	                }
 	            }
-
-				// Add predefined lines
-				/*
-	             TODO delete
-	             for($i = 1; $i <= $NBLINES; $i ++) {
-					if ($_POST['idprod' . $i]) {
-						$product = new Product($db);
-						$product->fetch($_POST['idprod' . $i]);
-						$startday = dol_mktime(12, 0, 0, $_POST['date_start' . $i . 'month'], $_POST['date_start' . $i . 'day'], $_POST['date_start' . $i . 'year']);
-						$endday = dol_mktime(12, 0, 0, $_POST['date_end' . $i . 'month'], $_POST['date_end' . $i . 'day'], $_POST['date_end' . $i . 'year']);
-						$result = $object->addline($product->description, $product->price, $_POST['qty' . $i], $product->tva_tx, $product->localtax1_tx, $product->localtax2_tx, $_POST['idprod' . $i], $_POST['remise_percent' . $i], $startday, $endday, 0, 0, '', $product->price_base_type, $product->price_ttc, $product->type);
-					}
-				}*/
 			}
 		}
 
@@ -1077,7 +1066,7 @@ if (empty($reshook))
 							{
 								if ($typeamount == 'amount')
 								{
-									$amountdeposit[] = $valuedeposit;
+									$amountdeposit[0] = $valuedeposit;
 								}
 								else
 								{
@@ -1095,9 +1084,11 @@ if (empty($reshook))
 										}
 
 										if ($totalamount != 0) {
-											$amountdeposit[$lines[$i]->tva] = ($totalamount * $valuedeposit) / 100;
+										    $tva_tx = $lines[$i]->tva_tx;
+										    if (! empty($lines[$i]->vat_src_code) && ! preg_match('/\(/', $tva_tx)) $tva_tx .= ' ('.$lines[$i]->vat_src_code.')';
+											$amountdeposit[$tva_tx] = ($totalamount * $valuedeposit) / 100;
 										} else {
-											$amountdeposit[] = 0;
+											$amountdeposit[0] = 0;
 										}
 									} else {
 										setEventMessages($srcobject->error, $srcobject->errors, 'errors');
@@ -1222,11 +1213,15 @@ if (empty($reshook))
 											$array_options = $lines[$i]->array_options;
 										}
 
-										// View third's localtaxes for now
-										$localtax1_tx = get_localtax($lines[$i]->tva_tx, 1, $object->thirdparty);
-										$localtax2_tx = get_localtax($lines[$i]->tva_tx, 2, $object->thirdparty);
+										$tva_tx = $lines[$i]->tva_tx;
+										if (! empty($lines[$i]->vat_src_code) && ! preg_match('/\(/', $tva_tx)) $tva_tx .= ' ('.$lines[$i]->vat_src_code.')';
+										
+										// View third's localtaxes for NOW and do not use value from origin.
+										// TODO Is this really what we want ? Yes if source if template invoice but what if proposal or order ?
+										$localtax1_tx = get_localtax($tva_tx, 1, $object->thirdparty);
+										$localtax2_tx = get_localtax($tva_tx, 2, $object->thirdparty);
 
-										$result = $object->addline($desc, $lines[$i]->subprice, $lines[$i]->qty, $lines[$i]->tva_tx, $localtax1_tx, $localtax2_tx, $lines[$i]->fk_product, $lines[$i]->remise_percent, $date_start, $date_end, 0, $lines[$i]->info_bits, $lines[$i]->fk_remise_except, 'HT', 0, $product_type, $lines[$i]->rang, $lines[$i]->special_code, $object->origin, $lines[$i]->rowid, $fk_parent_line, $lines[$i]->fk_fournprice, $lines[$i]->pa_ht, $label, $array_options, $lines[$i]->situation_percent, $lines[$i]->fk_prev_id, $lines[$i]->fk_unit);
+										$result = $object->addline($desc, $lines[$i]->subprice, $lines[$i]->qty, $tva_tx, $localtax1_tx, $localtax2_tx, $lines[$i]->fk_product, $lines[$i]->remise_percent, $date_start, $date_end, 0, $lines[$i]->info_bits, $lines[$i]->fk_remise_except, 'HT', 0, $product_type, $lines[$i]->rang, $lines[$i]->special_code, $object->origin, $lines[$i]->rowid, $fk_parent_line, $lines[$i]->fk_fournprice, $lines[$i]->pa_ht, $label, $array_options, $lines[$i]->situation_percent, $lines[$i]->fk_prev_id, $lines[$i]->fk_unit);
 
 										if ($result > 0) {
 											$lineid = $result;
@@ -3634,8 +3629,7 @@ else if ($id > 0 || ! empty($ref))
             print '<tr class="liste_titre">';
             print '<td>' . $langs->trans('ListOfNextSituationInvoices') . '</td>';
             print '<td></td>';
-            if (! empty($conf->banque->enabled))
-                print '<td align="right"></td>';
+            if (! empty($conf->banque->enabled)) print '<td align="right"></td>';
             print '<td align="right">' . $langs->trans('AmountHT') . '</td>';
             print '<td align="right">' . $langs->trans('AmountTTC') . '</td>';
             print '<td width="18">&nbsp;</td>';
@@ -3651,8 +3645,7 @@ else if ($id > 0 || ! empty($ref))
                 print '<tr ' . $bc[$var] . '>';
                 print '<td>' . $next_invoice->getNomUrl(1) . '</td>';
                 print '<td></td>';
-                if (! empty($conf->banque->enabled))
-                    print '<td align="right"></td>';
+                if (! empty($conf->banque->enabled)) print '<td align="right"></td>';
                 print '<td align="right">' . price($next_invoice->total_ht) . '</td>';
                 print '<td align="right">' . price($next_invoice->total_ttc) . '</td>';
                 print '<td align="right">' . $next_invoice->getLibStatut(3, $totalpaye) . '</td>';
@@ -3663,8 +3656,7 @@ else if ($id > 0 || ! empty($ref))
             
             print '<tr ' . $bc[$var] . '>';
             print '<td colspan="2" align="right"></td>';
-	    if (! empty($conf->banque->enabled))
-		print '<td align="right"></td>';
+		    if (! empty($conf->banque->enabled)) print '<td align="right"></td>';
 
             print '<td align="right"><b>' . price($total_next_ht) . '</b></td>';
             print '<td align="right"><b>' . price($total_next_ttc) . '</b></td>';

+ 9 - 5
htdocs/compta/facture/class/facture.class.php

@@ -951,6 +951,7 @@ class Facture extends CommonInvoice
 			$line->total_ht			= $object->lines[$i]->total_ht;
 			$line->total_tva		= $object->lines[$i]->total_tva;
 			$line->total_ttc		= $object->lines[$i]->total_ttc;
+			$line->vat_src_code  	= $object->lines[$i]->vat_src_code;
 			$line->tva_tx			= $object->lines[$i]->tva_tx;
 			$line->localtax1_tx		= $object->lines[$i]->localtax1_tx;
 			$line->localtax2_tx		= $object->lines[$i]->localtax2_tx;
@@ -1550,6 +1551,7 @@ class Facture extends CommonInvoice
 			$facligne->fk_facture=$this->id;
 			$facligne->fk_remise_except=$remise->id;
 			$facligne->desc=$remise->description;   	// Description ligne
+			$facligne->vat_src_code=$remise->vat_src_code;
 			$facligne->tva_tx=$remise->tva_tx;
 			$facligne->subprice=-$remise->amount_ht;
 			$facligne->fk_product=0;					// Id produit predefini
@@ -2398,7 +2400,7 @@ class Facture extends CommonInvoice
 	 * 		@param    	string		$desc            	Description of line
 	 * 		@param    	double		$pu_ht              Unit price without tax (> 0 even for credit note)
 	 * 		@param    	double		$qty             	Quantity
-	 * 		@param    	double		$txtva           	Force Vat rate, -1 for auto
+	 * 		@param    	double		$txtva           	Force Vat rate, -1 for auto (Can contain the vat_src_code too with syntax '9.9 (CODE)')
 	 * 		@param		double		$txlocaltax1		Local tax 1 rate (deprecated)
 	 *  	@param		double		$txlocaltax2		Local tax 2 rate (deprecated)
 	 *		@param    	int			$fk_product      	Id of predefined product/service
@@ -3511,10 +3513,11 @@ class Facture extends CommonInvoice
 
 
 	/**
-	 *	Create a withdrawal request for a standing order
+	 *	Create a withdrawal request for a standing order.
+	 *  Use the remain to pay excluding all existing open direct debit requests.
 	 *
-	 *	@param      User	$fuser       User asking standing order
-	 *  @param		float	$amount		Amount we request withdraw for
+	 *	@param      User	$fuser      User asking the direct debit transfer
+	 *  @param		float	$amount		Amount we request direct debit for
 	 *	@return     int         		<0 if KO, >0 if OK
 	 */
 	function demande_prelevement($fuser, $amount=0)
@@ -4225,7 +4228,7 @@ class FactureLigne extends CommonInvoiceLine
 	 */
 	function fetch($rowid)
 	{
-		$sql = 'SELECT fd.rowid, fd.fk_facture, fd.fk_parent_line, fd.fk_product, fd.product_type, fd.label as custom_label, fd.description, fd.price, fd.qty, fd.tva_tx,';
+		$sql = 'SELECT fd.rowid, fd.fk_facture, fd.fk_parent_line, fd.fk_product, fd.product_type, fd.label as custom_label, fd.description, fd.price, fd.qty, fd.vat_src_code, fd.tva_tx,';
 		$sql.= ' fd.localtax1_tx, fd. localtax2_tx, fd.remise, fd.remise_percent, fd.fk_remise_except, fd.subprice,';
 		$sql.= ' fd.date_start as date_start, fd.date_end as date_end, fd.fk_product_fournisseur_price as fk_fournprice, fd.buy_price_ht as pa_ht,';
 		$sql.= ' fd.info_bits, fd.special_code, fd.total_ht, fd.total_tva, fd.total_ttc, fd.total_localtax1, fd.total_localtax2, fd.rang,';
@@ -4253,6 +4256,7 @@ class FactureLigne extends CommonInvoiceLine
 			$this->desc					= $objp->description;
 			$this->qty					= $objp->qty;
 			$this->subprice				= $objp->subprice;
+			$this->vat_src_code  		= $objp->vat_src_code;
 			$this->tva_tx				= $objp->tva_tx;
 			$this->localtax1_tx			= $objp->localtax1_tx;
 			$this->localtax2_tx			= $objp->localtax2_tx;

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

@@ -35,8 +35,9 @@ require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
 require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php';
 if (! empty($conf->projet->enabled)) {
     require_once DOL_DOCUMENT_ROOT . '/projet/class/project.class.php';
-    require_once DOL_DOCUMENT_ROOT . '/core/class/html.formprojet.class.php';
+    //require_once DOL_DOCUMENT_ROOT . '/core/class/html.formprojet.class.php';
 }
+require_once DOL_DOCUMENT_ROOT . '/core/class/html.formprojet.class.php';
 require_once DOL_DOCUMENT_ROOT . '/core/class/doleditor.class.php';
 require_once DOL_DOCUMENT_ROOT . '/core/lib/invoice.lib.php';
 
@@ -891,7 +892,6 @@ if ($action == 'create')
 
 	$object = new Facture($db);   // Source invoice
 	$product_static = new Product($db);
-	$formproject = new FormProjets($db);
 
 	if ($object->fetch($id, $ref) > 0)
 	{

+ 19 - 19
htdocs/compta/paiement.php

@@ -1,6 +1,6 @@
 <?php
 /* Copyright (C) 2001-2006 Rodolphe Quiedeville  <rodolphe@quiedeville.org>
- * Copyright (C) 2004-2016 Laurent Destailleur   <eldy@users.sourceforge.net>
+ * Copyright (C) 2004-2017 Laurent Destailleur   <eldy@users.sourceforge.net>
  * Copyright (C) 2005      Marc Barilley / Ocebo <marc@ocebo.com>
  * Copyright (C) 2005-2012 Regis Houssin         <regis.houssin@capnetworks.com>
  * Copyright (C) 2007      Franky Van Liedekerke <franky.van.liedekerke@telenet.be>
@@ -221,7 +221,7 @@ if (empty($reshook))
 	    $db->begin();
 
 	    // Clean parameters amount if payment is for a credit note
-	    if (GETPOST('type') == 2)
+	    if (GETPOST('type') == Facture::TYPE_CREDIT_NOTE)
 	    {
 		    foreach ($amounts as $key => $value)	// How payment is dispatch
 		    {
@@ -249,7 +249,7 @@ if (empty($reshook))
 	    // Creation of payment line
 	    $paiement = new Paiement($db);
 	    $paiement->datepaye     = $datepaye;
-	    $paiement->amounts      = $amounts;   // Array with all payments dispatching
+	    $paiement->amounts      = $amounts;   // Array with all payments dispatching with invoice id
 	    $paiement->multicurrency_amounts = $multicurrency_amounts;   // Array with all payments dispatching
 	    $paiement->paiementid   = dol_getIdFromCode($db,GETPOST('paiementcode'),'c_paiement');
 	    $paiement->num_paiement = GETPOST('num_paiement');
@@ -257,7 +257,7 @@ if (empty($reshook))
 
 	    if (! $error)
 	    {
-	    	$paiement_id = $paiement->create($user, (GETPOST('closepaidinvoices')=='on'?1:0));
+	    	$paiement_id = $paiement->create($user, (GETPOST('closepaidinvoices')=='on'?1:0));    // This include closing invoices
 	    	if ($paiement_id < 0)
 	        {
 	            setEventMessages($paiement->error, $paiement->errors, 'errors');
@@ -268,7 +268,7 @@ if (empty($reshook))
 	    if (! $error)
 	    {
 	    	$label='(CustomerInvoicePayment)';
-	    	if (GETPOST('type') == 2) $label='(CustomerInvoicePaymentBack)';
+	    	if (GETPOST('type') == Facture::TYPE_CREDIT_NOTE) $label='(CustomerInvoicePaymentBack)';  // Refund of a credit note
 	        $result=$paiement->addPaymentToBank($user,'payment',$label,GETPOST('accountid'),GETPOST('chqemetteur'),GETPOST('chqbank'));
 	        if ($result < 0)
 	        {
@@ -281,7 +281,7 @@ if (empty($reshook))
 	    {
 	        $db->commit();
 
-	        // If payment dispatching on more than one invoice, we keep on summary page, otherwise go on invoice card
+	        // If payment dispatching on more than one invoice, we keep on summary page, otherwise jump on invoice card
 	        $invoiceid=0;
 	        foreach ($paiement->amounts as $key => $amount)
 	        {
@@ -309,7 +309,7 @@ if (empty($reshook))
  * View
  */
 
-llxHeader();
+llxHeader('', $langs->trans("Payment"));
 
 $form=new Form($db);
 
@@ -324,8 +324,8 @@ if ($action == 'create' || $action == 'confirm_paiement' || $action == 'add_paie
 		$facture->fetch_thirdparty();
 
 		$title='';
-		if ($facture->type != 2) $title.=$langs->trans("EnterPaymentReceivedFromCustomer");
-		if ($facture->type == 2) $title.=$langs->trans("EnterPaymentDueToCustomer");
+		if ($facture->type != Facture::TYPE_CREDIT_NOTE) $title.=$langs->trans("EnterPaymentReceivedFromCustomer");
+		if ($facture->type == Facture::TYPE_CREDIT_NOTE) $title.=$langs->trans("EnterPaymentDueToCustomer");
 		print load_fiche_titre($title);
 
 		// Initialize data for confirmation (this is used because data can be change during confirmation)
@@ -347,7 +347,7 @@ if ($action == 'create' || $action == 'confirm_paiement' || $action == 'add_paie
 		}
 
 		// Add realtime total information
-		if ($conf->use_javascript_ajax)
+		if (! empty($conf->use_javascript_ajax))
 		{
 			print "\n".'<script type="text/javascript" language="javascript">';
 			print '$(document).ready(function () {
@@ -369,7 +369,7 @@ if ($action == 'create' || $action == 'confirm_paiement' || $action == 'add_paie
 			                    }
             					if ($(\'#fieldchqemetteur\').val() == \'\')
             					{
-            						var emetteur = ('.$facture->type.' == 2) ? \''.dol_escape_js(dol_escape_htmltag($conf->global->MAIN_INFO_SOCIETE_NOM)).'\' : jQuery(\'#thirdpartylabel\').val();
+            						var emetteur = ('.$facture->type.' == '.Facture::TYPE_CREDIT_NOTE.') ? \''.dol_escape_js(dol_escape_htmltag($conf->global->MAIN_INFO_SOCIETE_NOM)).'\' : jQuery(\'#thirdpartylabel\').val();
             						$(\'#fieldchqemetteur\').val(emetteur);
             					}
             				}
@@ -437,14 +437,14 @@ if ($action == 'create' || $action == 'confirm_paiement' || $action == 'add_paie
 			';
 
 			print '	});'."\n";
-			if (!empty($conf->use_javascript_ajax)){
-				//Add js for AutoFill
-				print ' $(document).ready(function () {';
-				print ' 	$(".AutoFillAmout").on(\'click touchstart\', function(){
-								$("input[name="+$(this).data(\'rowname\')+"]").val($(this).data("value")).trigger("change");
-							});';
-				print '	});'."\n";
-			}
+
+			//Add js for AutoFill
+			print ' $(document).ready(function () {';
+			print ' 	$(".AutoFillAmout").on(\'click touchstart\', function(){
+							$("input[name="+$(this).data(\'rowname\')+"]").val($(this).data("value")).trigger("change");
+						});';
+			print '	});'."\n";
+
 			print '	</script>'."\n";
 		}
 

+ 119 - 112
htdocs/compta/paiement/cheque/card.php

@@ -334,7 +334,7 @@ else
 	//  $head[$h][1] = $langs->trans("Info");
 	//  $h++;
 
-	dol_fiche_head($head, $hselected, $langs->trans("Cheques"),0,'payment');
+	dol_fiche_head($head, $hselected, $langs->trans("Cheques"), -1, 'payment');
 
 	/*
 	 * Confirmation de la suppression du bordereau
@@ -476,8 +476,7 @@ if ($action == 'new')
         print '<table class="tagtable liste'.($moreforfilter?" listwithfilterbefore":"").'">'."\n";
 		
 		print '<tr class="liste_titre">';
-		print '<td style="min-width: 120px">'.$langs->trans("DateChequeReceived").' ';
-		print "</td>\n";
+		print '<td style="min-width: 120px">'.$langs->trans("DateChequeReceived").'</td>'."\n";
 		print '<td style="min-width: 120px">'.$langs->trans("ChequeNumber")."</td>\n";
 		print '<td style="min-width: 200px">'.$langs->trans("CheckTransmitter")."</td>\n";
 		print '<td style="min-width: 200px">'.$langs->trans("Bank")."</td>\n";
@@ -487,59 +486,57 @@ if ($action == 'new')
 		print '<td align="center" width="100px">'.$langs->trans("Select")."<br>";
 		if ($conf->use_javascript_ajax) print '<a href="#" id="checkall_'.$bid.'">'.$langs->trans("All").'</a> / <a href="#" id="checknone_'.$bid.'">'.$langs->trans("None").'</a>';
 		print '</td>';
-
 		print "</tr>\n";
 
-		$var=true;
-
-		foreach ($lines[$bid] as $lid => $value)
+		if (count($lines[$bid]))
 		{
-			
-
-			$account_id = $bid;
-			if (! isset($accounts[$bid]))
-				$accounts[$bid]=0;
-			$accounts[$bid] += 1;
-
-			print '<tr class="oddeven">';
-			print '<td>'.dol_print_date($value["date"],'day').'</td>';
-			print '<td>'.$value["numero"]."</td>\n";
-			print '<td>'.$value["emetteur"]."</td>\n";
-			print '<td>'.$value["banque"]."</td>\n";
-			print '<td align="right">'.price($value["amount"], 0, $langs, 1, -1, -1, $conf->currency).'</td>';
-
-			// Link to payment
-			print '<td align="center">';
-			$paymentstatic->id=$value["paymentid"];
-			$paymentstatic->ref=$value["paymentid"];
-			if ($paymentstatic->id)
-			{
-				print $paymentstatic->getNomUrl(1);
-			}
-			else
-			{
-				print '&nbsp;';
-			}
-			print '</td>';
-			// Link to bank transaction
-			print '<td align="center">';
-			$accountlinestatic->rowid=$value["id"];
-			if ($accountlinestatic->rowid)
-			{
-				print $accountlinestatic->getNomUrl(1);
-			}
-			else
-			{
-				print '&nbsp;';
-			}
-			print '</td>';
-
-			print '<td align="center">';
-			print '<input id="'.$value["id"].'" class="flat checkforremise_'.$bid.'" checked type="checkbox" name="toRemise[]" value="'.$value["id"].'">';
-			print '</td>' ;
-			print '</tr>';
-
-			$i++;
+    		foreach ($lines[$bid] as $lid => $value)
+    		{
+    			$account_id = $bid;
+    			if (! isset($accounts[$bid]))
+    				$accounts[$bid]=0;
+    			$accounts[$bid] += 1;
+
+    			print '<tr class="oddeven">';
+    			print '<td>'.dol_print_date($value["date"],'day').'</td>';
+    			print '<td>'.$value["numero"]."</td>\n";
+    			print '<td>'.$value["emetteur"]."</td>\n";
+    			print '<td>'.$value["banque"]."</td>\n";
+    			print '<td align="right">'.price($value["amount"], 0, $langs, 1, -1, -1, $conf->currency).'</td>';
+
+    			// Link to payment
+    			print '<td align="center">';
+    			$paymentstatic->id=$value["paymentid"];
+    			$paymentstatic->ref=$value["paymentid"];
+    			if ($paymentstatic->id)
+    			{
+    				print $paymentstatic->getNomUrl(1);
+    			}
+    			else
+    			{
+    				print '&nbsp;';
+    			}
+    			print '</td>';
+    			// Link to bank transaction
+    			print '<td align="center">';
+    			$accountlinestatic->rowid=$value["id"];
+    			if ($accountlinestatic->rowid)
+    			{
+    				print $accountlinestatic->getNomUrl(1);
+    			}
+    			else
+    			{
+    				print '&nbsp;';
+    			}
+    			print '</td>';
+    
+    			print '<td align="center">';
+    			print '<input id="'.$value["id"].'" class="flat checkforremise_'.$bid.'" checked type="checkbox" name="toRemise[]" value="'.$value["id"].'">';
+    			print '</td>' ;
+    			print '</tr>';
+    
+    			$i++;
+    		}
 		}
 		print "</table>";
         print '</div>';
@@ -686,65 +683,75 @@ else
 		print_liste_field_titre('');
 		print "</tr>\n";
 		$i=1;
-		$var=false;
-		while ($objp = $db->fetch_object($resql))
-		{
-			$account_id = $objp->bid;
-			if (! isset($accounts[$objp->bid]))
-				$accounts[$objp->bid]=0;
-			$accounts[$objp->bid] += 1;
-
-			print '<tr class="oddeven">';
-			print '<td align="center">'.$i.'</td>';
-			print '<td align="center">'.dol_print_date($db->jdate($objp->date),'day').'</td>';	// Date operation
-			print '<td align="center">'.($objp->num_chq?$objp->num_chq:'&nbsp;').'</td>';
-			print '<td>'.dol_trunc($objp->emetteur,24).'</td>';
-			print '<td>'.dol_trunc($objp->banque,24).'</td>';
-			print '<td align="right">'.price($objp->amount).'</td>';
-			// Link to payment
-			print '<td align="center">';
-			$paymentstatic->id=$objp->pid;
-			$paymentstatic->ref=$objp->pid;
-			if ($paymentstatic->id)
-			{
-				print $paymentstatic->getNomUrl(1);
-			}
-			else
-			{
-				print '&nbsp;';
-			}
-			print '</td>';
-			// Link to bank transaction
-			print '<td align="center">';
-			$accountlinestatic->rowid=$objp->rowid;
-			if ($accountlinestatic->rowid)
-			{
-				print $accountlinestatic->getNomUrl(1);
-			}
-			else
-			{
-				print '&nbsp;';
-			}
-			print '</td>';
-			// Action button
-			print '<td align="right">';
-			if ($object->statut == 0)
-			{
-				print '<a href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&amp;action=remove&amp;lineid='.$objp->rowid.'">'.img_delete().'</a>';
-			}
-   			if ($object->statut == 1 && $objp->statut != 2)
-   			{
-   				print '<a href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&amp;action=reject_check&amp;lineid='.$objp->rowid.'">'.img_picto($langs->trans("RejectCheck"),'disable').'</a>';
-   			}
-			if ($objp->statut == 2) 
-			{
-				print ' &nbsp; '.img_picto($langs->trans('CheckRejected'),'statut8').'</a>';
-			}
-		    print '</td>';
-			print '</tr>';
-			
-			$i++;
-		}
+
+        if ($num > 0)
+        {
+    		while ($objp = $db->fetch_object($resql))
+    		{
+    			$account_id = $objp->bid;
+    			if (! isset($accounts[$objp->bid]))
+    				$accounts[$objp->bid]=0;
+    			$accounts[$objp->bid] += 1;
+    
+    			print '<tr class="oddeven">';
+    			print '<td align="center">'.$i.'</td>';
+    			print '<td align="center">'.dol_print_date($db->jdate($objp->date),'day').'</td>';	// Date operation
+    			print '<td align="center">'.($objp->num_chq?$objp->num_chq:'&nbsp;').'</td>';
+    			print '<td>'.dol_trunc($objp->emetteur,24).'</td>';
+    			print '<td>'.dol_trunc($objp->banque,24).'</td>';
+    			print '<td align="right">'.price($objp->amount).'</td>';
+    			// Link to payment
+    			print '<td align="center">';
+    			$paymentstatic->id=$objp->pid;
+    			$paymentstatic->ref=$objp->pid;
+    			if ($paymentstatic->id)
+    			{
+    				print $paymentstatic->getNomUrl(1);
+    			}
+    			else
+    			{
+    				print '&nbsp;';
+    			}
+    			print '</td>';
+    			// Link to bank transaction
+    			print '<td align="center">';
+    			$accountlinestatic->rowid=$objp->rowid;
+    			if ($accountlinestatic->rowid)
+    			{
+    				print $accountlinestatic->getNomUrl(1);
+    			}
+    			else
+    			{
+    				print '&nbsp;';
+    			}
+    			print '</td>';
+    			// Action button
+    			print '<td align="right">';
+    			if ($object->statut == 0)
+    			{
+    				print '<a href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&amp;action=remove&amp;lineid='.$objp->rowid.'">'.img_delete().'</a>';
+    			}
+       			if ($object->statut == 1 && $objp->statut != 2)
+       			{
+       				print '<a href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&amp;action=reject_check&amp;lineid='.$objp->rowid.'">'.img_picto($langs->trans("RejectCheck"),'disable').'</a>';
+       			}
+    			if ($objp->statut == 2) 
+    			{
+    				print ' &nbsp; '.img_picto($langs->trans('CheckRejected'),'statut8').'</a>';
+    			}
+    		    print '</td>';
+    			print '</tr>';
+    			
+    			$i++;
+    		}
+        }
+        else
+        {
+            print '<td colspan="8" class="opacitymedium">';
+            print $langs->trans("None");
+            print '</td>';
+        }
+                
 		print "</table>";
 		print "</div>";
 	}

+ 4 - 10
htdocs/compta/paiement/cheque/index.php

@@ -50,8 +50,6 @@ llxHeader('',$langs->trans("ChequesArea"));
 
 print load_fiche_titre($langs->trans("ChequesArea"));
 
-//print '<table border="0" width="100%" class="notopnoleftnoright">';
-//print '<tr><td valign="top" width="30%" class="notopnoleft">';
 print '<div class="fichecenter"><div class="fichethirdleft">';
 
 $sql = "SELECT count(b.rowid)";
@@ -90,7 +88,6 @@ else
 }
 
 
-//print '</td><td valign="top" width="70%" class="notopnoleftnoright">';
 print '</div><div class="fichetwothirdright"><div class="ficheaddleft">';
 
 $max=10;
@@ -98,15 +95,13 @@ $max=10;
 $sql = "SELECT bc.rowid, bc.date_bordereau as db, bc.amount, bc.ref as ref";
 $sql.= ", bc.statut, bc.nbcheque";
 $sql.= ", ba.label, ba.rowid as bid";
-$sql.= " FROM ".MAIN_DB_PREFIX."bordereau_cheque as bc";
-$sql.= ", ".MAIN_DB_PREFIX."bank_account as ba";
+$sql.= " FROM ".MAIN_DB_PREFIX."bordereau_cheque as bc, ".MAIN_DB_PREFIX."bank_account as ba";
 $sql.= " WHERE ba.rowid = bc.fk_bank_account";
 $sql.= " AND bc.entity = ".$conf->entity;
 $sql.= " ORDER BY bc.date_bordereau DESC, rowid DESC";
 $sql.= $db->plimit($max);
 
 $resql = $db->query($sql);
-
 if ($resql)
 {
 	print '<table class="noborder" width="100%">';
@@ -128,9 +123,8 @@ if ($resql)
 
 		$accountstatic->id=$objp->bid;
 		$accountstatic->label=$objp->label;
-
 		
-		print "<tr ".$bc[$var].">\n";
+		print '<tr class="oddeven">'."\n";
 
 		print '<td>'.$checkdepositstatic->getNomUrl(1).'</td>';
 		print '<td>'.dol_print_date($db->jdate($objp->db),'day').'</td>';
@@ -142,15 +136,15 @@ if ($resql)
 		print '</tr>';
 	}
 	print "</table>";
+
 	$db->free($resql);
 }
 else
 {
-  dol_print_error($db);
+    dol_print_error($db);
 }
 
 
-//print "</td></tr></table>\n";
 print '</div></div></div>';
 
 llxFooter();

+ 55 - 5
htdocs/compta/paiement/class/paiement.class.php

@@ -255,7 +255,7 @@ class Paiement extends CommonObject
                                 {
                                     if (! empty($conf->prelevement->enabled))
                                     {
-                                        // TODO Check if this payment has a withdraw request
+                                        // FIXME Check if this invoice has a withdraw request
                                         // if not, $mustwait++;      // This will disable automatic close on invoice to allow to process
                                     }
                                 }
@@ -275,11 +275,61 @@ class Paiement extends CommonObject
                             else if ($mustwait) dol_syslog("There is ".$mustwait." differed payment to process, we do nothing more.");
                             else
                             {
-                                $result=$invoice->set_paid($user,'','');
-                                if ($result<0)
+                                // If invoice is a down payment, we also convert down payment to discount
+                                if ($invoice->type == Facture::TYPE_DEPOSIT)
                                 {
-                                    $this->error=$invoice->error;
-                                    $error++;
+			                        $amount_ht = $amount_tva = $amount_ttc = array();
+			                         
+                                    // Loop on each vat rate
+                                    $i = 0;
+                                    foreach ($invoice->lines as $line)
+                                    {
+                                        if ($line->total_ht!=0)
+                                        { 	// no need to create discount if amount is null
+                                            $amount_ht[$line->tva_tx] += $line->total_ht;
+                                            $amount_tva[$line->tva_tx] += $line->total_tva;
+                                            $amount_ttc[$line->tva_tx] += $line->total_ttc;
+                                            $i ++;
+                                        }
+                                    }
+                                    
+                                    // Insert one discount by VAT rate category
+                                    $discount = new DiscountAbsolute($this->db);
+                                    $discount->description = '(DEPOSIT)';
+                                    $discount->fk_soc = $invoice->socid;
+                                    $discount->fk_facture_source = $invoice->id;
+                                
+                                    foreach ($amount_ht as $tva_tx => $xxx)
+                                    {
+                                        $discount->amount_ht = abs($amount_ht[$tva_tx]);
+                                        $discount->amount_tva = abs($amount_tva[$tva_tx]);
+                                        $discount->amount_ttc = abs($amount_ttc[$tva_tx]);
+                                        $discount->tva_tx = abs($tva_tx);
+                            
+                                        $result = $discount->create($user);
+                                        if ($result < 0)
+                                        {
+                                            $error++;
+                                            break;
+                                        }
+                                    }
+                                    
+                                    if ($error)
+                                    {
+                                        setEventMessages($discount->error, $discount->errors, 'errors');
+                                        $error++;
+                                    }                                   
+                                }
+                                
+                                // Set invoice to paid
+                                if (! $error)
+                                {
+                                    $result=$invoice->set_paid($user,'','');
+                                    if ($result<0)
+                                    {
+                                        $this->error=$invoice->error;
+                                        $error++;
+                                    }
                                 }
                             }
 					    }

+ 9 - 3
htdocs/contrat/card.php

@@ -332,14 +332,20 @@ if (empty($reshook))
 								else {
 								    $desc = dol_htmlentitiesbr($lines[$i]->desc);
 						        }
+
+								$txtva = $lines[$i]->vat_src_code ? $lines[$i]->tva_tx . ' (' .  $lines[$i]->vat_src_code . ')' : $lines[$i]->tva_tx;
+
+								// View third's localtaxes for now
+								$localtax1_tx = get_localtax($txtva, 1, $object->thirdparty);
+								$localtax2_tx = get_localtax($txtva, 2, $object->thirdparty);
 	
 			                    $result = $object->addline(
 					                $desc,
 					                $lines[$i]->subprice,
 					                $lines[$i]->qty,
-					                $lines[$i]->tva_tx,
-					                $lines[$i]->localtax1_tx,
-					                $lines[$i]->localtax2_tx,
+                                    $txtva,
+                                    $localtax1_tx,
+                                    $localtax2_tx,
 					                $lines[$i]->fk_product,
 					                $lines[$i]->remise_percent,
 					                $lines[$i]->date_start,

+ 7 - 1
htdocs/contrat/class/contrat.class.php

@@ -616,7 +616,7 @@ class Contrat extends CommonObject
 		
 		// Selectionne les lignes contrats liees a un produit
 		$sql = "SELECT p.label as product_label, p.description as product_desc, p.ref as product_ref,";
-		$sql.= " d.rowid, d.fk_contrat, d.statut, d.description, d.price_ht, d.tva_tx, d.localtax1_tx, d.localtax2_tx, d.qty, d.remise_percent, d.subprice, d.fk_product_fournisseur_price as fk_fournprice, d.buy_price_ht as pa_ht,";
+		$sql.= " d.rowid, d.fk_contrat, d.statut, d.description, d.price_ht, d.vat_src_code, d.tva_tx, d.localtax1_tx, d.localtax2_tx, d.localtax1_type, d.localtax2_type, d.qty, d.remise_percent, d.subprice, d.fk_product_fournisseur_price as fk_fournprice, d.buy_price_ht as pa_ht,";
 		$sql.= " d.total_ht,";
 		$sql.= " d.total_tva,";
 		$sql.= " d.total_localtax1,";
@@ -650,9 +650,12 @@ class Contrat extends CommonObject
 				$line->fk_contrat		= $objp->fk_contrat;
 				$line->desc				= $objp->description;  // Description ligne
 				$line->qty				= $objp->qty;
+				$line->vat_src_code 	= $objp->vat_src_code ;
 				$line->tva_tx			= $objp->tva_tx;
 				$line->localtax1_tx		= $objp->localtax1_tx;
 				$line->localtax2_tx		= $objp->localtax2_tx;
+				$line->localtax1_type	= $objp->localtax1_type;
+				$line->localtax2_type	= $objp->localtax2_type;
 				$line->subprice			= $objp->subprice;
 				$line->statut			= $objp->statut;
 				$line->remise_percent	= $objp->remise_percent;
@@ -2722,6 +2725,7 @@ class ContratLigne extends CommonObjectLine
 		$this->statut=(int) $this->statut;
 		$this->label=trim($this->label);
 		$this->description=trim($this->description);
+		$this->vat_src_code=trim($this->vat_src_code);
 		$this->tva_tx=trim($this->tva_tx);
 		$this->localtax1_tx=trim($this->localtax1_tx);
 		$this->localtax2_tx=trim($this->localtax2_tx);
@@ -2793,6 +2797,7 @@ class ContratLigne extends CommonObjectLine
 		$sql.= " date_ouverture=".($this->date_ouverture!=''?"'".$this->db->idate($this->date_ouverture)."'":"null").",";
 		$sql.= " date_fin_validite=".($this->date_fin_validite!=''?"'".$this->db->idate($this->date_fin_validite)."'":"null").",";
 		$sql.= " date_cloture=".($this->date_cloture!=''?"'".$this->db->idate($this->date_cloture)."'":"null").",";
+		$sql.= " vat_src_code='".$this->vat_src_code."',";
 		$sql.= " tva_tx='".$this->tva_tx."',";
 		$sql.= " localtax1_tx='".$this->localtax1_tx."',";
 		$sql.= " localtax2_tx='".$this->localtax2_tx."',";
@@ -2921,6 +2926,7 @@ class ContratLigne extends CommonObjectLine
 		$sql.= ") VALUES ($this->fk_contrat, '', '" . $this->db->escape($this->description) . "',";
 		$sql.= ($this->fk_product>0 ? $this->fk_product : "null").",";
 		$sql.= " '".$this->qty."',";
+		$sql.= " '".$this->vat_src_code."',";
 		$sql.= " '".$this->tva_tx."',";
 		$sql.= " '".$this->localtax1_tx."',";
 		$sql.= " '".$this->localtax2_tx."',";

+ 98 - 53
htdocs/core/actions_massactions.inc.php

@@ -406,60 +406,105 @@ if (! $error && $massaction == "builddoc" && $permtoread && ! GETPOST('button_se
         $outputlangs->setDefaultLang($newlang);
     }
 
-    // Create empty PDF
-    $pdf=pdf_getInstance();
-    if (class_exists('TCPDF'))
-    {
-        $pdf->setPrintHeader(false);
-        $pdf->setPrintFooter(false);
-    }
-    $pdf->SetFont(pdf_getPDFFont($outputlangs));
-
-    if (! empty($conf->global->MAIN_DISABLE_PDF_COMPRESSION)) $pdf->SetCompression(false);
-
-    // Add all others
-    foreach($files as $file)
-    {
-        // Charge un document PDF depuis un fichier.
-        $pagecount = $pdf->setSourceFile($file);
-        for ($i = 1; $i <= $pagecount; $i++)
-        {
-            $tplidx = $pdf->importPage($i);
-            $s = $pdf->getTemplatesize($tplidx);
-            $pdf->AddPage($s['h'] > $s['w'] ? 'P' : 'L');
-            $pdf->useTemplate($tplidx);
-        }
+    if(!empty($conf->global->USE_PDFTK_FOR_PDF_CONCAT)) {
+    	// Create output dir if not exists
+	dol_mkdir($diroutputmassaction);
+
+	// Defined name of merged file
+	$filename=strtolower(dol_sanitizeFileName($langs->transnoentities($objectlabel)));
+	$filename=preg_replace('/\s/','_',$filename);
+
+	// Save merged file
+	if ($filter=='paye:0')
+	{
+	if ($option=='late') $filename.='_'.strtolower(dol_sanitizeFileName($langs->transnoentities("Unpaid"))).'_'.strtolower(dol_sanitizeFileName($langs->transnoentities("Late")));
+	else $filename.='_'.strtolower(dol_sanitizeFileName($langs->transnoentities("Unpaid")));
+	}
+	if ($year) $filename.='_'.$year;
+	if ($month) $filename.='_'.$month;
+
+    	if (count($files)>0)
+    	{
+    	
+    		$now=dol_now();
+    		$file=$diroutputmassaction.'/'.$filename.'_'.dol_print_date($now,'dayhourlog').'.pdf';
+    		
+    		$input_files = '';
+    		foreach($files as $f) {
+    			$input_files.=' '.escapeshellarg($f);
+    		}
+    		
+    		$cmd = 'pdftk '.$input_files.' cat output '.escapeshellarg($file);
+    		exec($cmd);
+    		
+    		if (! empty($conf->global->MAIN_UMASK))
+    			@chmod($file, octdec($conf->global->MAIN_UMASK));
+    			
+    			$langs->load("exports");
+    			setEventMessages($langs->trans('FileSuccessfullyBuilt',$filename.'_'.dol_print_date($now,'dayhourlog')), null, 'mesgs');
+    	}
+    	else
+    	{
+    		setEventMessages($langs->trans('NoPDFAvailableForDocGenAmongChecked'), null, 'errors');
+    	}
+    	
     }
-
-    // Create output dir if not exists
-    dol_mkdir($diroutputmassaction);
-
-    // Defined name of merged file
-    $filename=strtolower(dol_sanitizeFileName($langs->transnoentities($objectlabel)));
-    $filename=preg_replace('/\s/','_',$filename);
-    
-    // Save merged file
-    if ($filter=='paye:0')
-    {
-        if ($option=='late') $filename.='_'.strtolower(dol_sanitizeFileName($langs->transnoentities("Unpaid"))).'_'.strtolower(dol_sanitizeFileName($langs->transnoentities("Late")));
-        else $filename.='_'.strtolower(dol_sanitizeFileName($langs->transnoentities("Unpaid")));
-    }
-    if ($year) $filename.='_'.$year;
-    if ($month) $filename.='_'.$month;
-    if ($pagecount)
-    {
-        $now=dol_now();
-        $file=$diroutputmassaction.'/'.$filename.'_'.dol_print_date($now,'dayhourlog').'.pdf';
-        $pdf->Output($file,'F');
-        if (! empty($conf->global->MAIN_UMASK))
-            @chmod($file, octdec($conf->global->MAIN_UMASK));
-
-            $langs->load("exports");
-            setEventMessages($langs->trans('FileSuccessfullyBuilt',$filename.'_'.dol_print_date($now,'dayhourlog')), null, 'mesgs');
-    }
-    else
-    {
-        setEventMessages($langs->trans('NoPDFAvailableForDocGenAmongChecked'), null, 'errors');
+    else {
+	    // Create empty PDF
+	    $pdf=pdf_getInstance();
+	    if (class_exists('TCPDF'))
+	    {
+		$pdf->setPrintHeader(false);
+		$pdf->setPrintFooter(false);
+	    }
+	    $pdf->SetFont(pdf_getPDFFont($outputlangs));
+
+	    if (! empty($conf->global->MAIN_DISABLE_PDF_COMPRESSION)) $pdf->SetCompression(false);
+
+	    // Add all others
+	    foreach($files as $file)
+	    {
+		// Charge un document PDF depuis un fichier.
+		$pagecount = $pdf->setSourceFile($file);
+		for ($i = 1; $i <= $pagecount; $i++)
+		{
+		    $tplidx = $pdf->importPage($i);
+		    $s = $pdf->getTemplatesize($tplidx);
+		    $pdf->AddPage($s['h'] > $s['w'] ? 'P' : 'L');
+		    $pdf->useTemplate($tplidx);
+		}
+	    }
+
+	    // Create output dir if not exists
+	    dol_mkdir($diroutputmassaction);
+
+	    // Defined name of merged file
+	    $filename=strtolower(dol_sanitizeFileName($langs->transnoentities($objectlabel)));
+	    $filename=preg_replace('/\s/','_',$filename);
+	    
+	    // Save merged file
+	    if ($filter=='paye:0')
+	    {
+		if ($option=='late') $filename.='_'.strtolower(dol_sanitizeFileName($langs->transnoentities("Unpaid"))).'_'.strtolower(dol_sanitizeFileName($langs->transnoentities("Late")));
+		else $filename.='_'.strtolower(dol_sanitizeFileName($langs->transnoentities("Unpaid")));
+	    }
+	    if ($year) $filename.='_'.$year;
+	    if ($month) $filename.='_'.$month;
+	    if ($pagecount)
+	    {
+		$now=dol_now();
+		$file=$diroutputmassaction.'/'.$filename.'_'.dol_print_date($now,'dayhourlog').'.pdf';
+		$pdf->Output($file,'F');
+		if (! empty($conf->global->MAIN_UMASK))
+		    @chmod($file, octdec($conf->global->MAIN_UMASK));
+
+		    $langs->load("exports");
+		    setEventMessages($langs->trans('FileSuccessfullyBuilt',$filename.'_'.dol_print_date($now,'dayhourlog')), null, 'mesgs');
+	    }
+	    else
+	    {
+		setEventMessages($langs->trans('NoPDFAvailableForDocGenAmongChecked'), null, 'errors');
+	    }
     }
 }
 

+ 6 - 1
htdocs/core/ajax/check_notifications.php

@@ -21,7 +21,6 @@ if (! defined('NOREQUIREMENU'))  define('NOREQUIREMENU','1');
 if (! defined('NOREQUIREHTML'))  define('NOREQUIREHTML','1');
 if (! defined('NOREQUIREAJAX'))  define('NOREQUIREAJAX','1');
 if (! defined('NOREQUIRESOC'))   define('NOREQUIRESOC','1');
-if (! defined('NOREQUIRETRAN'))  define('NOREQUIRETRAN','1');
 
 require '../../main.inc.php';
 
@@ -88,9 +87,11 @@ if ($time >= $_SESSION['auto_check_events_not_before'])
         while ($obj = $db->fetch_object($resql)) 
         {
             $langs->load("agenda");
+            $langs->load("commercial");
             
             $actionmod->fetch($obj->id);
 
+            // Message must be formated and translated to be used with javascript directly
             $event = array();
             $event['type'] = 'agenda';
             $event['id'] = $actionmod->id;
@@ -101,6 +102,10 @@ if ($time >= $_SESSION['auto_check_events_not_before'])
             $eventfound[] = $event;
         }
     }
+    else
+    {
+        dol_syslog("Error sql = ".$db->lasterror(), LOG_ERR);
+    }
 
 }
 

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

@@ -80,8 +80,11 @@ class box_external_rss extends ModeleBoxes
 		// documents/externalrss is created by module activation
 		// documents/externalrss/tmp is created by rssparser
 
+		$keyforparamurl="EXTERNAL_RSS_URLRSS_".$site;
+		$keyforparamtitle="EXTERNAL_RSS_TITLE_".$site;
+		
 		// Get RSS feed
-        $url=@constant("EXTERNAL_RSS_URLRSS_".$site);
+		$url=$conf->global->$keyforparamurl;
 
         $rssparser=new RssParser($this->db);
 		$result = $rssparser->parser($url, $this->max, $cachedelay, $conf->externalrss->dir_temp);
@@ -90,7 +93,7 @@ class box_external_rss extends ModeleBoxes
 		$description=$rssparser->getDescription();
 		$link=$rssparser->getLink();
 
-        $title=$langs->trans("BoxTitleLastRssInfos",$max, @constant("EXTERNAL_RSS_TITLE_". $site));
+        $title=$langs->trans("BoxTitleLastRssInfos", $max, $conf->global->$keyforparamtitle);
         if ($result < 0 || ! empty($rssparser->error))
         {
             // Show warning

+ 17 - 6
htdocs/core/class/commondocgenerator.class.php

@@ -360,7 +360,7 @@ abstract class CommonDocGenerator
 	{
 		global $conf;
 
-		$sumpayed=''; $alreadypayed='';
+		$sumpayed=$sumdeposit=$sumcreditnote='';
 		if ($object->element == 'facture')
 		{
 			$invoice_source=new Facture($this->db);
@@ -369,7 +369,8 @@ abstract class CommonDocGenerator
 				$invoice_source->fetch($object->fk_facture_source);
 			}
 			$sumpayed = $object->getSommePaiement();
-			$alreadypayed=price($sumpayed,0,$outputlangs);
+			$sumdeposit = $object->getSumDepositsUsed();
+			$sumcreditnote = $object->getSumCreditNotesUsed();
 		}
 
 		$resarray=array(
@@ -412,11 +413,21 @@ abstract class CommonDocGenerator
 		$array_key.'_note_private'=>$object->note,
 		$array_key.'_note_public'=>$object->note_public,
 		$array_key.'_note'=>$object->note_public,			// For backward compatibility
+		
 		// Payments
-		$array_key.'_already_payed_locale'=>price($alreadypayed, 0, $outputlangs),
-		$array_key.'_remain_to_pay_locale'=>price($object->total_ttc - $sumpayed, 0, $outputlangs),
-		$array_key.'_already_payed'=>$alreadypayed,
-		$array_key.'_remain_to_pay'=>price2num($object->total_ttc - $sumpayed)
+		$array_key.'_already_payed_locale'=>price($sumpayed, 0, $outputlangs),
+		$array_key.'_already_payed'=>price2num($sumpayed),
+		$array_key.'_already_deposit_locale'=>price($sumdeposit, 0, $outputlangs),
+		$array_key.'_already_deposit'=>price2num($sumdeposit),
+		$array_key.'_already_creditnote_locale'=>price($sumcreditnote, 0, $outputlangs),
+		$array_key.'_already_creditnote'=>price2num($sumcreditnote),
+		
+		$array_key.'_already_payed_all_locale'=>price(price2num($sumpayed + $sumdeposit + $sumcreditnote, 'MT'), 0, $outputlangs),
+		$array_key.'already_payed_all'=> price2num(($sumpayed + $sumdeposit + $sumcreditnote), 'MT'),
+		    
+		// Remain to pay with all know infrmation (except open direct debit requests)
+		$array_key.'_remain_to_pay_locale'=>price(price2num($object->total_ttc - $sumpayed - $sumdeposit - $sumcreditnote, 'MT'), 0, $outputlangs),
+		$array_key.'_remain_to_pay'=>price2num($object->total_ttc - $sumpayed - $sumdeposit - $sumcreditnote, 'MT')
 		);
 
 		// Add vat by rates

+ 10 - 3
htdocs/core/class/commoninvoice.class.php

@@ -51,7 +51,8 @@ abstract class CommonInvoice extends CommonObject
     const TYPE_DEPOSIT = 3;
 
     /**
-     * Proforma invoice
+     * Proforma invoice. 
+     * @deprectad Remove this. A "proforma invoice" is an order with a look of invoice, not an invoice !
      */
     const TYPE_PROFORMA = 4;
 
@@ -90,8 +91,8 @@ abstract class CommonInvoice extends CommonObject
 
 	
 	/**
-	 * 	Return remain amount to pay.
-	 *  Property ->id and ->total_ttc must be set.
+	 * 	Return remain amount to pay. Property ->id and ->total_ttc must be set.
+	 *  This does not include open direct debit requests.
 	 *
 	 *  @param 		int 	$multicurrency 	Return multicurrency_amount instead of amount
 	 *	@return		int						Remain of amount to pay
@@ -548,6 +549,12 @@ abstract class CommonInvoiceLine extends CommonObjectLine
 	 */
 	public $fk_product;
 
+	/**
+	 * VAT code
+	 * @var string
+	 */
+	public $vat_src_code;
+
 	/**
 	 * VAT %
 	 * @var float

+ 407 - 72
htdocs/core/class/commonobject.class.php

@@ -11,6 +11,7 @@
  * Copyright (C) 2012      Cedric Salvador      <csalvador@gpcsolutions.fr>
  * Copyright (C) 2015      Alexandre Spangaro   <aspangaro.dolibarr@gmail.com>
  * Copyright (C) 2016      Bahfir abbes         <dolipar@dolipar.org>
+ * Copyright (C) 2017      ATM Consulting       <support@atm-consulting.fr>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -238,6 +239,7 @@ abstract class CommonObject
 
 	/**
 	 * @var int Delivery address ID
+	 * @deprecated
 	 * @see setDeliveryAddress()
 	 */
 	public $fk_delivery_address;
@@ -1623,7 +1625,8 @@ abstract class CommonObject
 
     /**
      *	Define delivery address
-     *
+     *  @deprecated
+     *  
      *	@param      int		$id		Address id
      *	@return     int				<0 si ko, >0 si ok
      */
@@ -2787,6 +2790,8 @@ abstract class CommonObject
     {
     	global $user,$langs,$conf;
 
+    	$savElementId=$elementId;  // To be used later to know if we were using the method using the id of this or not.
+    	
         $elementId = (!empty($elementId)?$elementId:$this->id);
         $elementTable = (!empty($elementType)?$elementType:$this->table_element);
 
@@ -2810,11 +2815,13 @@ abstract class CommonObject
             $error = 0;
 
             $trigkey='';
-            if ($this->element == 'supplier_proposal' && $status == 2) $trigkey='SUPPLIER_PROPOSAL_CLOSE';
+            if ($this->element == 'supplier_proposal' && $status == 2) $trigkey='SUPPLIER_PROPOSAL_SIGN';   // 2 = SupplierProposal::STATUS_SIGNED. Can't use constant into this generic class
+            if ($this->element == 'supplier_proposal' && $status == 3) $trigkey='SUPPLIER_PROPOSAL_REFUSE'; // 3 = SupplierProposal::STATUS_REFUSED. Can't use constant into this generic class
+            if ($this->element == 'supplier_proposal' && $status == 4) $trigkey='SUPPLIER_PROPOSAL_CLOSE';  // 4 = SupplierProposal::STATUS_CLOSED. Can't use constant into this generic class
             if ($this->element == 'fichinter' && $status == 3) $trigkey='FICHINTER_CLASSIFY_DONE';
             if ($this->element == 'fichinter' && $status == 2) $trigkey='FICHINTER_CLASSIFY_BILLED';
             if ($this->element == 'fichinter' && $status == 1) $trigkey='FICHINTER_CLASSIFY_UNBILLED';
-
+            
             if ($trigkey)
             {
                 // Appel des triggers
@@ -2830,12 +2837,14 @@ abstract class CommonObject
 			if (! $error)
 			{
 				$this->db->commit();
-        		if (empty($elementId))    // If the element we update was $this (so $elementId is null)
+				
+        		if (empty($savElementId))    // If the element we update was $this (so $elementId is null)
         		{
         		    $this->statut = $status;
         		    $this->status = $status;
         		}
-				return 1;
+
+                return 1;
 			}
 			else
 			{
@@ -3031,12 +3040,12 @@ abstract class CommonObject
      */
     function getTotalWeightVolume()
     {
-        $weightUnit=0;
-        $volumeUnit=0;
-        $totalWeight = '';
-        $totalVolume = '';
-        $totalOrdered = '';     // defined for shipment only
-        $totalToShip = '';      // defined for shipment only
+        $totalWeight = 0;
+        $totalVolume = 0;
+	    // defined for shipment only
+        $totalOrdered = '';
+	    // defined for shipment only
+        $totalToShip = '';
 
         foreach ($this->lines as $line)
         {
@@ -3051,11 +3060,18 @@ abstract class CommonObject
                 $totalToShip+=$line->qty_shipped;   // defined for shipment only
             }
 
-            // Define qty, weight, volume, weight_units, volume_units
-            if ($this->element == 'shipping') $qty=$line->qty_shipped;     // for shipments
-            else $qty=$line->qty;
-            $weight=$line->weight;
-            $volume=$line->volume;
+	        // Define qty, weight, volume, weight_units, volume_units
+	        if ($this->element == 'shipping') {
+		        // for shipments
+		        $qty = $line->qty_shipped ? $line->qty_shipped : 0;
+	        }
+	        else {
+		        $qty = $line->qty ? $line->qty : 0;
+	        }
+
+            $weight = $line->weight ? $line->weight : 0;
+            $volume = $line->volume ? $line->volume : 0;
+
             $weight_units=$line->weight_units;
             $volume_units=$line->volume_units;
 
@@ -3223,51 +3239,14 @@ abstract class CommonObject
 
     /**
      *  Return if a country is inside the EEC (European Economic Community)
-     *  TODO Add a field into dictionary
+     *  @deprecated
      *
      *  @return     boolean		true = country inside EEC, false = country outside EEC
      */
     function isInEEC()
     {
-        // List of all country codes that are in europe for european vat rules
-        // List found on http://ec.europa.eu/taxation_customs/common/faq/faq_1179_en.htm#9
-        $country_code_in_EEC=array(
-    			'AT',	// Austria
-    			'BE',	// Belgium
-    			'BG',	// Bulgaria
-    			'CY',	// Cyprus
-    			'CZ',	// Czech republic
-    			'DE',	// Germany
-    			'DK',	// Danemark
-    			'EE',	// Estonia
-    			'ES',	// Spain
-    			'FI',	// Finland
-    			'FR',	// France
-    			'GB',	// United Kingdom
-    			'GR',	// Greece
-    			'HR',   // Croatia
-                'NL',	// Holland
-    			'HU',	// Hungary
-    			'IE',	// Ireland
-    			'IM',	// Isle of Man - Included in UK
-    			'IT',	// Italy
-    			'LT',	// Lithuania
-    			'LU',	// Luxembourg
-    			'LV',	// Latvia
-    			'MC',	// Monaco - Included in France
-    			'MT',	// Malta
-                //'NO',	// Norway
-    			'PL',	// Poland
-    			'PT',	// Portugal
-    			'RO',	// Romania
-    			'SE',	// Sweden
-    			'SK',	// Slovakia
-    			'SI',	// Slovenia
-    			'UK',	// United Kingdom
-        //'CH',	// Switzerland - No. Swizerland in not in EEC
-        );
-        //print "dd".$this->country_code;
-        return in_array($this->country_code,$country_code_in_EEC);
+        require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php';
+        return isInEEC($this);
     }
 
 
@@ -3594,7 +3573,7 @@ abstract class CommonObject
         print '<tr class="liste_titre">';
         print '<td>'.$langs->trans('Ref').'</td>';
         print '<td>'.$langs->trans('Description').'</td>';
-        print '<td align="right">'.$langs->trans('VAT').'</td>';
+        print '<td align="right">'.$langs->trans('VATRate').'</td>';
         print '<td align="right">'.$langs->trans('PriceUHT').'</td>';
 		if (!empty($conf->multicurrency->enabled)) print '<td align="right">'.$langs->trans('PriceUHTCurrency').'</td>';
         print '<td align="right">'.$langs->trans('Qty').'</td>';
@@ -3731,7 +3710,10 @@ abstract class CommonObject
             $this->tpl['description'] = '&nbsp;';
         }
 
+        // VAT Rate
         $this->tpl['vat_rate'] = vatrate($line->tva_tx, true);
+        if (! empty($line->vat_src_code) && ! preg_match('/\(/', $this->tpl['vat_rate'])) $this->tpl['vat_rate'].=' ('.$line->vat_src_code.')';
+
         $this->tpl['price'] = price($line->subprice);
 		$this->tpl['multicurrency_price'] = price($line->multicurrency_subprice);
         $this->tpl['qty'] = (($line->info_bits & 2) != 2) ? $line->qty : '&nbsp;';
@@ -3754,21 +3736,6 @@ abstract class CommonObject
     }
 
 
-	/**
-	 * Show the array with all margin infos
-	 *
-	 * @param 		bool	$force_price	Force price
-	 * @return		void
-	 * @deprecated	3.8 Load FormMargin class and make a direct call to displayMarginInfos
-	 */
-	function displayMarginInfos($force_price=false)
-	{
-		include_once DOL_DOCUMENT_ROOT.'/core/class/html.formmargin.class.php';
-		$formmargin=new FormMargin($this->db);
-		$formmargin->displayMarginInfos($this, $force_price);
-	}
-
-
 	/**
 	 *	Add resources to the current object : add entry into llx_element_resources
 	 *	Need $this->element & $this->id
@@ -4711,4 +4678,372 @@ abstract class CommonObject
 		}
 		return $buyPrice;
 	}
+	
+	/**
+	 * Function test if type is date
+	 *
+	 * @param   array   $info   content informations of field
+	 * @return                  bool
+	 */
+	protected function isDate($info)
+	{
+		if(isset($info['type']) && $info['type']=='date') return true;
+		else return false;
+	}
+	
+	/**
+	 * Function test if type is array
+	 *
+	 * @param   array   $info   content informations of field
+	 * @return                  bool
+	 */
+	protected function isArray($info)
+	{
+		if(is_array($info))
+		{
+			if(isset($info['type']) && $info['type']=='array') return true;
+			else return false;
+		}
+		else return false;
+	}
+	
+	/**
+	 * Function test if type is null
+	 *
+	 * @param   array   $info   content informations of field
+	 * @return                  bool
+	 */
+	protected function isNull($info)
+	{
+		if(is_array($info))
+		{
+			if(isset($info['type']) && $info['type']=='null') return true;
+			else return false;
+		}
+		else return false;
+	}
+	
+	/**
+	 * Function test if type is integer
+	 *
+	 * @param   array   $info   content informations of field
+	 * @return                  bool
+	 */
+	protected function isInt($info)
+	{
+		if(is_array($info))
+		{
+			if(isset($info['type']) && ($info['type']=='int' || $info['type']=='integer' )) return true;
+			else return false;
+		}
+		else return false;
+	}
+	
+	/**
+	 * Function test if type is float
+	 *
+	 * @param   array   $info   content informations of field
+	 * @return                  bool
+	 */
+	protected function isFloat($info)
+	{
+		if(is_array($info))
+		{
+			if(isset($info['type']) && $info['type']=='float') return true;
+			else return false;
+		}
+		else return false;
+	}
+	
+	/**
+	 * Function test if type is text
+	 *
+	 * @param   array   $info   content informations of field
+	 * @return                  bool
+	 */
+	protected function isText($info)
+	{
+		if(is_array($info))
+		{
+			if(isset($info['type']) && $info['type']=='text') return true;
+			else return false;
+		}
+		else return false;
+	}
+	
+	/**
+	 * Function test if is indexed
+	 *
+	 * @param   array   $info   content informations of field
+	 * @return                  bool
+	 */
+	protected function isIndex($info)
+	{
+		if(is_array($info))
+		{
+			if(isset($info['index']) && $info['index']==true) return true;
+			else return false;
+		}
+		else return false;
+	}
+	
+	/**
+	 * Function to prepare the values to insert
+	 *
+	 * @return array
+	 */
+	private function set_save_query()
+	{
+		$query=array();
+		foreach ($this->fields as $field=>$info)
+		{
+			if($this->isDate($info))
+			{
+				if(empty($this->{$field}))
+				{
+					$query[$field] = NULL;
+				}
+				else
+				{
+					$query[$field] = $this->db->idate($this->{$field});
+				}
+			}
+			else if($this->isArray($info))
+			{
+				$query[$field] = serialize($this->{$field});
+			}
+			else if($this->isInt($info))
+			{
+				$query[$field] = (int) price2num($this->{$field});
+			}
+			else if($this->isFloat($info))
+			{
+				$query[$field] = (double) price2num($this->{$field});
+			}
+			elseif($this->isNull($info))
+			{
+				$query[$field] = (is_null($this->{$field}) || (empty($this->{$field}) && $this->{$field}!==0 && $this->{$field}!=='0') ? null : $this->{$field});
+			}
+			else
+			{
+				$query[$field] = $this->{$field};
+			}
+		}
+		
+		return $query;
+	}
+
+	/**
+	 * Create object into database
+	 *
+	 * @param  User $user      User that creates
+	 * @param  bool $notrigger false=launch triggers after, true=disable triggers
+	 *
+	 * @return int <0 if KO, Id of created object if OK
+	 */
+	public function createCommon(User $user, $notrigger = false)
+	{
+	    
+	    $fields = array_merge(array('datec'=>$this->db->idate(dol_now())), $this->set_save_query());
+	    
+	    foreach ($fields as $k => $v) {
+	    	
+	    	$keys[] = $k;
+	    	$values[] = $this->quote($v);
+	    	
+	    }
+	    $sql = 'INSERT INTO '.MAIN_DB_PREFIX.$this->table_element.'
+					( '.implode( ",", $keys ).' )
+					VALUES ( '.implode( ",", $values ).' ) ';
+	    $res = $this->db->query( $sql );
+	    if($res===false) {
+	    	
+	    	return false;
+	    }
+	    
+	    // TODO Add triggers
+	    
+	    return true;
+	    
+	}
+	
+	/**
+	 * Function to load data into current object this
+	 *
+	 * @param   stdClass    $obj    Contain data of object from database
+	 */
+	private function set_vars_by_db(&$obj)
+	{
+		foreach ($this->fields as $field => $info)
+		{
+			if($this->isDate($info))
+			{
+				if(empty($obj->{$field}) || $obj->{$field} === '0000-00-00 00:00:00' || $obj->{$field} === '1000-01-01 00:00:00') $this->{$field} = 0;
+				else $this->{$field} = strtotime($obj->{$field});
+			}
+			elseif($this->isArray($info))
+			{
+				$this->{$field} = @unserialize($obj->{$field});
+				// Hack for data not in UTF8
+				if($this->{$field } === FALSE) @unserialize(utf8_decode($obj->{$field}));
+			}
+			elseif($this->isInt($info))
+			{
+				$this->{$field} = (int) $obj->{$field};
+			}
+			elseif($this->isFloat($info))
+			{
+				$this->{$field} = (double) $obj->{$field};
+			}
+			elseif($this->isNull($info))
+			{
+				$val = $obj->{$field};
+				// zero is not null
+				$this->{$field} = (is_null($val) || (empty($val) && $val!==0 && $val!=='0') ? null : $val);
+			}
+			else
+			{
+				$this->{$field} = $obj->{$field};
+			}
+			
+		}
+	}
+	
+	/**
+	 * Function to concat keys of fields
+	 *
+	 * @return string
+	 */
+	private function get_field_list()
+	{
+		$keys = array_keys($this->fields);
+		return implode(',', $keys);
+	}
+	
+	/**
+	 * Load object in memory from the database
+	 *
+	 * @param int    $id  Id object
+	 * @param string $ref Ref
+	 *
+	 * @return int <0 if KO, 0 if not found, >0 if OK
+	 */
+	public function fetchCommon($id, $ref = null)
+	{
+	    
+		if (empty($id) && empty($ref)) return false;
+		
+		$sql = 'SELECT '.$this->get_field_list().', datec, tms';
+		$sql.= ' FROM '.MAIN_DB_PREFIX.$this->table_element;
+		
+		if(!empty($id)) $sql.= ' WHERE rowid = '.$id;
+		else  $sql.= ' WHERE ref = \''.$this->quote($ref).'\'';
+
+		$res = $this->db->query($sql);
+		if ($res)
+		{
+    		if ($obj = $this->db->fetch_object($res))
+    		{
+    			$this->id = $id;
+    			$this->set_vars_by_db($obj);
+    			
+    			$this->datec = $this->db->idate($obj->datec);
+    			$this->tms = $this->db->idate($obj->tms);
+    			
+    			return $this->id;
+    		}
+    		else
+    		{
+    			$this->error = $this->db->lasterror();
+    			$this->errors[] = $this->error;
+    			return -1;
+    		}
+		}
+		else
+		{
+		    $this->error = $this->db->lasterror();
+		    $this->errors[] = $this->error;
+		    return -1;
+		}
+	}
+
+	/**
+	 * Update object into database
+	 *
+	 * @param  User $user      User that modifies
+	 * @param  bool $notrigger false=launch triggers after, true=disable triggers
+	 *
+	 * @return int <0 if KO, >0 if OK
+	 */
+	public function updateCommon(User $user, $notrigger = false)
+	{
+		$fields = $this->set_save_query();
+		
+		foreach ($fields as $k => $v) {
+			
+			if (is_array($key)){
+				$i=array_search($k, $key);
+				if ( $i !== false) {
+					$where[] = $key[$i].'=' . $this->quote( $v ) ;
+					continue;
+				}
+			} else {
+				if ( $k == $key) {
+					$where[] = $k.'=' .$this->quote( $v ) ;
+					continue;
+				}
+			}
+			
+			$tmp[] = $k.'='.$this->quote($v);
+		}
+		$sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element.' SET '.implode( ',', $tmp ).' WHERE rowid='.$this->id ;
+		$res = $this->db->query( $sql );
+		
+		if($res===false) {
+			//error
+			return false;
+		}
+		
+		// TODO Add triggers
+		
+		return true;
+	}
+	
+	/**
+	 * Delete object in database
+	 *
+	 * @param User $user      User that deletes
+	 * @param bool $notrigger false=launch triggers after, true=disable triggers
+	 *
+	 * @return int <0 if KO, >0 if OK
+	 */
+	public function deleteCommon(User $user, $notrigger = false)
+	{
+		$sql = 'DELETE FROM '.MAIN_DB_PREFIX.$this->table_element.' WHERE rowid='.$this->id;
+		
+		$res = $this->db->query( $sql );
+		if($res===false) {
+			return false;
+		}
+		
+		// TODO Add triggers
+		
+		return true;
+	}
+
+	/**
+	 * Add quote to field value if necessary
+	 *
+	 * @param string|int	$value	value to protect
+	 * @return string|int
+	 */
+	protected function quote($value) {
+	
+	    if(is_null($value)) return 'NULL';
+	    else if(is_numeric($value)) return $value;
+	    else return "'".$this->db->escape( $value )."'";
+	
+	}
+	
 }
+

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

@@ -210,7 +210,7 @@ class Conf
                 $file=dol_sanitizeFileName($file);
                 include_once DOL_DOCUMENT_ROOT . "/".$file."/".$file."_consts.php";
                 foreach ($file2bddconsts as $key=>$value) {
-                    $this->global->$key=constant($value);
+                    $this->global->$key=$value;
                 }
             }
         }
@@ -358,8 +358,8 @@ class Conf
     			$this->supplier_order->dir_temp=$rootfordata."/fournisseur/commande/temp";
     			$this->supplier_invoice=new stdClass();
     			$this->supplier_invoice->enabled=1;
-    			$this->supplier_order->dir_output=$rootfordata."/fournisseur/facture";
-    			$this->supplier_order->dir_temp=$rootfordata."/fournisseur/facture/temp";
+    			$this->supplier_invoice->dir_output=$rootfordata."/fournisseur/facture";
+    			$this->supplier_invoice->dir_temp=$rootfordata."/fournisseur/facture/temp";
 			}
 		}
 

+ 438 - 0
htdocs/core/class/coreobject.class.php

@@ -0,0 +1,438 @@
+<?php
+/* EXPERIMENTAL
+ * 
+ * Copyright (C) 2016		ATM Consulting			<support@atm-consulting.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ *	\file       htdocs/core/class/coreobject.class.php
+ *	\ingroup    core
+ *	\brief      File of class to manage all object. Might be replace or merge into commonobject
+ */
+ 
+require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php';
+
+class CoreObject extends CommonObject
+{
+	public $withChild = true;
+
+	/**
+	 *  @var Array $_fields Fields to synchronize with Database
+	 */
+	protected $fields=array();
+
+    /**
+	 *  Constructor
+	 *
+	 *  @param      DoliDB		$db      Database handler
+	 */
+	function __construct(DoliDB &$db)
+    {
+        $this->db = $db;
+	}
+
+    /**
+     * Function to init fields
+     *
+     * @return bool
+     */
+	protected function init()
+    {
+		$this->id = 0;
+		$this->datec = 0;
+		$this->tms = 0;
+		
+		if (!empty($this->fields))
+		{
+			foreach ($this->fields as $field=>$info)
+			{
+		        if ($this->isDate($info)) $this->{$field} = time();
+		        elseif ($this->isArray($info)) $this->{$field} = array();
+		        elseif ($this->isInt($info)) $this->{$field} = (int) 0;
+		        elseif ($this->isFloat($info)) $this->{$field} = (double) 0;
+				else $this->{$field} = '';
+		    }
+
+            $this->to_delete=false;
+            $this->is_clone=false;
+			
+			return true;
+		}
+		else
+        {
+			return false;
+		}
+			
+	}
+
+    /**
+     * Test type of field
+     *
+     * @param   string  $field  name of field
+     * @param   string  $type   type of field to test
+     * @return                  value of field or false
+     */
+    private function checkFieldType($field, $type)
+    {
+		if (isset($this->fields[$field]) && method_exists($this, 'is_'.$type))
+		{
+			return $this->{'is_'.$type}($this->fields[$field]);
+		}
+		else
+        {
+            return false;
+        }
+	}
+
+    /**
+     *	Get object and children from database
+     *
+     *	@param      int			$id       		Id of object to load
+     * 	@param		bool		$loadChild		used to load children from database
+     *	@return     int         				>0 if OK, <0 if KO, 0 if not found
+     */
+	public function fetch($id, $loadChild = true)
+    {
+    	$res = $this->fetchCommon($id);
+    	if($res>0) {
+    		if ($loadChild) $this->fetchChild();
+    	}
+    	
+    	return $res;
+	}
+
+
+    /**
+     * Function to instantiate a new child
+     *
+     * @param   string  $tabName        Table name of child
+     * @param   int     $id             If id is given, we try to return his key if exist or load if we try_to_load
+     * @param   string  $key            Attribute name of the object id
+     * @param   bool    $try_to_load    Force the fetch if an id is given
+     * @return                          int
+     */
+    public function addChild($tabName, $id=0, $key='id', $try_to_load = false)
+    {
+		if(!empty($id))
+		{
+			foreach($this->{$tabName} as $k=>&$object)
+			{
+				if($object->{$key} === $id) return $k;
+			}
+		}
+	
+		$k = count($this->{$tabName});
+	
+		$className = ucfirst($tabName);
+		$this->{$tabName}[$k] = new $className($this->db);
+		if($id>0 && $key==='id' && $try_to_load)
+		{
+			$this->{$tabName}[$k]->fetch($id); 
+		}
+
+		return $k;
+	}
+
+
+    /**
+     * Function to set a child as to delete
+     *
+     * @param   string  $tabName        Table name of child
+     * @param   int     $id             Id of child to set as to delete
+     * @param   string  $key            Attribute name of the object id
+     * @return                          bool
+     */
+    public function removeChild($tabName, $id, $key='id')
+    {
+		foreach ($this->{$tabName} as &$object)
+		{
+			if ($object->{$key} == $id)
+			{
+				$object->to_delete = true;
+				return true;
+			}
+		}
+		return false;
+	}
+
+
+    /**
+     * Function to fetch children objects
+     */
+    public function fetchChild()
+    {
+		if($this->withChild && !empty($this->childtables) && !empty($this->fk_element))
+		{
+			foreach($this->childtables as &$childTable)
+			{
+                $className = ucfirst($childTable);
+
+                $this->{$className}=array();
+
+                $sql = 'SELECT rowid FROM '.MAIN_DB_PREFIX.$childTable.' WHERE '.$this->fk_element.' = '.$this->id;
+                $res = $this->db->query($sql);
+
+                if($res)
+                {
+                    while($obj = $this->db->fetch_object($res))
+                    {
+                        $o=new $className($this->db);
+                        $o->fetch($obj->rowid);
+
+                        $this->{$className}[] = $o;
+                    }
+                }
+                else
+                {
+                    $this->errors[] = $this->db->lasterror();
+                }
+			}
+		}
+	}
+
+    /**
+     * Function to update children data
+     *
+     * @param   User    $user   user object
+     */
+	public function saveChild(User &$user)
+    {
+		if($this->withChild && !empty($this->childtables) && !empty($this->fk_element))
+		{
+			foreach($this->childtables as &$childTable)
+			{
+				$className = ucfirst($childTable);
+				if(!empty($this->{$className}))
+				{
+					foreach($this->{$className} as $i => &$object)
+					{
+						$object->{$this->fk_element} = $this->id;
+						
+						$object->update($user);
+						if($this->unsetChildDeleted && isset($object->to_delete) && $object->to_delete==true) unset($this->{$className}[$i]);
+					}
+				}
+			}
+		}
+	}
+
+
+    /**
+     * Function to update object or create or delete if needed
+     *
+     * @param   User    $user   user object
+     * @return                  < 0 if ko, > 0 if ok
+     */
+    public function update(User &$user)
+    {
+		if (empty($this->id)) return $this->create($user); // To test, with that, no need to test on high level object, the core decide it, update just needed
+        elseif (isset($this->to_delete) && $this->to_delete==true) return $this->delete($user);
+
+        $error = 0;
+        $this->db->begin();
+
+        $res = $this->updateCommon($user);
+        if ($res)
+        {
+            $result = $this->call_trigger(strtoupper($this->element). '_UPDATE', $user);
+            if ($result < 0) $error++;
+            else $this->saveChild($user);
+        }
+        else
+        {
+            $error++;
+            $this->error = $this->db->lasterror();
+            $this->errors[] = $this->error;
+        }
+
+        if (empty($error))
+        {
+            $this->db->commit();
+            return $this->id;
+        }
+        else
+        {
+            $this->db->rollback();
+            return -1;
+        }
+
+	}
+
+    /**
+     * Function to create object in database
+     *
+     * @param   User    $user   user object
+     * @return                  < 0 if ko, > 0 if ok
+     */
+    public function create(User &$user)
+    {
+		if($this->id > 0) return $this->update($user);
+
+        $error = 0;
+        $this->db->begin();
+
+        $res = $this->createCommon($user);
+		if($res)
+		{
+			$this->id = $this->db->last_insert_id($this->table_element);
+
+			$result = $this->call_trigger(strtoupper($this->element). '_CREATE', $user);
+            if ($result < 0) $error++;
+            else $this->saveChild($user);
+		}
+		else
+        {
+            $error++;
+            $this->error = $this->db->lasterror();
+            $this->errors[] = $this->error;
+		}
+
+        if (empty($error))
+        {
+            $this->db->commit();
+            return $this->id;
+        }
+        else
+        {
+            $this->db->rollback();
+            return -1;
+        }
+	}
+
+    /**
+     * Function to delete object in database
+     *
+     * @param   User    $user   user object
+     * @return                  < 0 if ko, > 0 if ok
+     */
+	public function delete(User &$user)
+    {
+		if ($this->id <= 0) return 0;
+
+        $error = 0;
+        $this->db->begin();
+
+        $result = $this->call_trigger(strtoupper($this->element). '_DELETE', $user);
+        if ($result < 0) $error++;
+
+        if (!$error)
+        {
+            $this->deleteCommon($user);
+            if($this->withChild && !empty($this->childtables))
+            {
+                foreach($this->childtables as &$childTable)
+                {
+                    $className = ucfirst($childTable);
+                    if (!empty($this->{$className}))
+                    {
+                        foreach($this->{$className} as &$object)
+                        {
+                            $object->delete($user);
+                        }
+                    }
+                }
+            }
+        }
+
+        if (empty($error))
+        {
+            $this->db->commit();
+            return 1;
+        }
+        else
+        {
+            $this->error = $this->db->lasterror();
+            $this->errors[] = $this->error;
+            $this->db->rollback();
+            return -1;
+        }
+	}
+
+
+    /**
+     * Function to get a formatted date
+     *
+     * @param   string  $field  Attribute to return
+     * @param   string  $format Output date format
+     * @return          string
+     */
+    public function getDate($field, $format='')
+    {
+		if(empty($this->{$field})) return '';
+		else
+        {
+			return dol_print_date($this->{$field}, $format);
+		}
+	}
+
+    /**
+     * Function to set date in field
+     *
+     * @param   string  $field  field to set
+     * @param   string  $date   formatted date to convert
+     * @return                  mixed
+     */
+    public function setDate($field, $date)
+    {
+	  	if (empty($date))
+	  	{
+	  		$this->{$field} = 0;
+	  	}
+		else
+        {
+			require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
+			$this->{$field} = dol_stringtotime($date);
+		}
+
+		return $this->{$field};
+	}
+
+
+    /**
+     * Function to update current object
+     *
+     * @param   array   $Tab    Array of values
+     * @return                  int
+     */
+    public function setValues(&$Tab)
+    {
+		foreach ($Tab as $key => $value)
+		{
+			if($this->checkFieldType($key, 'date'))
+			{
+				$this->setDate($key, $value);
+			}
+			else if( $this->checkFieldType($key, 'array'))
+			{
+				$this->{$key} = $value;
+			}
+			else if( $this->checkFieldType($key, 'float') )
+			{
+				$this->{$key} = (double) price2num($value);
+			}
+			else if( $this->checkFieldType($key, 'int') ) {
+				$this->{$key} = (int) price2num($value);
+			}
+			else
+            {
+				$this->{$key} = $value;
+			}
+		}
+
+		return 1;
+	}
+
+}

+ 500 - 0
htdocs/core/class/ctyperesource.class.php

@@ -0,0 +1,500 @@
+<?php
+/* Copyright (C) 2007-2012  Laurent Destailleur <eldy@users.sourceforge.net>
+ * Copyright (C) 2014-2016  Juanjo Menent       <jmenent@2byte.es>
+ * Copyright (C) 2016       Florian Henry       <florian.henry@atm-consulting.fr>
+ * Copyright (C) 2015       Raphaël Doursenaud  <rdoursenaud@gpcsolutions.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file    resource/ctyperesource.class.php
+ * \ingroup resource
+ */
+
+/**
+ * Class Ctyperesource
+ *
+ * Put here description of your class
+ *
+ * @see CommonObject
+ */
+class Ctyperesource
+{
+	/**
+	 * @var string Id to identify managed objects
+	 */
+	public $element = 'ctyperesource';
+	/**
+	 * @var string Name of table without prefix where object is stored
+	 */
+	public $table_element = 'c_type_resource';
+
+	/**
+	 * @var CtyperesourceLine[] Lines
+	 */
+	public $lines = array();
+
+	/**
+	 */
+	
+	public $code;
+	public $label;
+	public $active;
+
+	/**
+	 */
+	
+
+	/**
+	 * Constructor
+	 *
+	 * @param DoliDb $db Database handler
+	 */
+	public function __construct(DoliDB $db)
+	{
+		$this->db = $db;
+	}
+
+	/**
+	 * Create object into database
+	 *
+	 * @param  User $user      User that creates
+	 * @param  bool $notrigger false=launch triggers after, true=disable triggers
+	 *
+	 * @return int <0 if KO, Id of created object if OK
+	 */
+	public function create(User $user, $notrigger = false)
+	{
+		dol_syslog(__METHOD__, LOG_DEBUG);
+
+		$error = 0;
+
+		// Clean parameters
+		
+		if (isset($this->code)) {
+			 $this->code = trim($this->code);
+		}
+		if (isset($this->label)) {
+			 $this->label = trim($this->label);
+		}
+		if (isset($this->active)) {
+			 $this->active = trim($this->active);
+		}
+
+		
+
+		// Check parameters
+		// Put here code to add control on parameters values
+
+		// Insert request
+		$sql = 'INSERT INTO ' . MAIN_DB_PREFIX . $this->table_element . '(';
+		
+		$sql.= 'code,';
+		$sql.= 'label';
+		$sql.= 'active';
+
+		
+		$sql .= ') VALUES (';
+		
+		$sql .= ' '.(! isset($this->code)?'NULL':"'".$this->db->escape($this->code)."'").',';
+		$sql .= ' '.(! isset($this->label)?'NULL':"'".$this->db->escape($this->label)."'").',';
+		$sql .= ' '.(! isset($this->active)?'NULL':$this->active);
+
+		
+		$sql .= ')';
+
+		$this->db->begin();
+
+		$resql = $this->db->query($sql);
+		if (!$resql) {
+			$error ++;
+			$this->errors[] = 'Error ' . $this->db->lasterror();
+			dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR);
+		}
+
+		if (!$error) {
+			$this->id = $this->db->last_insert_id(MAIN_DB_PREFIX . $this->table_element);
+
+			if (!$notrigger) {
+				// Uncomment this and change MYOBJECT to your own tag if you
+				// want this action to call a trigger.
+
+				//// Call triggers
+				//$result=$this->call_trigger('MYOBJECT_CREATE',$user);
+				//if ($result < 0) $error++;
+				//// End call triggers
+			}
+		}
+
+		// Commit or rollback
+		if ($error) {
+			$this->db->rollback();
+
+			return - 1 * $error;
+		} else {
+			$this->db->commit();
+
+			return $this->id;
+		}
+	}
+
+	/**
+	 * Load object in memory from the database
+	 *
+	 * @param int    $id  Id object
+	 * @param string $code code
+	 * @param string $label Label
+	 *
+	 * @return int <0 if KO, 0 if not found, >0 if OK
+	 */
+	public function fetch($id,$code='',$label='')
+	{
+		dol_syslog(__METHOD__, LOG_DEBUG);
+
+		$sql = 'SELECT';
+		$sql .= ' t.rowid,';
+		
+		$sql .= " t.code,";
+		$sql .= " t.label,";
+		$sql .= " t.active";
+
+		
+		$sql .= ' FROM ' . MAIN_DB_PREFIX . $this->table_element . ' as t';
+		if ($id)   $sql.= " WHERE t.id = ".$id;
+		elseif ($code) $sql.= " WHERE t.code = '".$this->db->escape($code)."'";
+		elseif ($label) $sql.= " WHERE t.label = '".$this->db->escape($label)."'";
+		
+		
+		$resql = $this->db->query($sql);
+		if ($resql) {
+			$numrows = $this->db->num_rows($resql);
+			if ($numrows) {
+				$obj = $this->db->fetch_object($resql);
+
+				$this->id = $obj->rowid;
+				
+				$this->code = $obj->code;
+				$this->label = $obj->label;
+				$this->active = $obj->active;
+
+				
+			}
+			
+			// Retrieve all extrafields for invoice
+			// fetch optionals attributes and labels
+			/*
+			require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
+			$extrafields=new ExtraFields($this->db);
+			$extralabels=$extrafields->fetch_name_optionals_label($this->table_element,true);
+			$this->fetch_optionals($this->id,$extralabels);
+            */
+			
+			// $this->fetch_lines();
+			
+			$this->db->free($resql);
+
+			if ($numrows) {
+				return 1;
+			} else {
+				return 0;
+			}
+		} else {
+			$this->errors[] = 'Error ' . $this->db->lasterror();
+			dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR);
+
+			return - 1;
+		}
+	}
+
+	/**
+	 * Load object in memory from the database
+	 *
+	 * @param string $sortorder Sort Order
+	 * @param string $sortfield Sort field
+	 * @param int    $limit     offset limit
+	 * @param int    $offset    offset limit
+	 * @param array  $filter    filter array
+	 * @param string $filtermode filter mode (AND or OR)
+	 *
+	 * @return int <0 if KO, >0 if OK
+	 */
+	public function fetchAll($sortorder='', $sortfield='', $limit=0, $offset=0, array $filter = array(), $filtermode='AND')
+	{
+		dol_syslog(__METHOD__, LOG_DEBUG);
+
+		$sql = 'SELECT';
+		$sql .= ' t.rowid,';
+		
+		$sql .= " t.code,";
+		$sql .= " t.label,";
+		$sql .= " t.active";
+
+		
+		$sql .= ' FROM ' . MAIN_DB_PREFIX . $this->table_element. ' as t';
+
+		// Manage filter
+		$sqlwhere = array();
+		if (count($filter) > 0) {
+			foreach ($filter as $key => $value) {
+				$sqlwhere [] = $key . ' LIKE \'%' . $this->db->escape($value) . '%\'';
+			}
+		}
+		
+		if (count($sqlwhere) > 0) {
+			$sql .= ' WHERE ' . implode(' '.$filtermode.' ', $sqlwhere);
+		}
+		if (!empty($sortfield)) {
+			$sql .= $this->db->order($sortfield,$sortorder);
+		}
+		if (!empty($limit)) {
+		 $sql .=  ' ' . $this->db->plimit($limit, $offset);
+		}
+
+		$resql = $this->db->query($sql);
+		if ($resql) {
+			$num = $this->db->num_rows($resql);
+
+			while ($obj = $this->db->fetch_object($resql)) {
+				$line = new self($this->db);
+
+				$line->id = $obj->rowid;
+				
+				$line->code = $obj->code;
+				$line->label = $obj->label;
+				$line->active = $obj->active;
+
+				
+			}
+			$this->db->free($resql);
+
+			return $num;
+		} else {
+			$this->errors[] = 'Error ' . $this->db->lasterror();
+			dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR);
+
+			return - 1;
+		}
+	}
+
+	/**
+	 * Update object into database
+	 *
+	 * @param  User $user      User that modifies
+	 * @param  bool $notrigger false=launch triggers after, true=disable triggers
+	 *
+	 * @return int <0 if KO, >0 if OK
+	 */
+	public function update(User $user, $notrigger = false)
+	{
+		$error = 0;
+
+		dol_syslog(__METHOD__, LOG_DEBUG);
+
+		// Clean parameters
+		
+		if (isset($this->code)) {
+			 $this->code = trim($this->code);
+		}
+		if (isset($this->label)) {
+			 $this->label = trim($this->label);
+		}
+		if (isset($this->active)) {
+			 $this->active = trim($this->active);
+		}
+
+		// Check parameters
+		// Put here code to add a control on parameters values
+
+		// Update request
+		$sql = 'UPDATE ' . MAIN_DB_PREFIX . $this->table_element . ' SET';
+		
+		$sql .= ' code = '.(isset($this->code)?"'".$this->db->escape($this->code)."'":"null").',';
+		$sql .= ' label = '.(isset($this->label)?"'".$this->db->escape($this->label)."'":"null").',';
+		$sql .= ' active = '.(isset($this->active)?$this->active:"null");
+
+        
+		$sql .= ' WHERE rowid=' . $this->id;
+
+		$this->db->begin();
+
+		$resql = $this->db->query($sql);
+		if (!$resql) {
+			$error ++;
+			$this->errors[] = 'Error ' . $this->db->lasterror();
+			dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR);
+		}
+
+		if (!$error && !$notrigger) {
+			// Uncomment this and change MYOBJECT to your own tag if you
+			// want this action calls a trigger.
+
+			//// Call triggers
+			//$result=$this->call_trigger('MYOBJECT_MODIFY',$user);
+			//if ($result < 0) { $error++; //Do also what you must do to rollback action if trigger fail}
+			//// End call triggers
+		}
+
+		// Commit or rollback
+		if ($error) {
+			$this->db->rollback();
+
+			return - 1 * $error;
+		} else {
+			$this->db->commit();
+
+			return 1;
+		}
+	}
+
+	/**
+	 * Delete object in database
+	 *
+	 * @param User $user      User that deletes
+	 * @param bool $notrigger false=launch triggers after, true=disable triggers
+	 *
+	 * @return int <0 if KO, >0 if OK
+	 */
+	public function delete(User $user, $notrigger = false)
+	{
+		dol_syslog(__METHOD__, LOG_DEBUG);
+
+		$error = 0;
+
+		$this->db->begin();
+
+		if (!$error) {
+			if (!$notrigger) {
+				// Uncomment this and change MYOBJECT to your own tag if you
+				// want this action calls a trigger.
+
+				//// Call triggers
+				//$result=$this->call_trigger('MYOBJECT_DELETE',$user);
+				//if ($result < 0) { $error++; //Do also what you must do to rollback action if trigger fail}
+				//// End call triggers
+			}
+		}
+
+		// If you need to delete child tables to, you can insert them here
+		
+		if (!$error) {
+			$sql = 'DELETE FROM ' . MAIN_DB_PREFIX . $this->table_element;
+			$sql .= ' WHERE rowid=' . $this->id;
+
+			$resql = $this->db->query($sql);
+			if (!$resql) {
+				$error ++;
+				$this->errors[] = 'Error ' . $this->db->lasterror();
+				dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR);
+			}
+		}
+
+		// Commit or rollback
+		if ($error) {
+			$this->db->rollback();
+
+			return - 1 * $error;
+		} else {
+			$this->db->commit();
+
+			return 1;
+		}
+	}
+
+	/**
+	 * Load an object from its id and create a new one in database
+	 *
+	 * @param int $fromid Id of object to clone
+	 *
+	 * @return int New id of clone
+	 */
+	public function createFromClone($fromid)
+	{
+		dol_syslog(__METHOD__, LOG_DEBUG);
+
+		global $user;
+		$error = 0;
+		$object = new Ctyperesource($this->db);
+
+		$this->db->begin();
+
+		// Load source object
+		$object->fetch($fromid);
+		// Reset object
+		$object->id = 0;
+
+		// Clear fields
+		// ...
+
+		// Create clone
+		$result = $object->create($user);
+
+		// Other options
+		if ($result < 0) {
+			$error ++;
+			$this->errors = $object->errors;
+			dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR);
+		}
+
+		// End
+		if (!$error) {
+			$this->db->commit();
+
+			return $object->id;
+		} else {
+			$this->db->rollback();
+
+			return - 1;
+		}
+	}
+
+	/**
+	 * Initialise object with example values
+	 * Id must be 0 if object instance is a specimen
+	 *
+	 * @return void
+	 */
+	public function initAsSpecimen()
+	{
+		$this->id = 0;
+		
+		$this->code = '';
+		$this->label = '';
+		$this->active = '';
+	}
+
+}
+
+/**
+ * Class CtyperesourceLine
+ */
+class CtyperesourceLine
+{
+	/**
+	 * @var int ID
+	 */
+	public $id;
+	/**
+	 * @var mixed Sample line property 1
+	 */
+	
+	public $code;
+	public $label;
+	public $active;
+
+	/**
+	 * @var mixed Sample line property 2
+	 */
+	
+}

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