Bläddra i källkod

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

Laurent Destailleur 2 år sedan
förälder
incheckning
d36acc63dd

+ 78 - 0
htdocs/adherents/class/adherentstats.class.php

@@ -171,4 +171,82 @@ class AdherentStats extends Stats
 
 		return $this->_getAllByYear($sql);
 	}
+
+
+
+	/**
+	 *	Return count of member by status group by adh type, total and average
+	 *
+	 * 	@param		int	$numberYears    Years to scan
+	 * 	@return		array 	Array with total of draft, pending, uptodate, expired, resiliated for each member tag
+	 */
+	public function countMembersByTagAndStatus($numberYears = 2)
+	{
+		global $user;
+
+		$now = dol_now();
+		$endYear = date('Y');
+		$startYear = $endYear - $numberYears;
+
+		$sql = "SELECT c.rowid as fk_categorie, c.label as label";
+		$sql .= ", COUNT(".$this->db->ifsql("d.statut = ".Adherent::STATUS_DRAFT, "'members_draft'", 'NULL').") as members_draft";
+		$sql .= ", COUNT(".$this->db->ifsql("d.statut = ".Adherent::STATUS_VALIDATED."  AND (d.datefin IS NULL AND t.subscription = '1')", "'members_pending'", 'NULL').") as members_pending";
+		$sql .= ", COUNT(".$this->db->ifsql("d.statut = ".Adherent::STATUS_VALIDATED."  AND (d.datefin >= '".$this->db->idate($now)."' OR t.subscription = 0)", "'members_uptodate'", 'NULL').") as members_uptodate";
+		$sql .= ", COUNT(".$this->db->ifsql("d.statut = ".Adherent::STATUS_VALIDATED."  AND (d.datefin < '".$this->db->idate($now)."' AND t.subscription = 1)", "'members_expired'", 'NULL').") as members_expired";
+		$sql .= ", COUNT(".$this->db->ifsql("d.statut = ".Adherent::STATUS_EXCLUDED, "'members_excluded'", 'NULL').") as members_excluded";
+		$sql .= ", COUNT(".$this->db->ifsql("d.statut = ".Adherent::STATUS_RESILIATED, "'members_resiliated'", 'NULL').") as members_resiliated";
+		$sql .= " FROM ".MAIN_DB_PREFIX."categorie as c";
+		$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."categorie_member as ct ON c.rowid = ct.fk_categorie";
+		$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."adherent as d ON d.rowid = ct.fk_member";
+		$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."adherent_type as t ON t.rowid = d.fk_adherent_type";
+		$sql .= " WHERE c.entity IN (".getEntity('member_type').")";
+		$sql .= " AND d.entity IN (" . getEntity('adherent') . ")";
+		$sql .= " AND t.entity IN (" . getEntity('adherent') . ")";
+		$sql .= " AND d.datefin > '".$this->db->idate(dol_get_first_day($startYear))."'";
+		$sql .= " AND c.fk_parent = 0";
+		$sql .= " GROUP BY c.rowid";
+
+		dol_syslog("box_members_by_type::select nb of members per type", LOG_DEBUG);
+		$result = $this->db->query($sql);
+
+		if ($result) {
+			$num = $this->db->num_rows($result);
+			$i = 0;
+			$MembersCountArray = [];
+			$totalstatus = array(
+				'label' => 'Total',
+				'members_draft' => 0,
+				'members_pending' => 0,
+				'members_uptodate' => 0,
+				'members_expired' => 0,
+				'members_excluded' => 0,
+				'members_resiliated' => 0
+			);
+			while ($i < $num) {
+				$objp = $this->db->fetch_object($result);
+				$MembersCountArray[$objp->fk_categorie] = array(
+					'label' => $objp->label,
+					'members_draft' => (int) $objp->members_draft,
+					'members_pending' => (int) $objp->members_pending,
+					'members_uptodate' => (int) $objp->members_uptodate,
+					'members_expired' => (int) $objp->members_expired,
+					'members_excluded' => (int) $objp->members_excluded,
+					'members_resiliated' => (int) $objp->members_resiliated
+				);
+				$totalrow = 0;
+				foreach ($MembersCountArray[$objp->fk_categorie] as $key=>$nb) {
+					if ($key!='label') {
+						$totalrow += $nb;
+						$totalstatus[$key] += $nb;
+					}
+				}
+				$MembersCountArray[$objp->fk_categorie]['total_adhtype'] = $totalrow;
+				$i++;
+			}
+			$this->db->free($result);
+			$MembersCountArray['total'] = $totalstatus;
+			$MembersCountArray['total']['all'] = array_sum($totalstatus);
+		}
+		return $MembersCountArray;
+	}
 }

+ 34 - 29
htdocs/adherents/list.php

@@ -30,9 +30,9 @@
 
 // Load Dolibarr environment
 require '../main.inc.php';
-require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php';
 require_once DOL_DOCUMENT_ROOT.'/adherents/class/adherent.class.php';
 require_once DOL_DOCUMENT_ROOT.'/adherents/class/adherent_type.class.php';
+require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php';
 require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php';
 
 
@@ -41,47 +41,51 @@ $langs->loadLangs(array("members", "companies"));
 
 
 // Get parameters
-$action = GETPOST('action', 'aZ09');
+$action 	= GETPOST('action', 'aZ09');
 $massaction = GETPOST('massaction', 'alpha');
 $show_files = GETPOST('show_files', 'int');
-$confirm = GETPOST('confirm', 'alpha');
-$toselect = GETPOST('toselect', 'array');
+$confirm 	= GETPOST('confirm', 'alpha');
+$cancel     = GETPOST('cancel', 'alpha');
+$toselect 	= GETPOST('toselect', 'array');
 $contextpage = GETPOST('contextpage', 'aZ') ?GETPOST('contextpage', 'aZ') : 'memberslist'; // To manage different context of search
-$mode        = GETPOST('mode', 'alpha');
-
+$backtopage = GETPOST('backtopage', 'alpha');
+$optioncss 	= GETPOST('optioncss', 'aZ');
+$mode 		= GETPOST('mode', 'alpha');
 
 // Search fields
-$search = GETPOST("search", 'alpha');
-$search_ref = GETPOST("search_ref", 'alpha');
-$search_lastname = GETPOST("search_lastname", 'alpha');
-$search_firstname = GETPOST("search_firstname", 'alpha');
-$search_gender = GETPOST("search_gender", 'alpha');
-$search_civility = GETPOST("search_civility", 'alpha');
-$search_company = GETPOST('search_company', 'alphanohtml');
-$search_login = GETPOST("search_login", 'alpha');
-$search_address = GETPOST("search_address", 'alpha');
-$search_zip = GETPOST("search_zip", 'alpha');
-$search_town = GETPOST("search_town", 'alpha');
-$search_state = GETPOST("search_state", 'alpha');
-$search_country = GETPOST("search_country", 'alpha');
-$search_phone = GETPOST("search_phone", 'alpha');
+$search 			= GETPOST("search", 'alpha');
+$search_ref 		= GETPOST("search_ref", 'alpha');
+$search_lastname 	= GETPOST("search_lastname", 'alpha');
+$search_firstname 	= GETPOST("search_firstname", 'alpha');
+$search_gender 		= GETPOST("search_gender", 'alpha');
+$search_civility 	= GETPOST("search_civility", 'alpha');
+$search_company 	= GETPOST('search_company', 'alphanohtml');
+$search_login 		= GETPOST("search_login", 'alpha');
+$search_address 	= GETPOST("search_address", 'alpha');
+$search_zip 		= GETPOST("search_zip", 'alpha');
+$search_town 		= GETPOST("search_town", 'alpha');
+$search_state 		= GETPOST("search_state", 'alpha');  // county / departement / federal state
+$search_country 	= GETPOST("search_country", 'alpha');
+$search_phone 		= GETPOST("search_phone", 'alpha');
 $search_phone_perso = GETPOST("search_phone_perso", 'alpha');
 $search_phone_mobile = GETPOST("search_phone_mobile", 'alpha');
-$search_type = GETPOST("search_type", 'alpha');
-$search_email = GETPOST("search_email", 'alpha');
-$search_categ = GETPOST("search_categ", 'int');
-$search_filter = GETPOST("search_filter", 'alpha');
-$search_status = GETPOST("search_status", 'intcomma');
-$search_morphy = GETPOST("search_morphy", 'alpha');
+$search_type 		= GETPOST("search_type", 'alpha');
+$search_email 		= GETPOST("search_email", 'alpha');
+$search_categ 		= GETPOST("search_categ", 'int');
+$search_morphy 		= GETPOST("search_morphy", 'alpha');
 $search_import_key  = trim(GETPOST("search_import_key", 'alpha'));
-$catid        = GETPOST("catid", 'int');
-$optioncss = GETPOST('optioncss', 'alpha');
-$socid = GETPOST('socid', 'int');
+
+$catid 		= GETPOST("catid", 'int');
+$socid 		= GETPOST('socid', 'int');
+
+$search_filter 		= GETPOST("search_filter", 'alpha');
+$search_status 		= GETPOST("search_status", 'intcomma');  // statut
 
 $filter = GETPOST("filter", 'alpha');
 if ($filter) {
 	$search_filter = $filter; // For backward compatibility
 }
+
 $statut = GETPOST("statut", 'alpha');
 if ($statut != '') {
 	$search_status = $statut; // For backward compatibility
@@ -93,6 +97,7 @@ if ($search_status < -2) {
 	$search_status = '';
 }
 
+// Pagination parameters
 $limit = GETPOST('limit', 'int') ?GETPOST('limit', 'int') : $conf->liste_limit;
 $sortfield = GETPOST('sortfield', 'aZ09comma');
 $sortorder = GETPOST('sortorder', 'aZ09comma');

+ 2 - 2
htdocs/admin/commande.php

@@ -117,7 +117,7 @@ if ($action == 'updateMask') {
 } elseif ($action == 'del') {
 	$ret = delDocumentModel($value, $type);
 	if ($ret > 0) {
-		if ($conf->global->COMMANDE_ADDON_PDF == "$value") {
+		if (getDolGlobalString('COMMANDE_ADDON_PDF') == $value) {
 			dolibarr_del_const($db, 'COMMANDE_ADDON_PDF', $conf->entity);
 		}
 	}
@@ -461,7 +461,7 @@ foreach ($dirmodels as $reldir) {
 
 								// Default
 								print '<td class="center">';
-								if ($conf->global->COMMANDE_ADDON_PDF == $name) {
+								if (getDolGlobalString('COMMANDE_ADDON_PDF') == $name) {
 									print img_picto($langs->trans("Default"), 'on');
 								} else {
 									print '<a class="reposition" href="'.$_SERVER["PHP_SELF"].'?action=setdoc&token='.newToken().'&value='.urlencode($name).'&scan_dir='.urlencode($module->scandir).'&label='.urlencode($module->name).'" alt="'.$langs->trans("Default").'">'.img_picto($langs->trans("Disabled"), 'off').'</a>';

+ 9 - 6
htdocs/bookmarks/list.php

@@ -29,15 +29,18 @@ require_once DOL_DOCUMENT_ROOT.'/bookmarks/class/bookmark.class.php';
 $langs->loadLangs(array('bookmarks', 'admin'));
 
 // Get Parameters
-$action = GETPOST('action', 'aZ09');
+$id = GETPOST("id", 'int');
+
+$action 	= GETPOST('action', 'aZ09');
 $massaction = GETPOST('massaction', 'alpha');
 $show_files = GETPOST('show_files', 'int');
-$confirm = GETPOST('confirm', 'alpha');
-$toselect = GETPOST('toselect', 'array');
+$confirm 	= GETPOST('confirm', 'alpha');
+$cancel     = GETPOST('cancel', 'alpha');
+$toselect 	= GETPOST('toselect', 'array');
 $contextpage = GETPOST('contextpage', 'aZ') ?GETPOST('contextpage', 'aZ') : 'bookmarklist'; // To manage different context of search
-$id = GETPOST("id", 'int');
-$optioncss = GETPOST('optioncss', 'alpha');
-$mode = GETPOST('mode', 'aZ09');
+$backtopage = GETPOST('backtopage', 'alpha');
+$optioncss 	= GETPOST('optioncss', 'alpha');
+$mode 		= GETPOST('mode', 'aZ09');
 
 // Load variable for pagination
 $limit = GETPOST('limit', 'int') ? GETPOST('limit', 'int') : $conf->liste_limit;

+ 11 - 5
htdocs/comm/action/list.php

@@ -33,18 +33,22 @@ require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
 require_once DOL_DOCUMENT_ROOT.'/comm/action/class/actioncomm.class.php';
 require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
 require_once DOL_DOCUMENT_ROOT.'/core/lib/agenda.lib.php';
-include_once DOL_DOCUMENT_ROOT.'/core/class/html.formactions.class.php';
 require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
 
+include_once DOL_DOCUMENT_ROOT.'/core/class/html.formactions.class.php';
+
 // Load translation files required by the page
 $langs->loadLangs(array("users", "companies", "agenda", "commercial", "other", "orders", "bills"));
 
-$action = GETPOST('action', 'aZ09');
+// Get Parameters
+$action 	= GETPOST('action', 'aZ09');
 $massaction = GETPOST('massaction', 'alpha');
+$confirm 	= GETPOST('confirm', 'alpha');
+$cancel     = GETPOST('cancel', 'alpha');
+$toselect 	= GETPOST('toselect', 'array');
 $contextpage = GETPOST('contextpage', 'aZ') ?GETPOST('contextpage', 'aZ') : 'actioncommlist'; // To manage different context of search
-$optioncss = GETPOST('optioncss', 'alpha');
-$toselect = GETPOST('toselect', 'array');
-$confirm = GETPOST('confirm', 'alpha');
+$optioncss 	= GETPOST('optioncss', 'alpha');
+
 
 $disabledefaultvalues = GETPOST('disabledefaultvalues', 'int');
 
@@ -70,6 +74,7 @@ if (GETPOST('search_actioncode', 'array')) {
 	$actioncode = GETPOST("search_actioncode", "alpha", 3) ?GETPOST("search_actioncode", "alpha", 3) : (GETPOST("search_actioncode") == '0' ? '0' : ((empty($conf->global->AGENDA_DEFAULT_FILTER_TYPE) || $disabledefaultvalues) ? '' : $conf->global->AGENDA_DEFAULT_FILTER_TYPE));
 }
 
+// Search Fields
 $search_id = GETPOST('search_id', 'alpha');
 $search_title = GETPOST('search_title', 'alpha');
 $search_note = GETPOST('search_note', 'alpha');
@@ -106,6 +111,7 @@ if (empty($filtert) && empty($conf->global->AGENDA_ALL_CALENDARS)) {
 	$filtert = $user->id;
 }
 
+// Pagination parameters
 $limit = GETPOST('limit', 'int') ?GETPOST('limit', 'int') : $conf->liste_limit;
 $sortfield = GETPOST('sortfield', 'aZ09comma');
 $sortorder = GETPOST('sortorder', 'aZ09comma');

+ 7 - 2
htdocs/comm/card.php

@@ -1419,7 +1419,7 @@ if ($object->id > 0) {
 		$sql .= ', f.total_tva';
 		$sql .= ', f.total_ttc';
 		$sql .= ', f.entity';
-		$sql .= ', f.datef as df, f.datec as dc, f.paye as paye, f.fk_statut as status';
+		$sql .= ', f.datef as df, f.date_lim_reglement as dl, f.datec as dc, f.paye as paye, f.fk_statut as status';
 		$sql .= ', s.nom, s.rowid as socid';
 		$sql .= ', SUM(pf.amount) as am';
 		$sql .= " FROM ".MAIN_DB_PREFIX."societe as s,".MAIN_DB_PREFIX."facture as f";
@@ -1493,7 +1493,12 @@ if ($object->id > 0) {
 				//print $formfile->getDocumentsLink($facturestatic->element, $filename, $filedir);
 				print '</td>';
 				if ($objp->df > 0) {
-					print '<td class="right" width="80px">'.dol_print_date($db->jdate($objp->df), 'day').'</td>';
+					print '<td class="right" width="80px">'.$langs->trans('DateInvoice').": ".dol_print_date($db->jdate($objp->df), 'day').'</td>';
+				} else {
+					print '<td class="right"><b>!!!</b></td>';
+				}
+				if ($objp->dl > 0) {
+					print '<td class="right" width="80px">'.$langs->trans('DateMaxPayment').": ".dol_print_date($db->jdate($objp->dl), 'day').'</td>';
 				} else {
 					print '<td class="right"><b>!!!</b></td>';
 				}

+ 15 - 7
htdocs/comm/mailing/list.php

@@ -27,20 +27,24 @@ require '../../main.inc.php';
 require_once DOL_DOCUMENT_ROOT.'/comm/mailing/class/mailing.class.php';
 
 // Load translation files required by the page
-$langs->load("mails");
+$langs->load('mails');
 
-$sortfield = GETPOST('sortfield', 'aZ09comma');
-$sortorder = GETPOST('sortorder', 'aZ09comma');
-$limit = GETPOST('limit', 'int') ?GETPOST('limit', 'int') : $conf->liste_limit;
-$optioncss = GETPOST('optioncss', 'alpha');
+// Get Parameters
 $massaction = GETPOST('massaction', 'alpha');
-$page = GETPOSTISSET('pageplusone') ? (GETPOST('pageplusone') - 1) : GETPOST("page", 'int');
+$optioncss 	= GETPOST('optioncss', 'alpha');
+
+// Pagination
+$limit 		= GETPOST('limit', 'int') ?GETPOST('limit', 'int') : $conf->liste_limit;
+$sortfield 	= GETPOST('sortfield', 'aZ09comma');
+$sortorder 	= GETPOST('sortorder', 'aZ09comma');
+$page 		= GETPOSTISSET('pageplusone') ? (GETPOST('pageplusone') - 1) : GETPOST("page", 'int');
 if (empty($page) || $page == -1 || GETPOST('button_search', 'alpha') || GETPOST('button_removefilter', 'alpha') || (empty($toselect) && $massaction === '0')) {
 	$page = 0;
 }     // If $page is not defined, or '' or -1 or if we click on clear filters or if we select empty mass action
 $offset = $limit * $page;
 $pageprev = $page - 1;
 $pagenext = $page + 1;
+
 if (!$sortorder) {
 	$sortorder = "DESC";
 }
@@ -48,10 +52,12 @@ if (!$sortfield) {
 	$sortfield = "m.date_creat";
 }
 
+// Search Fields
 $search_all = trim((GETPOST('search_all', 'alphanohtml') != '') ?GETPOST('search_all', 'alphanohtml') : GETPOST('sall', 'alphanohtml'));
 $search_ref = GETPOST("search_ref", "alpha") ? GETPOST("search_ref", "alpha") : GETPOST("sref", "alpha");
 $filteremail = GETPOST('filteremail', 'alpha');
 
+// Initialize objects
 $object = new Mailing($db);
 
 // Initialize technical object to manage hooks of page. Note that conf->hooks_modules contains array of hook context
@@ -128,7 +134,9 @@ if (empty($reshook)) {
  * View
  */
 
-llxHeader('', $langs->trans("Mailing"), 'EN:Module_EMailing|FR:Module_Mailing|ES:M&oacute;dulo_Mailing');
+// Page Header
+$help_url = 'EN:Module_EMailing|FR:Module_Mailing|ES:M&oacute;dulo_Mailing';
+llxHeader('', $langs->trans("Mailing"), $help_url);
 
 $form = new Form($db);
 

+ 15 - 10
htdocs/comm/propal/list.php

@@ -62,21 +62,23 @@ if (isModEnabled("expedition")) {
 	$langs->loadLangs(array('sendings'));
 }
 
+// Get Parameters
 $socid = GETPOST('socid', 'int');
 
-$action = GETPOST('action', 'aZ09');
+$action 	= GETPOST('action', 'aZ09');
 $massaction = GETPOST('massaction', 'alpha');
 $show_files = GETPOST('show_files', 'int');
-$confirm = GETPOST('confirm', 'alpha');
-$toselect = GETPOST('toselect', 'array');
+$confirm 	= GETPOST('confirm', 'alpha');
+$cancel     = GETPOST('cancel', 'alpha');
+$toselect 	= GETPOST('toselect', 'array');
 $contextpage = GETPOST('contextpage', 'aZ') ?GETPOST('contextpage', 'aZ') : 'proposallist';
-$mode = GETPOST('mode', 'alpha');
+$mode 		= GETPOST('mode', 'alpha');
 
-$search_user = GETPOST('search_user', 'int');
-$search_sale = GETPOST('search_sale', 'int');
-$search_ref = GETPOST('sf_ref') ?GETPOST('sf_ref', 'alpha') : GETPOST('search_ref', 'alpha');
+// Search Fields
+$search_user 	= GETPOST('search_user', 'int');
+$search_sale 	= GETPOST('search_sale', 'int');
+$search_ref 	= GETPOST('sf_ref') ?GETPOST('sf_ref', 'alpha') : GETPOST('search_ref', 'alpha');
 $search_refcustomer = GETPOST('search_refcustomer', 'alpha');
-
 $search_refproject = GETPOST('search_refproject', 'alpha');
 $search_project = GETPOST('search_project', 'alpha');
 
@@ -140,15 +142,15 @@ $search_date_signature_endyear = GETPOST('search_date_signature_endyear', 'int')
 $search_date_signature_start = dol_mktime(0, 0, 0, $search_date_signature_startmonth, $search_date_signature_startday, $search_date_signature_startyear);
 $search_date_signature_end = dol_mktime(23, 59, 59, $search_date_signature_endmonth, $search_date_signature_endday, $search_date_signature_endyear);
 
-
 $search_status = GETPOST('search_status', 'alpha');
+
 $optioncss = GETPOST('optioncss', 'alpha');
 $object_statut = GETPOST('search_statut', 'alpha');
 
 $sall = trim((GETPOST('search_all', 'alphanohtml') != '') ?GETPOST('search_all', 'alphanohtml') : GETPOST('sall', 'alphanohtml'));
 $mesg = (GETPOST("msg") ? GETPOST("msg") : GETPOST("mesg"));
 
-
+// Pagination
 $limit = GETPOST('limit', 'int') ?GETPOST('limit', 'int') : $conf->liste_limit;
 $sortfield = GETPOST('sortfield', 'aZ09comma');
 $sortorder = GETPOST('sortorder', 'aZ09comma');
@@ -263,6 +265,7 @@ foreach ($object->fields as $key => $val) {
 		$fieldstosearchall['t.'.$key] = $val['label'];
 	}
 }*/
+
 // Definition of array of fields for columns
 /*$arrayfields = array();
 foreach ($object->fields as $key => $val) {
@@ -278,9 +281,11 @@ foreach ($object->fields as $key => $val) {
 		);
 	}
 }*/
+
 // Extra fields
 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_array_fields.tpl.php';
 
+// Permissions
 $permissiontoread = $user->rights->propal->lire;
 $permissiontoadd = $user->rights->propal->creer;
 $permissiontodelete = $user->rights->propal->supprimer;

+ 2 - 2
htdocs/commande/list_det.php

@@ -137,10 +137,10 @@ $offset = $limit * $page;
 $pageprev = $page - 1;
 $pagenext = $page + 1;
 if (!$sortfield) {
-	$sortfield = 'c.ref';
+	$sortfield = 'pr.ref';
 }
 if (!$sortorder) {
-	$sortorder = 'DESC';
+	$sortorder = 'ASC';
 }
 
 $show_shippable_command = GETPOST('show_shippable_command', 'aZ09');

+ 4 - 1
htdocs/compta/localtax/card.php

@@ -144,9 +144,12 @@ $form = new Form($db);
 
 $title = $langs->trans("LT".$object->ltt)." - ".$langs->trans("Card");
 $help_url = '';
-llxHeader('', $title, $helpurl);
+llxHeader('', $title, $help_url);
 
 if ($action == 'create') {
+	$datev = dol_mktime(12, 0, 0, GETPOST("datevmonth"), GETPOST("datevday"), GETPOST("datevyear"));
+	$datep = dol_mktime(12, 0, 0, GETPOST("datepmonth"), GETPOST("datepday"), GETPOST("datepyear"));
+
 	print load_fiche_titre($langs->transcountry($lttype == 2 ? "newLT2Payment" : "newLT1Payment", $mysoc->country_code));
 
 	print '<form name="add" action="'.$_SERVER["PHP_SELF"].'" name="formlocaltax" method="post">'."\n";

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

@@ -272,7 +272,7 @@ if ($id > 0 || $ref) {
 	print $formconfirm;
 
 
-	if (empty($object->date_trans) && $user->rights->prelevement->bons->send && $action == 'settransmitted') {
+	if (empty($object->date_trans) && (($user->rights->prelevement->bons->send && $object->type != 'bank-transfer') || ($user->rights->paymentbybanktransfer->send && $object->type == 'bank-transfer')) && $action == 'settransmitted') {
 		print '<form method="post" name="userfile" action="card.php?id='.$object->id.'" enctype="multipart/form-data">';
 		print '<input type="hidden" name="token" value="'.newToken().'">';
 		print '<input type="hidden" name="action" value="infotrans">';
@@ -291,7 +291,7 @@ if ($id > 0 || $ref) {
 		print '<br>';
 	}
 
-	if (!empty($object->date_trans) && empty($object->date_credit) && $user->rights->prelevement->bons->credit && $action == 'setcredited') {
+	if (!empty($object->date_trans) && empty($object->date_credit) && (($user->rights->prelevement->bons->credit && $object->type != 'bank-transfer') || ($user->rights->paymentbybanktransfer->debit && $object->type == 'bank-transfer')) && $action == 'setcredited') {
 		$btnLabel = ($object->type == 'bank-transfer') ? $langs->trans("ClassDebited") : $langs->trans("ClassCredited");
 		print '<form name="infocredit" method="post" action="card.php?id='.$object->id.'">';
 		print '<input type="hidden" name="token" value="'.newToken().'">';

+ 3 - 0
htdocs/contrat/services_list.php

@@ -822,6 +822,9 @@ while ($i < min($num, $limit)) {
 		if (!$i) {
 			$totalarray['pos'][$totalarray['nbfield']] = 'cd.qty';
 		}
+		if (!$i) {
+			$totalarray['val']['cd.qty'] = $obj->qty;
+		}
 		$totalarray['val']['cd.qty'] += $obj->qty;
 	}
 	if (!empty($arrayfields['cd.total_ht']['checked'])) {

+ 278 - 0
htdocs/core/boxes/box_members_by_tags.php

@@ -0,0 +1,278 @@
+<?php
+/* Copyright (C) 2003-2007 Rodolphe Quiedeville <rodolphe@quiedeville.org>
+ * Copyright (C) 2004-2017 Laurent Destailleur  <eldy@users.sourceforge.net>
+ * Copyright (C) 2005-2012 Regis Houssin        <regis.houssin@inodbox.com>
+ * Copyright (C) 2015-2020 Frederic France      <frederic.france@netlogic.fr>
+ * Copyright (C) 2021-2022 Waël Almoman         <info@almoman.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 <https://www.gnu.org/licenses/>.
+ */
+
+/**
+ *	\file       htdocs/core/boxes/box_members_by_tags.php
+ *	\ingroup    adherent
+ *	\brief      Module to show box of members
+ */
+
+include_once DOL_DOCUMENT_ROOT . '/core/boxes/modules_boxes.php';
+
+
+/**
+ * Class to manage the box to show last modofied members
+ */
+class box_members_by_tags extends ModeleBoxes
+{
+	public $boxcode = "box_members_by_tags";
+	public $boximg = "object_user";
+	public $boxlabel = "BoxTitleMembersByTags";
+	public $depends = array("adherent", "categorie");
+
+	/**
+	 * @var DoliDB Database handler.
+	 */
+	public $db;
+
+	public $param;
+	public $enabled = 1;
+
+	public $info_box_head = array();
+	public $info_box_contents = array();
+
+
+	/**
+	 *  Constructor
+	 *
+	 *  @param  DoliDB	$db      	Database handler
+	 *  @param	string	$param		More parameters
+	 */
+	public function __construct($db, $param = '')
+	{
+		global $conf, $user;
+
+		$this->db = $db;
+
+		// disable module for such cases
+		$listofmodulesforexternal = explode(',', $conf->global->MAIN_MODULES_FOR_EXTERNAL);
+		if (!in_array('adherent', $listofmodulesforexternal) && !empty($user->socid)) {
+			$this->enabled = 0; // disabled for external users
+		}
+
+		$this->hidden = !(isModEnabled('adherent') && $user->rights->adherent->lire);
+	}
+
+	/**
+	 *  Load data into info_box_contents array to show array later.
+	 *
+	 *  @param	int		$max        Maximum number of records to load
+	 *  @return	void
+	 */
+	public function loadBox($max = 5)
+	{
+		global $user, $langs, $conf;
+		$langs->load("boxes");
+
+		$this->max = $max;
+
+		include_once DOL_DOCUMENT_ROOT . '/adherents/class/adherent.class.php';
+		$staticmember = new Adherent($this->db);
+
+		$year = date('Y');
+		$numberyears = empty(getDolGlobalInt("MAIN_NB_OF_YEAR_IN_WIDGET_GRAPH")) ? 2 : getDolGlobalInt("MAIN_NB_OF_YEAR_IN_WIDGET_GRAPH");
+
+		$this->info_box_head = array('text' => $langs->trans("BoxTitleMembersByTags").' ('.$year-$numberyears.' - '.$year.')');
+
+		if ($user->rights->adherent->lire) {
+			require_once DOL_DOCUMENT_ROOT.'/adherents/class/adherentstats.class.php';
+			require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
+			$stats = new AdherentStats($this->db, $user->socid, $user->id);
+
+			// Show array
+			$sumMembers= $stats->countMembersByTagAndStatus($numberyears);
+			if ($sumMembers) {
+				$line = 0;
+				$this->info_box_contents[$line][] = array(
+					'td' => 'class=""',
+					'text' => '',
+				);
+				// Members Status To Valid
+				$labelstatus = $staticmember->LibStatut($staticmember::STATUS_DRAFT, 0, 0, 1);
+				$this->info_box_contents[$line][] = array(
+					'td' => 'class="right tdoverflowmax100" width="10%" title="'.dol_escape_htmltag($labelstatus).'"',
+					'text' => $labelstatus
+				);
+				// Waiting for subscription
+				$labelstatus = $staticmember->LibStatut($staticmember::STATUS_VALIDATED, 1, 0, 1);
+				$this->info_box_contents[$line][] = array(
+					'td' => 'class="right tdoverflowmax100" width="10%" title="'.dol_escape_htmltag($labelstatus).'"',
+					'text' => $labelstatus,
+				);
+				// Up to date
+				$labelstatus = $staticmember->LibStatut($staticmember::STATUS_VALIDATED, 1, dol_now() + 86400, 1);
+				$this->info_box_contents[$line][] = array(
+					'td' => 'class="right tdoverflowmax100" width="10%" title="'.dol_escape_htmltag($labelstatus).'"',
+					'text' => $labelstatus,
+				);
+				// Expired
+				$labelstatus = $staticmember->LibStatut($staticmember::STATUS_VALIDATED, 1, dol_now() - 86400, 1);
+				$this->info_box_contents[$line][] = array(
+					'td' => 'class="right tdoverflowmax100" width="10%" title="'.dol_escape_htmltag($labelstatus).'"',
+					'text' => $labelstatus
+				);
+				// Excluded
+				$labelstatus = $staticmember->LibStatut($staticmember::STATUS_EXCLUDED, 0, 0, 1);
+				$this->info_box_contents[$line][] = array(
+					'td' => 'class="right tdoverflowmax100" width="10%" title="'.dol_escape_htmltag($labelstatus).'"',
+					'text' => $labelstatus
+				);
+				// Resiliated
+				$labelstatus = $staticmember->LibStatut($staticmember::STATUS_RESILIATED, 0, 0, 1);
+				$this->info_box_contents[$line][] = array(
+					'td' => 'class="right tdoverflowmax100" width="10%" title="'.dol_escape_htmltag($labelstatus).'"',
+					'text' => $labelstatus
+				);
+				// Total row
+				$labelstatus = $staticmember->LibStatut($staticmember::STATUS_RESILIATED, 0, 0, 1);
+				$this->info_box_contents[$line][] = array(
+					'td' => 'class="right tdoverflowmax100" width="10%" title="'.dol_escape_htmltag($langs->trans("Total")).'"',
+					'text' => $langs->trans("Total")
+				);
+				$line++;
+				foreach ($sumMembers as $key => $data) {
+					$adhtype = new AdherentType($this->db);
+					$adhtype->id = $key;
+
+					if ($key=='total') {
+						break;
+					}
+					$adhtype->label = $data['label'];
+					$AdherentType[$key] = $adhtype;
+
+					$this->info_box_contents[$line][] = array(
+						'td' => 'class="tdoverflowmax150 maxwidth150onsmartphone"',
+						'text' => $adhtype->getNomUrl(1, dol_size(32)),
+						'asis' => 1,
+					);
+					$this->info_box_contents[$line][] = array(
+						'td' => 'class="right"',
+						'text' => (isset($data['members_draft']) && $data['members_draft'] > 0 ? $data['members_draft'] : '') . ' ' . $staticmember->LibStatut(Adherent::STATUS_DRAFT, 1, 0, 3),
+						'asis' => 1,
+					);
+					$this->info_box_contents[$line][] = array(
+						'td' => 'class="right"',
+						'text' => (isset($data['members_pending']) && $data['members_pending'] > 0 ? $data['members_pending'] : '') . ' ' . $staticmember->LibStatut(Adherent::STATUS_VALIDATED, 1, $now, 3),
+						'asis' => 1,
+					);
+					$this->info_box_contents[$line][] = array(
+						'td' => 'class="right"',
+						'text' => (isset($data['members_uptodate']) && $data['members_uptodate'] > 0 ? $data['members_uptodate'] : '') . ' ' . $staticmember->LibStatut(Adherent::STATUS_VALIDATED, 0, 0, 3),
+						'asis' => 1,
+					);
+					$this->info_box_contents[$line][] = array(
+						'td' => 'class="right"',
+						'text' => (isset($data['members_expired']) && $data['members_expired'] > 0 ? $data['members_expired'] : '') . ' ' . $staticmember->LibStatut(Adherent::STATUS_VALIDATED, 1, 1, 3),
+						'asis' => 1,
+					);
+					$this->info_box_contents[$line][] = array(
+						'td' => 'class="right"',
+						'text' => (isset($data['members_excluded']) && $data['members_excluded'] > 0 ? $data['members_excluded'] : '') . ' ' . $staticmember->LibStatut(Adherent::STATUS_EXCLUDED, 1, $now, 3),
+						'asis' => 1,
+					);
+					$this->info_box_contents[$line][] = array(
+						'td' => 'class="right"',
+						'text' => (isset($data['members_resiliated']) && $data['members_resiliated'] > 0 ? $data['members_resiliated'] : '') . ' ' . $staticmember->LibStatut(Adherent::STATUS_RESILIATED, 1, 0, 3),
+						'asis' => 1,
+					);
+					$this->info_box_contents[$line][] = array(
+						'td' => 'class="right"',
+						'text' => (isset($data['total_adhtype']) && $data['total_adhtype'] > 0 ? $data['total_adhtype'] : ''),
+						'asis' => 1,
+					);
+					$line++;
+				}
+
+				if (count($sumMembers) == 0) {
+					$this->info_box_contents[$line][0] = array(
+						'td' => 'class="center" colspan="6"',
+						'text' => $langs->trans("NoRecordedMembersByType")
+					);
+				} else {
+					$this->info_box_contents[$line][] = array(
+						'tr' => 'class="liste_total"',
+						'td' => 'class="liste_total"',
+						'text' => $langs->trans("Total")
+					);
+					$this->info_box_contents[$line][] = array(
+						'td' => 'class="liste_total right"',
+						'text' => $sumMembers['total']['members_draft'].' '.$staticmember->LibStatut(Adherent::STATUS_DRAFT, 1, 0, 3),
+						'asis' => 1
+					);
+					$this->info_box_contents[$line][] = array(
+						'td' => 'class="liste_total right"',
+						'text' => $sumMembers['total']['members_pending'].' '.$staticmember->LibStatut(Adherent::STATUS_VALIDATED, 1, $now, 3),
+						'asis' => 1
+					);
+					$this->info_box_contents[$line][] = array(
+						'td' => 'class="liste_total right"',
+						'text' => $sumMembers['total']['members_uptodate'].' '.$staticmember->LibStatut(Adherent::STATUS_VALIDATED, 0, 0, 3),
+						'asis' => 1
+					);
+					$this->info_box_contents[$line][] = array(
+						'td' => 'class="liste_total right"',
+						'text' => $sumMembers['total']['members_expired'].' '.$staticmember->LibStatut(Adherent::STATUS_VALIDATED, 1, 1, 3),
+						'asis' => 1
+					);
+					$this->info_box_contents[$line][] = array(
+						'td' => 'class="liste_total right"',
+						'text' => $sumMembers['total']['members_excluded'].' '.$staticmember->LibStatut(Adherent::STATUS_EXCLUDED, 1, 0, 3),
+						'asis' => 1
+					);
+					$this->info_box_contents[$line][] = array(
+						'td' => 'class="liste_total right"',
+						'text' => $sumMembers['total']['members_resiliated'].' '.$staticmember->LibStatut(Adherent::STATUS_RESILIATED, 1, 0, 3),
+						'asis' => 1
+					);
+					$this->info_box_contents[$line][] = array(
+						'td' => 'class="liste_total right"',
+						'text' => $sumMembers['total']['all'],
+						'asis' => 1
+					);
+				}
+			} else {
+				$this->info_box_contents[0][0] = array(
+					'td' => '',
+					'maxlength' => 500,
+					'text' => ($this->db->error() . ' sql=' . $sql)
+				);
+			}
+		} else {
+			$this->info_box_contents[0][0] = array(
+				'td' => 'class="nohover opacitymedium left"',
+				'text' => $langs->trans("ReadPermissionNotAllowed")
+			);
+		}
+	}
+
+	/**
+	 *	Method to show box
+	 *
+	 *	@param	array	$head       Array with properties of box title
+	 *	@param  array	$contents   Array with properties of box lines
+	 *  @param	int		$nooutput	No print, only return string
+	 *	@return	string
+	 */
+	public function showBox($head = null, $contents = null, $nooutput = 0)
+	{
+		return parent::showBox($this->info_box_head, $this->info_box_contents, $nooutput);
+	}
+}

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

@@ -464,6 +464,7 @@ class ModeleBoxes // Can't be abtract as it is instantiated to build "empty" box
 				closedir($handle);
 			}
 		}
+		//echo "<pre>";print_r($modules);echo "</pre>";
 
 		asort($orders);
 

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

@@ -1104,7 +1104,7 @@ abstract class CommonDocGenerator
 	public function getColumnContentXStart($colKey)
 	{
 		$colDef = $this->cols[$colKey];
-		return  $colDef['xStartPos'] + $colDef['content']['padding'][3];
+		return  (isset($colDef['xStartPos']) ? $colDef['xStartPos'] : 0) + $colDef['content']['padding'][3];
 	}
 
 	/**

+ 1 - 0
htdocs/core/modules/modAdherent.class.php

@@ -198,6 +198,7 @@ class modAdherent extends DolibarrModules
 			4 => array('file'=>'box_members_last_subscriptions.php', 'enabledbydefaulton'=>'membersindex'),
 			5 => array('file'=>'box_members_subscriptions_by_year.php', 'enabledbydefaulton'=>'membersindex'),
 			6 => array('file'=>'box_members_by_type.php', 'enabledbydefaulton'=>'membersindex'),
+			7 => array('file'=>'box_members_by_tags.php', 'enabledbydefaulton'=>'membersindex'),
 		);
 
 		// Permissions

+ 28 - 0
htdocs/core/modules/modTicket.class.php

@@ -208,6 +208,13 @@ class modTicket extends DolibarrModules
 		$this->rights[$r][3] = 0; // La permission est-elle une permission par defaut
 		$this->rights[$r][4] = 'manage';
 
+		$r++;
+		$this->rights[$r][0] = 56006; // id de la permission
+		$this->rights[$r][1] = "Export ticket"; // libelle de la permission
+		//$this->rights[$r][2] = 'd'; // type de la permission (deprecie a ce jour)
+		$this->rights[$r][3] = 0; // La permission est-elle une permission par defaut
+		$this->rights[$r][4] = 'export';
+
 		/* Seems not used and in conflict with societe->client->voir (see all thirdparties)
 		$r++;
 		$this->rights[$r][0] = 56005; // id de la permission
@@ -318,6 +325,27 @@ class modTicket extends DolibarrModules
 			'target' => '',
 			'user' => 0);
 		$r++;
+
+		// Exports
+		//--------
+		$r = 1;
+
+		// Export list of tickets and attributes
+		$langs->load("ticket");
+		$this->export_code[$r]=$this->rights_class.'_'.$r;
+		$this->export_label[$r]='ExportDataset_ticket_1';	// Translation key (used only if key ExportDataset_xxx_z not found)
+		$this->export_permission[$r] = array(array("ticket", "export"));
+		$this->export_icon[$r]='ticket';
+		$keyforclass = 'Ticket';$keyforclassfile='/ticket/class/ticket.class.php';$keyforelement='ticket';
+		include DOL_DOCUMENT_ROOT.'/core/commonfieldsinexport.inc.php';
+		$keyforselect='ticket'; $keyforaliasextra='extra'; $keyforelement='ticket';
+		include DOL_DOCUMENT_ROOT.'/core/extrafieldsinexport.inc.php';
+		$this->export_sql_start[$r]='SELECT DISTINCT ';
+		$this->export_sql_end[$r]  =' FROM '.MAIN_DB_PREFIX.'ticket as t';
+		$this->export_sql_end[$r] .= ' LEFT JOIN '.MAIN_DB_PREFIX.'ticket_extrafields as extra on (t.rowid = extra.fk_object)';
+		$this->export_sql_end[$r] .=' WHERE 1 = 1';
+		$this->export_sql_end[$r] .=' AND t.entity IN ('.getEntity('ticket').')';
+		$r++;
 	}
 
 	/**

+ 6 - 1
htdocs/debugbar/class/DataCollector/DolLogsCollector.php

@@ -41,6 +41,11 @@ class DolLogsCollector extends MessagesCollector
 	 */
 	protected $maxnboflines;
 
+	/**
+	 * @var int number of lines
+	 */
+	protected $nboflines;
+
 	/**
 	 * Constructor
 	 *
@@ -54,7 +59,7 @@ class DolLogsCollector extends MessagesCollector
 		parent::__construct($name);
 
 		$this->nboflines = 0;
-		$this->maxnboflines = empty($conf->global->DEBUGBAR_LOGS_LINES_NUMBER) ? 250 : $conf->global->DEBUGBAR_LOGS_LINES_NUMBER; // High number slows seriously output
+		$this->maxnboflines = getDolGlobalInt('DEBUGBAR_LOGS_LINES_NUMBER', 250); // High number slows seriously output
 
 		$this->path = $path ?: $this->getLogsFile();
 	}

+ 4 - 56
htdocs/emailcollector/class/emailcollectoraction.class.php

@@ -24,8 +24,6 @@
 
 // Put here all includes required by your class file
 require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php';
-//require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php';
-//require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
 
 /**
  * Class for EmailCollectorAction
@@ -113,37 +111,6 @@ class EmailCollectorAction extends CommonObject
 	public $status;
 	// END MODULEBUILDER PROPERTIES
 
-
-
-	// If this object has a subtable with lines
-
-	// /**
-	//  * @var string    Name of subtable line
-	//  */
-	//public $table_element_line = 'emailcollectoractiondet';
-
-	// /**
-	//  * @var string    Field with ID of parent key if this field has a parent
-	//  */
-	//public $fk_element = 'fk_emailcollectoraction';
-
-	// /**
-	//  * @var string    Name of subtable class that manage subtable lines
-	//  */
-	//public $class_element_line = 'EmailcollectorActionline';
-
-	// /**
-	//	* @var array	List of child tables. To test if we can delete object.
-	//  */
-	//protected $childtables=array();
-
-	// /**
-	//  * @var EmailcollectorActionLine[]     Array of subtable lines
-	//  */
-	//public $lines = array();
-
-
-
 	/**
 	 * Constructor
 	 *
@@ -225,16 +192,14 @@ class EmailCollectorAction extends CommonObject
 
 		// Clear fields
 		$object->ref = "copy_of_".$object->ref;
-		$object->title = $langs->trans("CopyOf")." ".$object->title;
-		// ...
+		// $object->title = $langs->trans("CopyOf")." ".$object->title;
+
 		// Clear extrafields that are unique
 		if (is_array($object->array_options) && count($object->array_options) > 0) {
 			$extrafields->fetch_name_optionals_label($this->table_element);
 			foreach ($object->array_options as $key => $option) {
 				$shortkey = preg_replace('/options_/', '', $key);
 				if (!empty($extrafields->attributes[$this->element]['unique'][$shortkey])) {
-					//var_dump($key);
-					//var_dump($clonedObj->array_options[$key]); exit;
 					unset($object->array_options[$key]);
 				}
 			}
@@ -271,26 +236,10 @@ class EmailCollectorAction extends CommonObject
 	public function fetch($id, $ref = null)
 	{
 		$result = $this->fetchCommon($id, $ref);
-		// if ($result > 0 && !empty($this->table_element_line)) {
-		// 	$this->fetchLinesCommon();
-		// }
+
 		return $result;
 	}
 
-	/**
-	 * Load object lines in memory from the database
-	 *
-	 * @return int         <0 if KO, 0 if not found, >0 if OK
-	 */
-	/*public function fetchLines()
-	{
-		$this->lines=array();
-
-		// Load lines with object EmailcollectorActionLine
-
-		return count($this->lines)?1:0;
-	}*/
-
 	/**
 	 * Update object into database
 	 *
@@ -336,7 +285,6 @@ class EmailCollectorAction extends CommonObject
 		}
 
 		$result = '';
-		$companylink = '';
 
 		$label = '<u>'.$langs->trans("EmailcollectorAction").'</u>';
 		$label .= '<br>';
@@ -487,7 +435,7 @@ class EmailCollectorAction extends CommonObject
 
 				$this->user_creation_id = $obj->fk_user_creat;
 				$this->user_modification_id = $obj->fk_user_modif;
-				$this->date_creation     = $this->db->jdate($obj->datec);
+				$this->date_creation = $this->db->jdate($obj->datec);
 				$this->date_modification = empty($obj->datem) ? '' : $this->db->jdate($obj->datem);
 			}
 

+ 4 - 23
htdocs/emailcollector/class/emailcollectorfilter.class.php

@@ -206,16 +206,14 @@ class EmailCollectorFilter extends CommonObject
 
 		// Clear fields
 		$object->ref = "copy_of_".$object->ref;
-		$object->title = $langs->trans("CopyOf")." ".$object->title;
-		// ...
+		// $object->title = $langs->trans("CopyOf")." ".$object->title;
+
 		// Clear extrafields that are unique
 		if (is_array($object->array_options) && count($object->array_options) > 0) {
 			$extrafields->fetch_name_optionals_label($this->table_element);
 			foreach ($object->array_options as $key => $option) {
 				$shortkey = preg_replace('/options_/', '', $key);
 				if (!empty($extrafields->attributes[$this->element]['unique'][$shortkey])) {
-					//var_dump($key);
-					//var_dump($clonedObj->array_options[$key]); exit;
 					unset($object->array_options[$key]);
 				}
 			}
@@ -252,26 +250,10 @@ class EmailCollectorFilter extends CommonObject
 	public function fetch($id, $ref = null)
 	{
 		$result = $this->fetchCommon($id, $ref);
-		if ($result > 0 && !empty($this->table_element_line)) {
-			$this->fetchLines();
-		}
+
 		return $result;
 	}
 
-	/**
-	 * Load object lines in memory from the database
-	 *
-	 * @return int         <0 if KO, 0 if not found, >0 if OK
-	 */
-	/*public function fetchLines()
-	{
-		$this->lines=array();
-
-		// Load lines with object EmailcollectorFilterLine
-
-		return count($this->lines)?1:0;
-	}*/
-
 	/**
 	 * Update object into database
 	 *
@@ -317,7 +299,6 @@ class EmailCollectorFilter extends CommonObject
 		}
 
 		$result = '';
-		$companylink = '';
 
 		$label = '<u>'.$langs->trans("EmailcollectorFilter").'</u>';
 		$label .= '<br>';
@@ -468,7 +449,7 @@ class EmailCollectorFilter extends CommonObject
 
 				$this->user_creation_id = $obj->fk_user_creat;
 				$this->user_modification_id = $obj->fk_user_modif;
-				$this->date_creation     = $this->db->jdate($obj->datec);
+				$this->date_creation = $this->db->jdate($obj->datec);
 				$this->date_modification = empty($obj->datem) ? '' : $this->db->jdate($obj->datem);
 			}
 

+ 35 - 0
htdocs/hrm/class/position.class.php

@@ -1118,6 +1118,41 @@ class Position extends CommonObject
 
 		return $error;
 	}
+
+	/**
+	 *	Return clicable link of object (with eventually picto)
+	 *
+	 *	@param      string	    $option                 Where point the link (0=> main card, 1,2 => shipment, 'nolink'=>No link)
+	 *  @return		string		HTML Code for Kanban thumb.
+	 */
+	public function getKanbanView($option = '')
+	{
+		global $selected, $langs;
+		$return = '<div class="box-flex-item box-flex-grow-zero">';
+		$return .= '<div class="info-box info-box-sm">';
+		$return .= '<span class="info-box-icon bg-infobox-action">';
+		$return .= img_picto('', $this->picto);
+		$return .= '</span>';
+		$return .= '<div class="info-box-content">';
+		$return .= '<span class="info-box-ref">'.(method_exists($this, 'getNomUrl') ? $this->getNomUrl(1) : $this->ref).'</span>';
+		$return .= '<input class="fright" id="cb'.$this->id.'" class="flat checkforselect" type="checkbox" name="toselect[]" value="'.$this->id.'"'.($selected ? ' checked="checked"' : '').'>';
+		if (property_exists($this, 'fk_user') && !(empty($this->fk_user))) {
+			$return .= '<br><span class="info-box-label opacitymedium">'.$langs->trans("Employee").'</span> : ';
+			$return .= '<span class="info-box-label ">'.$this->fk_user.'</span>';
+		}
+		if (property_exists($this, 'fk_job') && !(empty($this->fk_job))) {
+			$return .= '<br><span class="info-box-label opacitymedium">'.$langs->trans("Job").'</span> : ';
+			$return .= '<span class="info-box-label ">'.$this->fk_job.'</span>';
+		}
+		if (property_exists($this, 'date_start') && property_exists($this, 'date_end')) {
+			$return .= '<br><div class ="margintoponly"><span class="info-box-label ">'.dol_print_date($this->db->jdate($this->date_start), 'day').'</span>';
+			$return .= ' - <span class="info-box-label ">'.dol_print_date($this->db->jdate($this->date_end), 'day').'</span></div>';
+		}
+		$return .= '</div>';
+		$return .= '</div>';
+		$return .= '</div>';
+		return $return;
+	}
 }
 
 

+ 34 - 5
htdocs/hrm/position_list.php

@@ -73,6 +73,7 @@ $pagenext = $page + 1;
 // Initialize technical objects
 $object = new Position($db);
 $extrafields = new ExtraFields($db);
+$userstatic = new User($db);
 $diroutputmassaction = $conf->hrm->dir_output.'/temp/massgeneration/'.$user->id;
 $hookmanager->initHooks(array('positionlist')); // Note that conf->hooks_modules contains array
 
@@ -218,6 +219,10 @@ $morecss = array();
 // --------------------------------------------------------------------
 $sql = 'SELECT ';
 $sql .= $object->getFieldList('t');
+$sql .= ',';
+$sql .= $userstatic->getFieldList('u');
+$sql .= ',u.email, u.statut';
+$sql .= ',j.rowid, j.label as job_label';
 // Add fields from extrafields
 if (!empty($extrafields->attributes[$object->table_element]['label'])) {
 	foreach ($extrafields->attributes[$object->table_element]['label'] as $key => $val) {
@@ -229,7 +234,7 @@ $parameters = array();
 $reshook = $hookmanager->executeHooks('printFieldListSelect', $parameters, $object); // Note that $action and $object may have been modified by hook
 $sql .= preg_replace('/^,/', '', $hookmanager->resPrint);
 $sql = preg_replace('/,\s*$/', '', $sql);
-$sql .= " FROM ".MAIN_DB_PREFIX.$object->table_element." as t";
+$sql .= " FROM ".MAIN_DB_PREFIX.$object->table_element." as t LEFT JOIN ".MAIN_DB_PREFIX.$userstatic->table_element." as u on t.fk_user = u.rowid, ".MAIN_DB_PREFIX."hrm_job as j";
 if (isset($extrafields->attributes[$object->table_element]['label']) && is_array($extrafields->attributes[$object->table_element]['label']) && count($extrafields->attributes[$object->table_element]['label'])) {
 	$sql .= " LEFT JOIN ".MAIN_DB_PREFIX.$object->table_element."_extrafields as ef on (t.rowid = ef.fk_object)";
 }
@@ -242,6 +247,7 @@ if ($object->ismultientitymanaged == 1) {
 } else {
 	$sql .= " WHERE 1 = 1";
 }
+$sql .= " AND t.fk_job = j.rowid";
 foreach ($search as $key => $val) {
 	if (array_key_exists($key, $object->fields)) {
 		if ($key == 'status' && $search[$key] == -1) {
@@ -426,7 +432,10 @@ print '<input type="hidden" name="page" value="'.$page.'">';
 print '<input type="hidden" name="contextpage" value="'.$contextpage.'">';
 print '<input type="hidden" name="mode" value="'.$mode.'">';
 
-$newcardbutton = dolGetButtonTitle($langs->trans('New'), '', 'fa fa-plus-circle', dol_buildpath('/hrm/position.php', 1).'?action=create', '', $permissiontoadd);
+$newcardbutton = '';
+$newcardbutton .= dolGetButtonTitle($langs->trans('ViewList'), '', 'fa fa-bars imgforviewmode', $_SERVER["PHP_SELF"].'?mode=common'.preg_replace('/(&|\?)*mode=[^&]+/', '', $param), '', ((empty($mode) || $mode == 'common') ? 2 : 1), array('morecss'=>'reposition'));
+$newcardbutton .= dolGetButtonTitle($langs->trans('ViewKanban'), '', 'fa fa-th-list imgforviewmode', $_SERVER["PHP_SELF"].'?mode=kanban'.preg_replace('/(&|\?)*mode=[^&]+/', '', $param), '', ($mode == 'kanban' ? 2 : 1), array('morecss'=>'reposition'));
+$newcardbutton .= dolGetButtonTitle($langs->trans('New'), '', 'fa fa-plus-circle', dol_buildpath('/hrm/position.php', 1).'?action=create', '', $permissiontoadd);
 
 print_barre_liste($title, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $massactionbutton, $num, $nbtotalofrecords, 'object_'.$object->picto, 0, $newcardbutton, '', $limit, 0, 0, 1);
 
@@ -602,13 +611,33 @@ while ($i < $imaxinloop) {
 	// Store properties in $object
 	$object->setVarsFromFetchObj($obj);
 
+
 	if ($mode == 'kanban') {
 		if ($i == 0) {
-			print '<tr><td colspan="'.$savnbfield.'">';
+			print '<tr><td colspan="12">';
 			print '<div class="box-flex-container">';
 		}
-		// Output Kanban
-		print $object->getKanbanView('');
+		// get info needed
+		$object->date_start = $obj->date_start;
+		$object->date_end = $obj->date_end;
+		$object->fk_job = $obj->job_label;
+
+		$userstatic->id = $obj->fk_user;
+		$userstatic->ref = $obj->fk_user;
+		$userstatic->firstname = $obj->firstname;
+		$userstatic->lastname = $obj->lastname;
+		$userstatic->email = $obj->email;
+		$userstatic->statut = $obj->statut;
+
+		$object->fk_user = $userstatic->getNomUrl(1);
+		// output kanban
+		if ($massactionbutton || $massaction) { // If we are in select mode (massactionbutton defined) or if we have already selected and sent an action ($massaction) defined
+			$selected = 0;
+			if (in_array($object->id, $arrayofselected)) {
+				$selected = 1;
+			}
+			print $object->getKanbanView('');
+		}
 		if ($i == ($imaxinloop - 1)) {
 			print '</div>';
 			print '</td></tr>';

+ 8 - 0
htdocs/install/mysql/data/llx_10_c_regions.sql

@@ -78,6 +78,7 @@
 -- Portugal
 -- Romania -> for Departmements
 -- San Salvador
+-- Slovakia
 -- Slovenia
 -- Spain
 -- Switzerland/Suisse -> for Departmements/Cantons
@@ -450,6 +451,13 @@ INSERT INTO llx_c_regions (fk_pays, code_region, cheflieu, tncc, nom) values ( 8
 INSERT INTO llx_c_regions (fk_pays, code_region, cheflieu, tncc, nom) values ( 86, 8603, NULL, NULL, 'Occidental');
 
 
+-- Slovakia Regions (rowid country=201)
+INSERT INTO llx_c_regions (fk_pays, code_region, cheflieu, tncc, nom) VALUES ( 201, '20101', 'SK01', NULL, 'Bratislava Region');
+INSERT INTO llx_c_regions (fk_pays, code_region, cheflieu, tncc, nom) VALUES ( 201, '20102', 'SK02', NULL, 'Western Slovakia');
+INSERT INTO llx_c_regions (fk_pays, code_region, cheflieu, tncc, nom) VALUES ( 201, '20103', 'SK03', NULL, 'Central Slovakia');
+INSERT INTO llx_c_regions (fk_pays, code_region, cheflieu, tncc, nom) VALUES ( 201, '20104', 'SK04', NULL, 'Eastern Slovakia');
+
+
 -- Slovenia Regions (rowid country=202)
 INSERT INTO llx_c_regions (fk_pays, code_region, cheflieu, tncc, nom) VALUES ( 202, '20203', 'SI03', NULL, 'East Slovenia');
 INSERT INTO llx_c_regions (fk_pays, code_region, cheflieu, tncc, nom) VALUES ( 202, '20204', 'SI04', NULL, 'West Slovenia');

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

@@ -24,6 +24,7 @@ BoxFicheInter=Latest interventions
 BoxCurrentAccounts=Open accounts balance
 BoxTitleMemberNextBirthdays=Birthdays of this month (members)
 BoxTitleMembersByType=Members by type and status
+BoxTitleMembersByTags=Members by tags and status
 BoxTitleMembersSubscriptionsByYear=Members Subscriptions by year
 BoxTitleLastRssInfos=Latest %s news from %s
 BoxTitleLastProducts=Products/Services: last %s modified

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

@@ -26,6 +26,7 @@ Permission56002=Modify tickets
 Permission56003=Delete tickets
 Permission56004=Manage tickets
 Permission56005=See tickets of all third parties (not effective for external users, always be limited to the third party they depend on)
+Permission56006=Export tickets
 
 Tickets=Tickets
 TicketDictType=Ticket - Types
@@ -61,6 +62,8 @@ TypeContact_ticket_external_CONTRIBUTOR=External contributor
 OriginEmail=Reporter Email
 Notify_TICKET_SENTBYMAIL=Send ticket message by email
 
+ExportDataset_ticket_1=Tickets
+
 # Status
 Read=Read
 Assigned=Assigned

+ 3 - 2
htdocs/loan/card.php

@@ -66,6 +66,7 @@ $error = 0;
  * Actions
  */
 
+$parameters = array();
 $reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
 if ($reshook < 0) {
 	setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
@@ -291,13 +292,13 @@ if ($action == 'create') {
 	// Date Start
 	print "<tr>";
 	print '<td class="fieldrequired">'.$langs->trans("DateStart").'</td><td>';
-	print $form->selectDate($datestart ? $datestart : -1, 'start', '', '', '', 'add', 1, 1);
+	print $form->selectDate(!empty($datestart) ? $datestart : -1, 'start', '', '', '', 'add', 1, 1);
 	print '</td></tr>';
 
 	// Date End
 	print "<tr>";
 	print '<td class="fieldrequired">'.$langs->trans("DateEnd").'</td><td>';
-	print $form->selectDate($dateend ? $dateend : -1, 'end', '', '', '', 'add', 1, 1);
+	print $form->selectDate(!empty($dateend) ? $dateend : -1, 'end', '', '', '', 'add', 1, 1);
 	print '</td></tr>';
 
 	// Number of terms

+ 2 - 0
htdocs/loan/list.php

@@ -42,6 +42,7 @@ $limit = GETPOST('limit', 'int') ? GETPOST('limit', 'int') : $conf->liste_limit;
 $sortfield = GETPOST('sortfield', 'aZ09comma');
 $sortorder = GETPOST('sortorder', 'aZ09comma');
 $page = GETPOSTISSET('pageplusone') ? (GETPOST('pageplusone') - 1) : GETPOST("page", 'int');
+$massaction = GETPOST('massaction', 'alpha');
 if (empty($page) || $page == -1 || GETPOST('button_search', 'alpha') || GETPOST('button_removefilter', 'alpha') || (empty($toselect) && $massaction === '0')) {
 	$page = 0;
 }     // If $page is not defined, or '' or -1 or if we click on clear filters or if we select empty mass action
@@ -148,6 +149,7 @@ if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST)) {
 	}
 	$db->free($resql);
 }
+$arrayfields = array();
 
 // Complete request and execute it with limit
 $sql .= $db->order($sortfield, $sortorder);

+ 1 - 1
htdocs/product/card.php

@@ -1485,7 +1485,7 @@ if (is_object($objcanvas) && $objcanvas->displayCanvasExists($action)) {
 			}
 		}
 
-		if ($type == 1  && $conf->workstation->enabled) {
+		if ($type == 1  && isModEnabled("workstation")) {
 				// Default workstation
 				print '<tr><td>'.$langs->trans("DefaultWorkstation").'</td><td>';
 				print img_picto($langs->trans("DefaultWorkstation"), 'workstation', 'class="pictofixedwidth"');

+ 1 - 1
htdocs/product/reassort.php

@@ -133,7 +133,7 @@ $helpurl = 'EN:Module_Stocks_En|FR:Module_Stock|ES:M&oacute;dulo_Stocks';
 
 $form = new Form($db);
 $htmlother = new FormOther($db);
-if ($objp->stock_physique < 0) { print '<span class="warning">'; }
+if (!empty($objp->stock_physique) && $objp->stock_physique < 0) { print '<span class="warning">'; }
 
 $sql = 'SELECT p.rowid, p.ref, p.label, p.barcode, p.price, p.price_ttc, p.price_base_type, p.entity,';
 $sql .= ' p.fk_product_type, p.tms as datem,';

+ 1 - 1
htdocs/reception/contact.php

@@ -72,7 +72,7 @@ if ($origin == 'reception') {
 } else {
 	if ($origin == 'supplierorder' || $origin == 'order_supplier') {
 		$result = restrictedArea($user, 'fournisseur', $origin_id, 'commande_fournisseur', 'commande');
-	} elseif (empty($user->rights->{$origin}->lire) && empty($user->rights->{$origin}->read)) {
+	} elseif (!$user->hasRight($origin, "lire") && !$user->hasRight($origin, "read")) {
 		accessforbidden();
 	}
 }

+ 8 - 1
htdocs/salaries/payments.php

@@ -97,6 +97,7 @@ $search_chq_number = GETPOST('search_chq_number', 'int');
 
 $filtre = GETPOST("filtre", 'restricthtml');
 
+$search_type_id = '';
 if (!GETPOST('search_type_id', 'int')) {
 	$newfiltre = str_replace('filtre=', '', $filtre);
 	$filterarray = explode('-', $newfiltre);
@@ -532,6 +533,7 @@ if (isset($extrafields->attributes[$object->table_element]['computed']) && is_ar
 $i = 0;
 $total = 0;
 $totalarray = array();
+$totalarray['nbfield'] = 0;
 while ($i < ($limit ? min($num, $limit) : $num)) {
 	$obj = $db->fetch_object($resql);
 	if (empty($obj)) {
@@ -697,7 +699,12 @@ while ($i < ($limit ? min($num, $limit) : $num)) {
 		if (!$i) {
 			$totalarray['pos'][$totalarray['nbfield']] = 'totalttcfield';
 		}
-		$totalarray['val']['totalttcfield'] += $obj->amount;
+		if (!$i) {
+			$totalarray['val']['totalttcfield'] = $obj->amount;
+		} else {
+			$totalarray['val']['totalttcfield'] += $obj->amount;
+		}
+
 
 		// Extra fields
 		include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_print_fields.tpl.php';