diff --git a/htdocs/admin/resource.php b/htdocs/admin/resource.php
index a5a0b5fbf3f..3dfd8e1e2c2 100644
--- a/htdocs/admin/resource.php
+++ b/htdocs/admin/resource.php
@@ -127,6 +127,15 @@ print '';
print '
| ';
print '';
+
+print '';
+print '| '.$langs->trans('EnableResourceUsedInEventCheck').' | ';
+print '';
+echo ajax_constantonoff('RESOURCE_USED_IN_EVENT_CHECK');
+print ' | ';
+print ' | ';
+print '
';
+
print '';
print '';
diff --git a/htdocs/comm/action/card.php b/htdocs/comm/action/card.php
index 003203940a8..173770d725c 100644
--- a/htdocs/comm/action/card.php
+++ b/htdocs/comm/action/card.php
@@ -512,6 +512,65 @@ if ($action == 'update')
$ret = $extrafields->setOptionalsFromPost($extralabels, $object);
if ($ret < 0) $error++;
+ if (!$error) {
+ // check if an event resource is already in use
+ if (!empty($conf->global->RESOURCE_USED_IN_EVENT_CHECK) && $object->element == 'action') {
+ $eventDateStart = $object->datep;
+ $eventDateEnd = $object->datef;
+
+ $sql = "SELECT er.rowid, r.ref as r_ref, ac.id as ac_id, ac.label as ac_label";
+ $sql .= " FROM " . MAIN_DB_PREFIX . "element_resources as er";
+ $sql .= " INNER JOIN " . MAIN_DB_PREFIX . "resource as r ON r.rowid = er.resource_id AND er.resource_type = 'dolresource'";
+ $sql .= " INNER JOIN " . MAIN_DB_PREFIX . "actioncomm as ac ON ac.id = er.element_id AND er.element_type = '" . $db->escape($object->element) . "'";
+ $sql .= " WHERE ac.id != " . $object->id;
+ $sql .= " AND er.resource_id IN (";
+ $sql .= " SELECT resource_id FROM " . MAIN_DB_PREFIX . "element_resources";
+ $sql .= " WHERE element_id = " . $object->id;
+ $sql .= " AND element_type = '" . $db->escape($object->element) . "'";
+ $sql .= " AND busy = 1";
+ $sql .= ")";
+ $sql .= " AND er.busy = 1";
+ $sql .= " AND (";
+
+ // event date start between ac.datep and ac.datep2 (if datep2 is null we consider there is no end)
+ $sql .= " (ac.datep <= '" . $db->idate($eventDateStart) . "' AND (ac.datep2 IS NULL OR ac.datep2 >= '" . $db->idate($eventDateStart) . "'))";
+ // event date end between ac.datep and ac.datep2
+ if (!empty($eventDateEnd)) {
+ $sql .= " OR (ac.datep <= '" . $db->idate($eventDateEnd) . "' AND (ac.datep2 >= '" . $db->idate($eventDateEnd) . "'))";
+ }
+ // event date start before ac.datep and event date end after ac.datep2
+ $sql .= " OR (";
+ $sql .= "ac.datep >= '" . $db->idate($eventDateStart) . "'";
+ if (!empty($eventDateEnd)) {
+ $sql .= " AND (ac.datep2 IS NOT NULL AND ac.datep2 <= '" . $db->idate($eventDateEnd) . "')";
+ }
+ $sql .= ")";
+
+ $sql .= ")";
+ $resql = $db->query($sql);
+ if (!$resql) {
+ $error++;
+ $object->error = $db->lasterror();
+ $object->errors[] = $object->error;
+ } else {
+ if ($db->num_rows($resql) > 0) {
+ // already in use
+ $error++;
+ $object->error = $langs->trans('ErrorResourcesAlreadyInUse') . ' : ';
+ while ($obj = $db->fetch_object($resql)) {
+ $object->error .= '
- ' . $langs->trans('ErrorResourceUseInEvent', $obj->r_ref, $obj->ac_label . ' [' . $obj->ac_id . ']');
+ }
+ $object->errors[] = $object->error;
+ }
+ $db->free($resql);
+ }
+
+ if ($error) {
+ setEventMessages($object->error, $object->errors, 'errors');
+ }
+ }
+ }
+
if (! $error)
{
$db->begin();
diff --git a/htdocs/comm/action/index.php b/htdocs/comm/action/index.php
index 48165361d7c..d42b1b7d134 100644
--- a/htdocs/comm/action/index.php
+++ b/htdocs/comm/action/index.php
@@ -607,9 +607,7 @@ if ($resql)
$event->fk_element=$obj->fk_element;
$event->elementtype=$obj->elementtype;
- $event->societe->id=$obj->fk_soc;
$event->thirdparty_id=$obj->fk_soc;
- $event->contact->id=$obj->fk_contact;
$event->contact_id=$obj->fk_contact;
// Defined date_start_in_calendar and date_end_in_calendar property
@@ -1569,28 +1567,31 @@ function show_day_events($db, $day, $month, $year, $monthshown, $style, &$eventa
if ($event->type_code == 'ICALEVENT') print '
('.dol_trunc($event->icalname, $maxnbofchar).')';
+ $thirdparty_id = ($event->thirdparty_id > 0 ? $event->thirdparty_id : ((is_object($event->societe) && $event->societe->id > 0) ? $event->societe->id : 0));
+ $contact_id = ($event->contact_id > 0 ? $event->contact_id : ((is_object($event->contact) && $event->cotact->id > 0) ? $event->contact->id : 0));
+
// If action related to company / contact
$linerelatedto='';
- if (! empty($event->societe->id) && $event->societe->id > 0)
+ if ($thirdparty_id > 0)
{
- if (! isset($cachethirdparties[$event->societe->id]) || ! is_object($cachethirdparties[$event->societe->id]))
+ if (! isset($cachethirdparties[$thirdparty_id]) || ! is_object($cachethirdparties[$thirdparty_id]))
{
$thirdparty=new Societe($db);
- $thirdparty->fetch($event->societe->id);
- $cachethirdparties[$event->societe->id]=$thirdparty;
+ $thirdparty->fetch($thirdparty_id);
+ $cachethirdparties[$thirdparty_id]=$thirdparty;
}
- else $thirdparty=$cachethirdparties[$event->societe->id];
+ else $thirdparty=$cachethirdparties[$thirdparty_id];
if (! empty($thirdparty->id)) $linerelatedto.=$thirdparty->getNomUrl(1, '', 0);
}
- if (! empty($event->contact->id) && $event->contact->id > 0)
+ if (! empty($contact_id) && $contact_id > 0)
{
- if (! is_object($cachecontacts[$event->contact->id]))
+ if (! is_object($cachecontacts[$contact_id]))
{
$contact=new Contact($db);
- $contact->fetch($event->contact->id);
- $cachecontacts[$event->contact->id]=$contact;
+ $contact->fetch($contact_id);
+ $cachecontacts[$contact_id]=$contact;
}
- else $contact=$cachecontacts[$event->contact->id];
+ else $contact=$cachecontacts[$contact_id];
if ($linerelatedto) $linerelatedto.=' ';
if (! empty($contact->id)) $linerelatedto.=$contact->getNomUrl(1, '', 0);
}
diff --git a/htdocs/compta/bank/bankentries_list.php b/htdocs/compta/bank/bankentries_list.php
index 3522d8b6c9d..da8b110abd2 100644
--- a/htdocs/compta/bank/bankentries_list.php
+++ b/htdocs/compta/bank/bankentries_list.php
@@ -1376,7 +1376,7 @@ if ($resql)
// Debit
if (! empty($arrayfields['b.debit']['checked']))
{
- print '';
+ print ' | ';
if ($objp->amount < 0)
{
print price($objp->amount * -1);
@@ -1390,7 +1390,7 @@ if ($resql)
// Credit
if (! empty($arrayfields['b.credit']['checked']))
{
- print ' | ';
+ print ' | ';
if ($objp->amount > 0)
{
print price($objp->amount);
diff --git a/htdocs/core/class/commonobject.class.php b/htdocs/core/class/commonobject.class.php
index 26102b9b42a..817713f221b 100644
--- a/htdocs/core/class/commonobject.class.php
+++ b/htdocs/core/class/commonobject.class.php
@@ -7624,18 +7624,20 @@ abstract class CommonObject
}
// Delete cascade first
- foreach($this->childtablesoncascade as $table)
- {
- $sql = 'DELETE FROM '.MAIN_DB_PREFIX.$table.' WHERE '.$this->fk_element.' = '.$this->id;
- $resql = $this->db->query($sql);
- if (! $resql)
- {
- $this->error=$this->db->lasterror();
- $this->errors[]=$this->error;
- $this->db->rollback();
- return -1;
- }
- }
+ if (! empty($this->childtablesoncascade)) {
+ foreach($this->childtablesoncascade as $table)
+ {
+ $sql = 'DELETE FROM '.MAIN_DB_PREFIX.$table.' WHERE '.$this->fk_element.' = '.$this->id;
+ $resql = $this->db->query($sql);
+ if (! $resql)
+ {
+ $this->error=$this->db->lasterror();
+ $this->errors[]=$this->error;
+ $this->db->rollback();
+ return -1;
+ }
+ }
+ }
if (! $error) {
if (! $notrigger) {
@@ -7809,4 +7811,35 @@ abstract class CommonObject
}
}
}
+
+ /**
+ * copy related categories to another object
+ *
+ * @param int $fromId Id object source
+ * @param int $toId Id object cible
+ * @param string $type Type of category ('product', ...)
+ * @return int < 0 si erreur, > 0 si ok
+ */
+ public function cloneCategories($fromId, $toId, $type = '')
+ {
+ $this->db->begin();
+
+ if (empty($type)) $type = $this->table_element;
+
+ require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
+ $categorystatic = new Categorie($this->db);
+
+ $sql = "INSERT INTO ".MAIN_DB_PREFIX."categorie_" . $categorystatic->MAP_CAT_TABLE[$type] . " (fk_categorie, fk_product)";
+ $sql.= " SELECT fk_categorie, $toId FROM ".MAIN_DB_PREFIX."categorie_" . $categorystatic->MAP_CAT_TABLE[$type];
+ $sql.= " WHERE fk_product = '".$fromId."'";
+
+ if (! $this->db->query($sql))
+ {
+ $this->db->rollback();die($sql);
+ return -1;
+ }
+
+ $this->db->commit();
+ return 1;
+ }
}
diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php
index 12b5f63d7e1..86d02bcf22c 100644
--- a/htdocs/core/lib/functions.lib.php
+++ b/htdocs/core/lib/functions.lib.php
@@ -7265,7 +7265,7 @@ function printCommonFooter($zone = 'private')
{
print "\n";
print '/* JS CODE TO ENABLE to manage handler to switch left menu page (menuhider) */'."\n";
- print 'jQuery(".menuhider").click(function(event) {';
+ print 'jQuery("li.menuhider").click(function(event) {';
print ' if (!$( "body" ).hasClass( "sidebar-collapse" )){ event.preventDefault(); }'."\n";
print ' console.log("We click on .menuhider");'."\n";
print ' $("body").toggleClass("sidebar-collapse")'."\n";
diff --git a/htdocs/core/menus/standard/eldy.lib.php b/htdocs/core/menus/standard/eldy.lib.php
index a4eb2d57053..2eead6da81d 100644
--- a/htdocs/core/menus/standard/eldy.lib.php
+++ b/htdocs/core/menus/standard/eldy.lib.php
@@ -55,22 +55,23 @@ function print_eldy_menu($db, $atarget, $type_user, &$tabMenu, &$menu, $noout =
$usemenuhider = 1;
- // Show/Hide vertical menu
+ // Show/Hide vertical menu. The hamburger icon for .menuhider action.
if ($mode != 'jmobile' && $mode != 'topnb' && $usemenuhider && empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER))
{
$showmode=1;
$classname = 'class="tmenu menuhider"';
$idsel='menu';
- $menu->add('#', '', 0, $showmode, $atarget, "xxx", '', 0, $id, $idsel, $classname);
+ $menu->add('#', (! empty($conf->global->THEME_TOPMENU_DISABLE_IMAGE) ? '' : ''), 0, $showmode, $atarget, "xxx", '', 0, $id, $idsel, $classname);
}
$menu_arr = array();
+
// Home
$menu_arr[] = array(
'name' => 'Home',
'link' => '/index.php?mainmenu=home&leftmenu=home',
- 'title' => (! empty($conf->global->THEME_TOPMENU_DISABLE_IMAGE)? ' ' : "Home") ,
+ 'title' => (! empty($conf->global->THEME_TOPMENU_DISABLE_IMAGE) ? '' : "Home") ,
'level' => 0,
'enabled' => $showmode = 1,
'target' => $atarget,
@@ -473,8 +474,35 @@ function print_eldy_menu($db, $atarget, $type_user, &$tabMenu, &$menu, $noout =
$menu->liste = dol_sort_array($menu->liste, 'position');
// Output menu entries
+ // Show logo company
+ if (empty($conf->global->MAIN_MENU_INVERT) && empty($noout) && ! empty($conf->global->MAIN_SHOW_LOGO) && empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER))
+ {
+ $mysoc->logo_mini=$conf->global->MAIN_INFO_SOCIETE_LOGO_MINI;
+ $mysoc->logo_squarred_mini=$conf->global->MAIN_INFO_SOCIETE_LOGO_SQUARRED_MINI;
+ if (! empty($mysoc->logo_squarred_mini) && is_readable($conf->mycompany->dir_output.'/logos/thumbs/'.$mysoc->logo_squarred_mini))
+ {
+ $urllogo=DOL_URL_ROOT.'/viewimage.php?cache=1&modulepart=mycompany&file='.urlencode('logos/thumbs/'.$mysoc->logo_squarred_mini);
+ }
+ elseif (! empty($mysoc->logo_mini) && is_readable($conf->mycompany->dir_output.'/logos/thumbs/'.$mysoc->logo_mini))
+ {
+ $urllogo=DOL_URL_ROOT.'/viewimage.php?cache=1&modulepart=mycompany&file='.urlencode('logos/thumbs/'.$mysoc->logo_mini);
+ }
+ else
+ {
+ $urllogo=DOL_URL_ROOT.'/theme/dolibarr_logo_squarred.png';
+ }
+ $title=$langs->trans("GoIntoSetupToChangeLogo");
+
+ print "\n".''."\n";
+ print_start_menu_entry('companylogo', 'class="tmenu tmenucompanylogo"', 1);
+
+ print ''."\n";
+
+ print_end_menu_entry(4);
+ }
+
if (empty($noout)) {
- foreach($menu->liste as $menkey => $menuval) {
+ foreach($menu->liste as $menuval) {
print_start_menu_entry($menuval['idsel'], $menuval['classname'], $menuval['enabled']);
print_text_menu_entry($menuval['titre'], $menuval['enabled'], (($menuval['url']!='#' && !preg_match('/^(http:\/\/|https:\/\/)/i', $menuval['url'])) ? DOL_URL_ROOT:'').$menuval['url'], $menuval['id'], $menuval['idsel'], $menuval['classname'], ($menuval['target']?$menuval['target']:$atarget));
print_end_menu_entry($menuval['enabled']);
@@ -615,30 +643,6 @@ function print_left_eldy_menu($db, $menu_array_before, $menu_array_after, &$tabM
$usemenuhider = 0;
- // Show logo company
- if (empty($conf->global->MAIN_MENU_INVERT) && empty($noout) && ! empty($conf->global->MAIN_SHOW_LOGO) && empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER))
- {
- $mysoc->logo_mini=$conf->global->MAIN_INFO_SOCIETE_LOGO_MINI;
- if (! empty($mysoc->logo_mini) && is_readable($conf->mycompany->dir_output.'/logos/thumbs/'.$mysoc->logo_mini))
- {
- $urllogo=DOL_URL_ROOT.'/viewimage.php?cache=1&modulepart=mycompany&file='.urlencode('logos/thumbs/'.$mysoc->logo_mini);
- }
- else
- {
- $urllogo=DOL_URL_ROOT.'/theme/dolibarr_logo.png';
- }
- $title=$langs->trans("GoIntoSetupToChangeLogo");
- print "\n".''."\n";
- print ''."\n";
- }
-
if (is_array($moredata) && ! empty($moredata['searchform'])) // searchform can contains select2 code or link to show old search form or link to switch on search page
{
print "\n";
diff --git a/htdocs/core/modules/modStock.class.php b/htdocs/core/modules/modStock.class.php
index f3864525d8d..93afcdaebd7 100644
--- a/htdocs/core/modules/modStock.class.php
+++ b/htdocs/core/modules/modStock.class.php
@@ -316,17 +316,21 @@ class modStock extends DolibarrModules
$this->import_fields_array[$r]=array('e.ref'=>"LocationSummary*",
'e.description'=>"DescWareHouse",'e.lieu'=>"LieuWareHouse",
'e.address'=>"Address",'e.zip'=>'Zip','e.fk_pays'=>'CountryCode',
- 'e.statut'=>'Status'
+ 'e.statut'=>'Status',
+ 'e.fk_parent'=>'ParentWarehouse'
);
$this->import_convertvalue_array[$r]=array(
- 'e.fk_pays'=>array('rule'=>'fetchidfromcodeid','classfile'=>'/core/class/ccountry.class.php','class'=>'Ccountry','method'=>'fetch','dict'=>'DictionaryCountry')
+ 'e.fk_pays'=>array('rule'=>'fetchidfromcodeid','classfile'=>'/core/class/ccountry.class.php','class'=>'Ccountry','method'=>'fetch','dict'=>'DictionaryCountry'),
+ 'e.fk_parent'=>array('rule'=>'fetchidfromref','classfile'=>'/product/stock/class/entrepot.class.php','class'=>'Entrepot','method'=>'fetch','element'=>'ref')
);
$this->import_regex_array[$r]=array('e.statut'=>'^[0|1]');
$this->import_examplevalues_array[$r]=array('e.ref'=>"ALM001",
'e.description'=>"Central Warehouse",'e.lieu'=>"Central",
'e.address'=>"Route 66",'e.zip'=>'28080','e.fk_pays'=>'US',
- 'e.statut'=>'1');
+ 'e.statut'=>'1',
+ 'e.fk_parent'=>''
+ );
// Import stocks
$r++;
diff --git a/htdocs/install/mysql/data/llx_c_hrm_public_holiday.sql b/htdocs/install/mysql/data/llx_c_hrm_public_holiday.sql
index 70750494a10..737fe66f9da 100644
--- a/htdocs/install/mysql/data/llx_c_hrm_public_holiday.sql
+++ b/htdocs/install/mysql/data/llx_c_hrm_public_holiday.sql
@@ -70,7 +70,7 @@ INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, m
INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('AT-KONEGIE', 0, 41, '', 0, 6, 1, 1);
INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('AT-26OKT', 0, 41, '', 0, 10, 26, 1);
INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('AT-TOUSSAINT', 0, 41, '', 0, 11, 1, 1);
-INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('AT-IMMACULE', 0, 41, '', 0, 12 8, 1);
+INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('AT-IMMACULE', 0, 41, '', 0, 12, 8, 1);
INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('AT-24DEC', 0, 41, '', 0, 12, 24, 1);
INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('AT-SAINTSTEFAN', 0, 41, '', 0, 12, 26, 1);
INSERT INTO llx_c_hrm_public_holiday (code, entity, fk_country, dayrule, year, month, day, active) VALUES('AT-Silvester', 0, 41, '', 0, 12, 31, 1);
diff --git a/htdocs/langs/en_US/admin.lang b/htdocs/langs/en_US/admin.lang
index 9202e31308b..e530a8a47de 100644
--- a/htdocs/langs/en_US/admin.lang
+++ b/htdocs/langs/en_US/admin.lang
@@ -1907,6 +1907,7 @@ ResourceSetup=Configuration of Resource module
UseSearchToSelectResource=Use a search form to choose a resource (rather than a drop-down list).
DisabledResourceLinkUser=Disable feature to link a resource to users
DisabledResourceLinkContact=Disable feature to link a resource to contacts
+EnableResourceUsedInEventCheck=Enable feature to check if a resource is in use in an event
ConfirmUnactivation=Confirm module reset
OnMobileOnly=On small screen (smartphone) only
DisableProspectCustomerType=Disable the "Prospect + Customer" third party type (so third party must be Prospect or Customer but can't be both)
diff --git a/htdocs/langs/en_US/products.lang b/htdocs/langs/en_US/products.lang
index e0a1a5f8fcf..9919767db0f 100644
--- a/htdocs/langs/en_US/products.lang
+++ b/htdocs/langs/en_US/products.lang
@@ -153,6 +153,7 @@ RowMaterial=Raw Material
ConfirmCloneProduct=Are you sure you want to clone product or service %s?
CloneContentProduct=Clone all main information of product/service
ClonePricesProduct=Clone prices
+CloneCategoriesProduct=Clone tags/categories linked
CloneCompositionProduct=Clone virtual product/service
CloneCombinationsProduct=Clone product variants
ProductIsUsed=This product is used
diff --git a/htdocs/langs/en_US/resource.lang b/htdocs/langs/en_US/resource.lang
index 33a5046e006..134cc4c87a3 100644
--- a/htdocs/langs/en_US/resource.lang
+++ b/htdocs/langs/en_US/resource.lang
@@ -34,3 +34,6 @@ IdResource=Id resource
AssetNumber=Serial number
ResourceTypeCode=Resource type code
ImportDataset_resource_1=Resources
+
+ErrorResourcesAlreadyInUse=Some resources are in use
+ErrorResourceUseInEvent=%s use in %s event
\ No newline at end of file
diff --git a/htdocs/langs/fr_FR/admin.lang b/htdocs/langs/fr_FR/admin.lang
index ff684f01cb9..3d15d7fe3d4 100644
--- a/htdocs/langs/fr_FR/admin.lang
+++ b/htdocs/langs/fr_FR/admin.lang
@@ -1907,6 +1907,7 @@ ResourceSetup=Configuration du module Ressource
UseSearchToSelectResource=Utilisez un champ avec auto-complétion pour choisir les ressources (plutôt qu'une liste déroulante).
DisabledResourceLinkUser=Désactiver la fonctionnalité pour lier une ressource aux utilisateurs
DisabledResourceLinkContact=Désactiver la fonctionnalité pour lier une ressource aux contacts/adresses
+EnableResourceUsedInEventCheck=Activer la fonctionnalité de vérification d'une ressource déjà réservée lors d'un évènement
ConfirmUnactivation=Confirmer réinitialisation du module
OnMobileOnly=Sur petit écran (smartphone) uniquement
DisableProspectCustomerType=Désactiver le type de tiers "Prospect + Client" (le tiers doit donc être un client potentiel ou un client, mais ne peut pas être les deux)
diff --git a/htdocs/langs/fr_FR/products.lang b/htdocs/langs/fr_FR/products.lang
index a0473ad8c76..0248f6470a9 100644
--- a/htdocs/langs/fr_FR/products.lang
+++ b/htdocs/langs/fr_FR/products.lang
@@ -153,6 +153,8 @@ RowMaterial=Matière première
ConfirmCloneProduct=Êtes-vous sûr de vouloir cloner le produit ou service %s ?
CloneContentProduct=Cloner les informations générales du produit/service
ClonePricesProduct=Cloner les prix
+CloneCategoriesProduct=Cloner les catégories associées
+CloneCompositionProduct=Cloner le produits packagés
CloneCompositionProduct=Cloner les produits virtuels
CloneCombinationsProduct=Cloner les variantes
ProductIsUsed=Ce produit est utilisé
diff --git a/htdocs/langs/fr_FR/resource.lang b/htdocs/langs/fr_FR/resource.lang
index be7547b36da..5db22aedcbd 100644
--- a/htdocs/langs/fr_FR/resource.lang
+++ b/htdocs/langs/fr_FR/resource.lang
@@ -34,3 +34,6 @@ IdResource=id ressource
AssetNumber=Numéro de série
ResourceTypeCode=Code de type de ressource
ImportDataset_resource_1=Ressources
+
+ErrorResourcesAlreadyInUse=Des ressources sont déjà occupées
+ErrorResourceUseInEvent=%s occupée dans l'événement %s
\ No newline at end of file
diff --git a/htdocs/product/card.php b/htdocs/product/card.php
index 5be4dc43358..d6dd9e876cd 100644
--- a/htdocs/product/card.php
+++ b/htdocs/product/card.php
@@ -522,6 +522,19 @@ if (empty($reshook))
}
}
+ if (GETPOST('clone_categories'))
+ {
+ $result = $object->cloneCategories($originalId, $id);
+
+ if ($result < 1)
+ {
+ $db->rollback();
+ setEventMessage($langs->trans('ErrorProductClone'), null, 'errors');
+ header("Location: ".$_SERVER["PHP_SELF"]."?id=".$originalId);
+ exit;
+ }
+ }
+
// $object->clone_fournisseurs($originalId, $id);
$db->commit();
@@ -1951,6 +1964,7 @@ $formquestionclone=array(
'text' => $langs->trans("ConfirmClone"),
array('type' => 'text', 'name' => 'clone_ref','label' => $langs->trans("NewRefForClone"), 'value' => empty($tmpcode) ? $langs->trans("CopyOf").' '.$object->ref : $tmpcode, 'size'=>24),
array('type' => 'checkbox', 'name' => 'clone_content','label' => $langs->trans("CloneContentProduct"), 'value' => 1),
+ array('type' => 'checkbox', 'name' => 'clone_categories', 'label' => $langs->trans("CloneCategoriesProduct"), 'value' => 1),
array('type' => 'checkbox', 'name' => 'clone_prices', 'label' => $langs->trans("ClonePricesProduct").' ('.$langs->trans("FeatureNotYetAvailable").')', 'value' => 0, 'disabled' => true),
);
if (! empty($conf->global->PRODUIT_SOUSPRODUITS))
diff --git a/htdocs/product/class/api_products.class.php b/htdocs/product/class/api_products.class.php
index 446b4fa3cfe..812c2df7459 100644
--- a/htdocs/product/class/api_products.class.php
+++ b/htdocs/product/class/api_products.class.php
@@ -467,6 +467,94 @@ class Products extends DolibarrApi
);
}
+
+ /**
+ * List purchase prices
+ *
+ * Get a list of all purchase prices of products
+ *
+ * @param string $sortfield Sort field
+ * @param string $sortorder Sort order
+ * @param int $limit Limit for list
+ * @param int $page Page number
+ * @param int $mode Use this param to filter list (0 for all, 1 for only product, 2 for only service)
+ * @param int $category Use this param to filter list by category of product
+ * @param int $supplier Use this param to filter list by supplier
+ * @param string $sqlfilters Other criteria to filter answers separated by a comma. Syntax example "(t.tobuy:=:0) and (t.tosell:=:1)"
+ * @return array Array of product objects
+ *
+ * @url GET purchase_prices
+ */
+ public function getSupplierProducts($sortfield = "t.ref", $sortorder = 'ASC', $limit = 100, $page = 0, $mode = 0, $category = 0, $supplier = 0, $sqlfilters = '')
+ {
+ global $db, $conf;
+ $obj_ret = array();
+ $socid = DolibarrApiAccess::$user->societe_id ? DolibarrApiAccess::$user->societe_id : '';
+ $sql = "SELECT t.rowid, t.ref, t.ref_ext";
+ $sql.= " FROM ".MAIN_DB_PREFIX."product as t";
+ if ($category > 0) {
+ $sql.= ", ".MAIN_DB_PREFIX."categorie_product as c";
+ }
+ $sql.= ", ".MAIN_DB_PREFIX."product_fournisseur_price as s";
+
+ $sql.= ' WHERE t.entity IN ('.getEntity('product').')';
+
+ if ($supplier > 0) {
+ $sql.= " AND s.fk_soc = ".$db->escape($supplier);
+ }
+ $sql.= " AND s.fk_product = t.rowid ";
+ // Select products of given category
+ if ($category > 0) {
+ $sql.= " AND c.fk_categorie = ".$db->escape($category);
+ $sql.= " AND c.fk_product = t.rowid ";
+ }
+ if ($mode == 1) {
+ // Show only products
+ $sql.= " AND t.fk_product_type = 0";
+ } elseif ($mode == 2) {
+ // Show only services
+ $sql.= " AND t.fk_product_type = 1";
+ }
+ // Add sql filters
+ if ($sqlfilters) {
+ if (! DolibarrApi::_checkFilters($sqlfilters)) {
+ throw new RestException(503, 'Error when validating parameter sqlfilters '.$sqlfilters);
+ }
+ $regexstring='\(([^:\'\(\)]+:[^:\'\(\)]+:[^:\(\)]+)\)';
+ $sql.=" AND (".preg_replace_callback('/'.$regexstring.'/', 'DolibarrApi::_forge_criteria_callback', $sqlfilters).")";
+ }
+ $sql.= $db->order($sortfield, $sortorder);
+ if ($limit) {
+ if ($page < 0) {
+ $page = 0;
+ }
+ $offset = $limit * $page;
+ $sql.= $db->plimit($limit + 1, $offset);
+ }
+ $result = $db->query($sql);
+ if ($result) {
+ $num = $db->num_rows($result);
+ $min = min($num, ($limit <= 0 ? $num : $limit));
+ $i = 0;
+ while ($i < $min)
+ {
+ $obj = $db->fetch_object($result);
+ $product_static = new Product($db);
+ if($product_static->fetch($obj->rowid)) {
+ $obj_ret[] = $this->_cleanObjectDatas($product_static);
+ }
+ $i++;
+ }
+ }
+ else {
+ throw new RestException(503, 'Error when retrieve product list : '.$db->lasterror());
+ }
+ if(! count($obj_ret)) {
+ throw new RestException(404, 'No product found');
+ }
+ return $obj_ret;
+ }
+
/**
* Get purchase prices for a product
*
@@ -515,7 +603,7 @@ class Products extends DolibarrApi
if($result) {
$this->product = new ProductFournisseur($this->db);
$this->product->fetch($id, $ref);
- $this->product->list_product_fournisseur_price($id, $sortfield, $sortorder, 0, 0);
+ $this->product->list_product_fournisseur_price($id, '', '', 0, 0);
}
return $this->_cleanObjectDatas($this->product);
diff --git a/htdocs/resource/element_resource.php b/htdocs/resource/element_resource.php
index 02565a23dd0..bb9a54a9bf0 100644
--- a/htdocs/resource/element_resource.php
+++ b/htdocs/resource/element_resource.php
@@ -87,6 +87,8 @@ if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'e
if (empty($reshook))
{
+ $error = 0;
+
if ($action == 'add_element_resource' && ! $cancel)
{
$res = 0;
@@ -100,8 +102,68 @@ if (empty($reshook))
{
$objstat = fetchObjectByElement($element_id, $element, $element_ref);
$objstat->element = $element; // For externals module, we need to keep @xx
- $res = $objstat->add_element_resource($resource_id, $resource_type, $busy, $mandatory);
+
+ // TODO : add this check at update_linked_resource and when modifying event start or end date
+ // check if an event resource is already in use
+ if (!empty($conf->global->RESOURCE_USED_IN_EVENT_CHECK) && $objstat->element=='action' && $resource_type=='dolresource' && intval($busy)==1) {
+ $eventDateStart = $objstat->datep;
+ $eventDateEnd = $objstat->datef;
+ $isFullDayEvent = intval($objstat->fulldayevent);
+ if (empty($eventDateEnd)) {
+ if ($isFullDayEvent) {
+ $eventDateStartArr = dol_getdate($eventDateStart);
+ $eventDateStart = dol_mktime(0, 0, 0, $eventDateStartArr['mon'], $eventDateStartArr['mday'], $eventDateStartArr['year']);
+ $eventDateEnd = dol_mktime(23, 59, 59, $eventDateStartArr['mon'], $eventDateStartArr['mday'], $eventDateStartArr['year']);
+ }
+ }
+
+ $sql = "SELECT er.rowid, r.ref as r_ref, ac.id as ac_id, ac.label as ac_label";
+ $sql .= " FROM " . MAIN_DB_PREFIX . "element_resources as er";
+ $sql .= " INNER JOIN " . MAIN_DB_PREFIX . "resource as r ON r.rowid = er.resource_id AND er.resource_type = '" . $db->escape($resource_type) . "'";
+ $sql .= " INNER JOIN " . MAIN_DB_PREFIX . "actioncomm as ac ON ac.id = er.element_id AND er.element_type = '" . $db->escape($objstat->element) . "'";
+ $sql .= " WHERE er.resource_id = " . $resource_id;
+ $sql .= " AND er.busy = 1";
+ $sql .= " AND (";
+
+ // event date start between ac.datep and ac.datep2 (if datep2 is null we consider there is no end)
+ $sql .= " (ac.datep <= '" . $db->idate($eventDateStart) . "' AND (ac.datep2 IS NULL OR ac.datep2 >= '" . $db->idate($eventDateStart) . "'))";
+ // event date end between ac.datep and ac.datep2
+ if (!empty($eventDateEnd)) {
+ $sql .= " OR (ac.datep <= '" . $db->idate($eventDateEnd) . "' AND (ac.datep2 >= '" . $db->idate($eventDateEnd) . "'))";
+ }
+ // event date start before ac.datep and event date end after ac.datep2
+ $sql .= " OR (";
+ $sql .= "ac.datep >= '" . $db->idate($eventDateStart) . "'";
+ if (!empty($eventDateEnd)) {
+ $sql .= " AND (ac.datep2 IS NOT NULL AND ac.datep2 <= '" . $db->idate($eventDateEnd) . "')";
+ }
+ $sql .= ")";
+
+ $sql .= ")";
+ $resql = $db->query($sql);
+ if (!$resql) {
+ $error++;
+ $objstat->error = $db->lasterror();
+ $objstat->errors[] = $objstat->error;
+ } else {
+ if ($db->num_rows($resql)>0) {
+ // already in use
+ $error++;
+ $objstat->error = $langs->trans('ErrorResourcesAlreadyInUse') . ' : ';
+ while ($obj = $db->fetch_object($resql)) {
+ $objstat->error .= ' - ' . $langs->trans('ErrorResourceUseInEvent', $obj->r_ref, $obj->ac_label . ' [' . $obj->ac_id . ']');
+ }
+ $objstat->errors[] = $objstat->error;
+ }
+ $db->free($resql);
+ }
+ }
+
+ if (!$error) {
+ $res = $objstat->add_element_resource($resource_id, $resource_type, $busy, $mandatory);
+ }
}
+
if (! $error && $res > 0)
{
setEventMessages($langs->trans('ResourceLinkedWithSuccess'), null, 'mesgs');
@@ -123,18 +185,73 @@ if (empty($reshook))
$object->busy = $busy;
$object->mandatory = $mandatory;
- $result = $object->update_element_resource($user);
+ if (!empty($conf->global->RESOURCE_USED_IN_EVENT_CHECK) && $object->element_type=='action' && $object->resource_type=='dolresource' && intval($object->busy)==1) {
+ $eventDateStart = $object->objelement->datep;
+ $eventDateEnd = $object->objelement->datef;
+ $isFullDayEvent = intval($objstat->fulldayevent);
+ if (empty($eventDateEnd)) {
+ if ($isFullDayEvent) {
+ $eventDateStartArr = dol_getdate($eventDateStart);
+ $eventDateStart = dol_mktime(0, 0, 0, $eventDateStartArr['mon'], $eventDateStartArr['mday'], $eventDateStartArr['year']);
+ $eventDateEnd = dol_mktime(23, 59, 59, $eventDateStartArr['mon'], $eventDateStartArr['mday'], $eventDateStartArr['year']);
+ }
+ }
- if ($result >= 0)
- {
+ $sql = "SELECT er.rowid, r.ref as r_ref, ac.id as ac_id, ac.label as ac_label";
+ $sql .= " FROM " . MAIN_DB_PREFIX . "element_resources as er";
+ $sql .= " INNER JOIN " . MAIN_DB_PREFIX . "resource as r ON r.rowid = er.resource_id AND er.resource_type = '" . $db->escape($object->resource_type) . "'";
+ $sql .= " INNER JOIN " . MAIN_DB_PREFIX . "actioncomm as ac ON ac.id = er.element_id AND er.element_type = '" . $db->escape($object->element_type) . "'";
+ $sql .= " WHERE er.resource_id = " . $object->resource_id;
+ $sql .= " AND ac.id != " . $object->element_id;
+ $sql .= " AND er.busy = 1";
+ $sql .= " AND (";
+
+ // event date start between ac.datep and ac.datep2 (if datep2 is null we consider there is no end)
+ $sql .= " (ac.datep <= '" . $db->idate($eventDateStart) . "' AND (ac.datep2 IS NULL OR ac.datep2 >= '" . $db->idate($eventDateStart) . "'))";
+ // event date end between ac.datep and ac.datep2
+ if (!empty($eventDateEnd)) {
+ $sql .= " OR (ac.datep <= '" . $db->idate($eventDateEnd) . "' AND (ac.datep2 IS NULL OR ac.datep2 >= '" . $db->idate($eventDateEnd) . "'))";
+ }
+ // event date start before ac.datep and event date end after ac.datep2
+ $sql .= " OR (";
+ $sql .= "ac.datep >= '" . $db->idate($eventDateStart) . "'";
+ if (!empty($eventDateEnd)) {
+ $sql .= " AND (ac.datep2 IS NOT NULL AND ac.datep2 <= '" . $db->idate($eventDateEnd) . "')";
+ }
+ $sql .= ")";
+
+ $sql .= ")";
+ $resql = $db->query($sql);
+ if (!$resql) {
+ $error++;
+ $object->error = $db->lasterror();
+ $object->errors[] = $object->error;
+ } else {
+ if ($db->num_rows($resql)>0) {
+ // already in use
+ $error++;
+ $object->error = $langs->trans('ErrorResourcesAlreadyInUse') . ' : ';
+ while ($obj = $db->fetch_object($resql)) {
+ $object->error .= ' - ' . $langs->trans('ErrorResourceUseInEvent', $obj->r_ref, $obj->ac_label . ' [' . $obj->ac_id . ']');
+ }
+ $object->errors[] = $objstat->error;
+ }
+ $db->free($resql);
+ }
+ }
+
+ if (!$error) {
+ $result = $object->update_element_resource($user);
+ if ($result < 0) $error++;
+ }
+
+ if ($error) {
+ setEventMessages($object->error, $object->errors, 'errors');
+ } else {
setEventMessages($langs->trans('RessourceLineSuccessfullyUpdated'), null, 'mesgs');
header("Location: ".$_SERVER['PHP_SELF']."?element=".$element."&element_id=".$element_id);
exit;
}
- else
- {
- setEventMessages($object->error, $object->errors, 'errors');
- }
}
}
diff --git a/htdocs/societe/class/societe.class.php b/htdocs/societe/class/societe.class.php
index 86408c482cc..42fb797eceb 100644
--- a/htdocs/societe/class/societe.class.php
+++ b/htdocs/societe/class/societe.class.php
@@ -3915,17 +3915,17 @@ class Societe extends CommonObject
while($obj=$this->db->fetch_object($resql)) {
$tmpobject->id=$obj->rowid;
- if ($obj->fk_statut != Facture::STATUS_DRAFT // Not a draft
- && ! ($obj->fk_statut == Facture::STATUS_ABANDONED && $obj->close_code == 'replaced') // Not a replaced invoice
+ if ($obj->fk_statut != $tmpobject::STATUS_DRAFT // Not a draft
+ && ! ($obj->fk_statut == $tmpobject::STATUS_ABANDONED && $obj->close_code == 'replaced') // Not a replaced invoice
)
{
$outstandingTotal+= $obj->total_ht;
$outstandingTotalIncTax+= $obj->total_ttc;
}
if ($obj->paye == 0
- && $obj->fk_statut != Facture::STATUS_DRAFT // Not a draft
- && $obj->fk_statut != Facture::STATUS_ABANDONED // Not abandonned
- && $obj->fk_statut != Facture::STATUS_CLOSED) // Not classified as paid
+ && $obj->fk_statut != $tmpobject::STATUS_DRAFT // Not a draft
+ && $obj->fk_statut != $tmpobject::STATUS_ABANDONED // Not abandonned
+ && $obj->fk_statut != $tmpobject::STATUS_CLOSED) // Not classified as paid
//$sql .= " AND (fk_statut <> 3 OR close_code <> 'abandon')"; // Not abandonned for undefined reason
{
$paiement = $tmpobject->getSommePaiement();
@@ -3936,7 +3936,11 @@ class Societe extends CommonObject
}
//if credit note is converted but not used
- if($mode == 'supplier' && $obj->type == FactureFournisseur::TYPE_CREDIT_NOTE && $tmpobject->isCreditNoteUsed())$outstandingOpened-=$tmpobject->getSumFromThisCreditNotesNotUsed();
+ // TODO Do this also for customer ?
+ if($mode == 'supplier' && $obj->type == FactureFournisseur::TYPE_CREDIT_NOTE && $tmpobject->isCreditNoteUsed())
+ {
+ $outstandingOpened-=$tmpobject->getSumFromThisCreditNotesNotUsed();
+ }
}
return array('opened'=>$outstandingOpened, 'total_ht'=>$outstandingTotal, 'total_ttc'=>$outstandingTotalIncTax); // 'opened' is 'incl taxes'
}
diff --git a/htdocs/stripe/admin/stripe.php b/htdocs/stripe/admin/stripe.php
index 02039f3edc2..c3c008a5874 100644
--- a/htdocs/stripe/admin/stripe.php
+++ b/htdocs/stripe/admin/stripe.php
@@ -221,7 +221,7 @@ if (empty($conf->stripeconnect->enabled))
$endpoint = \Stripe\WebhookEndpoint::retrieve($conf->global->STRIPE_TEST_WEBHOOK_ID);
$endpoint->enabled_events = $stripearrayofwebhookevents;
if (GETPOST('webhook', 'alpha') == $conf->global->STRIPE_TEST_WEBHOOK_ID) {
- if (empty(GETPOST('status', 'alpha'))) {
+ if (! GETPOST('status', 'alpha')) {
$endpoint->disabled = true;
} else {
$endpoint->disabled = false;
diff --git a/htdocs/theme/dolibarr_logo_squarred.png b/htdocs/theme/dolibarr_logo_squarred.png
new file mode 100644
index 00000000000..bd8d7ac3bfd
Binary files /dev/null and b/htdocs/theme/dolibarr_logo_squarred.png differ
diff --git a/htdocs/theme/eldy/global.inc.php b/htdocs/theme/eldy/global.inc.php
index cbb69df74f9..533608aa132 100644
--- a/htdocs/theme/eldy/global.inc.php
+++ b/htdocs/theme/eldy/global.inc.php
@@ -1058,6 +1058,41 @@ div.blockvmenulogo
{
border-bottom: 0 !important;
}
+.backgroundforcompanylogo {
+ margin: px;
+ margin-left: 8px;
+ margin-right: 8px;
+ background-color: rgba(255,255,255,0.7);
+ padding: 0;
+ border-radius: 5px;
+ height: px;
+ /* width: 100px; */
+ max-width: 100px;
+ vertical-align: middle;
+}
+.backgroundforcompanylogo img.mycompany {
+ object-fit: contain;
+ width: inherit;
+ height: inherit;
+}
+#mainmenutd_companylogo::after, #mainmenutd_menu::after {
+ content: unset !important;
+}
+li#mainmenutd_companylogo .tmenucenter {
+ width: unset;
+}
+li#mainmenutd_companylogo {
+ min-width: unset !important;
+}
+
+ li#mainmenutd_home {
+ min-width: unset !important;
+ }
+ li#mainmenutd_home .tmenucenter {
+ width: unset;
+ }
+
+
div.blockvmenupair, div.blockvmenuimpair {
border-top: none !important;
border-left: none !important;
@@ -1504,9 +1539,6 @@ li.tmenu, li.tmenusel {
li.menuhider:hover {
background-image: none !important;
}
-li.tmenusel, li.tmenu:hover {
- /* background: rgba(0, 0, 0, 0.1); */
-}
li.tmenusel::after, li.tmenu:hover::after{
content: "";
@@ -1559,7 +1591,7 @@ div.tmenucenter
padding-top: 2px;
height: px;
- width: 100%;
+ /* width: 100%; */
}
#menu_titre_logo {
padding-top: 0;
@@ -1965,8 +1997,8 @@ div.login_block_other { padding-top: 0; text-align: right; margin-right: 8px; }
float: right;
vertical-align: top;
padding: 0px 3px 0px 4px !important;
- line-height: 50px;
- height: 50px;
+ line-height: px;
+ height: px;
}
.atoplogin, .atoplogin:hover {
color: # !important;
@@ -2003,8 +2035,8 @@ img.login, img.printer, img.entity {
font-weight: bold;
}
.userimg.atoplogin img.userphoto, .userimgatoplogin img.userphoto { /* size for user photo in login bar */
- width: 32px;
- height: 32px;
+ width: px;
+ height: px;
border-radius: 50%;
background-size: contain;
background-size: contain;
@@ -2618,7 +2650,7 @@ table.liste th, table.noborder th, table.noborder tr.liste_titre td, table.nobor
}
table.liste td, table.noborder td, div.noborder form div, table.tableforservicepart1 td, table.tableforservicepart2 td {
padding: 7px 8px 7px 8px; /* t r b l */
- line-height: 22px;
+ /* line-height: 22px; This create trouble on cell login on list of last events of a contract*/
height: 22px;
}
div.liste_titre_bydiv .divsearchfield {
@@ -5641,7 +5673,7 @@ div.tabsElem a.tab {
/* nboftopmenuentries = , fontsize= */
/* rule to reduce top menu - 1st reduction: Reduce width of top menu icons */
-@media only screen and (max-width: global->THEME_ELDY_WITDHOFFSET_FOR_REDUC1) ? round($nbtopmenuentries * 90, 0) + 240 : $conf->global->THEME_ELDY_WITDHOFFSET_FOR_REDUC1; ?>px) /* reduction 1 */
+@media only screen and (max-width: global->THEME_ELDY_WITDHOFFSET_FOR_REDUC1) ? round($nbtopmenuentries * 90, 0) + 340 : $conf->global->THEME_ELDY_WITDHOFFSET_FOR_REDUC1; ?>px) /* reduction 1 */
{
div.tmenucenter {
width: px; /* size of viewport */
@@ -5674,8 +5706,11 @@ div.tabsElem a.tab {
}
}
/* rule to reduce top menu - 2nd reduction: Reduce width of top menu icons again */
-@media only screen and (max-width: global->THEME_ELDY_WITDHOFFSET_FOR_REDUC2) ? round($nbtopmenuentries * 69, 0) + 40 : $conf->global->THEME_ELDY_WITDHOFFSET_FOR_REDUC2; ?>px) /* reduction 2 */
+@media only screen and (max-width: global->THEME_ELDY_WITDHOFFSET_FOR_REDUC2) ? round($nbtopmenuentries * 69, 0) + 140 : $conf->global->THEME_ELDY_WITDHOFFSET_FOR_REDUC2; ?>px) /* reduction 2 */
{
+ li.tmenucompanylogo {
+ display: none;
+ }
div.mainmenu {
height: 23px;
}
@@ -5698,7 +5733,7 @@ div.tabsElem a.tab {
}
}
/* rule to reduce top menu - 3rd reduction: The menu for user is on left */
-@media only screen and (max-width: global->THEME_ELDY_WITDHOFFSET_FOR_REDUC3) ? round($nbtopmenuentries * 47, 0) + 40 : $conf->global->THEME_ELDY_WITDHOFFSET_FOR_REDUC3; ?>px) /* reduction 3 */
+@media only screen and (max-width: global->THEME_ELDY_WITDHOFFSET_FOR_REDUC3) ? round($nbtopmenuentries * 47, 0) + 140 : $conf->global->THEME_ELDY_WITDHOFFSET_FOR_REDUC3; ?>px) /* reduction 3 */
{
.side-nav {
z-index: 200;
diff --git a/htdocs/theme/md/style.css.php b/htdocs/theme/md/style.css.php
index ebf6b1df23d..ab965b1d3d3 100644
--- a/htdocs/theme/md/style.css.php
+++ b/htdocs/theme/md/style.css.php
@@ -1948,6 +1948,11 @@ foreach($mainmenuusedarray as $val)
display: none;
}
+.topmenuimage {
+
+ display: none;
+
+}
a.tmenuimage {
display: block;
}
@@ -2232,6 +2237,41 @@ div.blockvmenulogo
{
border-bottom: 0 !important;
}
+.backgroundforcompanylogo {
+ margin: px;
+ margin-left: 12px;
+ margin-right: 6px;
+ background-color: rgba(255,255,255,0.7);
+ padding: 0;
+ border-radius: 5px;
+ height: px;
+ /* width: 100px; */
+ max-width: 100px;
+ vertical-align: middle;
+}
+.backgroundforcompanylogo img.mycompany {
+ object-fit: contain;
+ width: inherit;
+ height: inherit;
+}
+#mainmenutd_companylogo::after {
+ content: unset;
+}
+li#mainmenutd_companylogo .tmenucenter {
+ width: unset;
+}
+li#mainmenutd_companylogo {
+ min-width: unset !important;
+}
+
+ li#mainmenutd_home {
+ min-width: unset !important;
+ }
+ li#mainmenutd_home .tmenucenter {
+ width: unset;
+ }
+
+
div.blockvmenupair, div.blockvmenuimpair
{
font-family: ;
@@ -5624,13 +5664,13 @@ border-top-right-radius: 6px;
}
.menuhider {
- width: 40px;
+ width: px;
}
/* nboftopmenuentries = , fontsize= */
/* disableimages = */
/* rule to reduce top menu - 1st reduction */
-@media only screen and (max-width: px)
+@media only screen and (max-width: px)
{
div.tmenucenter {
max-width: px; /* size of viewport */
@@ -5657,8 +5697,12 @@ border-top-right-radius: 6px;
}
}
/* rule to reduce top menu - 2nd reduction */
-@media only screen and (max-width: px)
+@media only screen and (max-width: px)
{
+ li.tmenucompanylogo {
+ display: none;
+ }
+
div.tmenucenter {
max-width: px; /* size of viewport */
text-overflow: clip;
diff --git a/htdocs/user/perms.php b/htdocs/user/perms.php
index 2560ccc7f04..137ac659fd7 100644
--- a/htdocs/user/perms.php
+++ b/htdocs/user/perms.php
@@ -58,7 +58,8 @@ if (! empty($conf->global->MAIN_USE_ADVANCED_PERMS))
$socid=0;
if (isset($user->societe_id) && $user->societe_id > 0) $socid = $user->societe_id;
$feature2 = (($socid && $user->rights->user->self->creer)?'':'user');
-if ($user->id == $id && (! empty($conf->global->MAIN_USE_ADVANCED_PERMS) && empty($user->rights->user->self_advance->readperms))) // A user can always read its own card if not advanced perms enabled, or if he has advanced perms
+// A user can always read its own card if not advanced perms enabled, or if he has advanced perms, except for admin
+if ($user->id == $id && (! empty($conf->global->MAIN_USE_ADVANCED_PERMS) && empty($user->rights->user->self_advance->readperms) && empty($user->admin)))
{
accessforbidden();
}
diff --git a/htdocs/website/index.php b/htdocs/website/index.php
index 5d4c259bf9c..6394428bd42 100644
--- a/htdocs/website/index.php
+++ b/htdocs/website/index.php
@@ -3308,7 +3308,7 @@ if ($action == 'replacesite' || $action == 'replacesiteconfirm')
print ' | ';
print '| '.$langs->trans("Container").' | ';
print '';
- print 'ref.'&pageid='.$answerrecord->id.'">'.$answerrecord->title.'';
+ print 'ref.'&pageid='.$answerrecord->id.'">'.($answerrecord->title ? $answerrecord->title : $langs->trans("NoTitle")).'';
print ' | ';
print ''.$answerrecord->description;
print ' | ';