diff --git a/htdocs/install/mysql/migration/15.0.0-16.0.0.sql b/htdocs/install/mysql/migration/15.0.0-16.0.0.sql
index b57cab5b4eb..c2cb299a63c 100644
--- a/htdocs/install/mysql/migration/15.0.0-16.0.0.sql
+++ b/htdocs/install/mysql/migration/15.0.0-16.0.0.sql
@@ -648,4 +648,7 @@ ALTER TABLE llx_paiement MODIFY COLUMN ext_payment_id varchar(255);
ALTER TABLE llx_payment_donation MODIFY COLUMN ext_payment_id varchar(255);
ALTER TABLE llx_prelevement_facture_demande MODIFY COLUMN ext_payment_id varchar(255);
+ALTER TABLE llx_product ADD COLUMN fk_default_workstation integer DEFAULT NULL;
+
+
diff --git a/htdocs/install/mysql/tables/llx_product.sql b/htdocs/install/mysql/tables/llx_product.sql
index 83e8882caa7..9b124c8fede 100644
--- a/htdocs/install/mysql/tables/llx_product.sql
+++ b/htdocs/install/mysql/tables/llx_product.sql
@@ -107,4 +107,5 @@ create table llx_product
mandatory_period tinyint DEFAULT 0, -- is used to signal to the user that the start and end dates are mandatory for this type of product the fk_product_type == 1 (service) (non-blocking action)
fk_default_bom integer DEFAULT NULL
+ fk_default_workstation integer DEFAULT NULL
)ENGINE=innodb;
diff --git a/htdocs/langs/fr_FR/mrp.lang b/htdocs/langs/fr_FR/mrp.lang
index e65244b584f..6211db86e72 100644
--- a/htdocs/langs/fr_FR/mrp.lang
+++ b/htdocs/langs/fr_FR/mrp.lang
@@ -91,6 +91,7 @@ WorkstationSetup = Configuration du module Poste de travail
WorkstationSetupPage = Configuration du module Poste de travail
WorkstationList=Liste des postes de travail
WorkstationCreate=Ajouter un nouveau poste de travail
+DefaultWorkstation=Poste de travail par défaut
ConfirmEnableWorkstation=Voulez-vous vraiment activer le poste de travail %s?
EnableAWorkstation=Activer le module Poste de travail
ConfirmDisableWorkstation=Voulez-vous vraiment désactiver la station de travail %s?
diff --git a/htdocs/product/card.php b/htdocs/product/card.php
index d0b7e4ece73..087c7bc11ce 100644
--- a/htdocs/product/card.php
+++ b/htdocs/product/card.php
@@ -52,6 +52,7 @@ require_once DOL_DOCUMENT_ROOT.'/core/lib/product.lib.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php';
require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
require_once DOL_DOCUMENT_ROOT.'/core/modules/product/modules_product.class.php';
+require_once DOL_DOCUMENT_ROOT.'/workstation/class/workstation.class.php';
if (!empty($conf->propal->enabled)) {
require_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php';
@@ -552,6 +553,7 @@ if (empty($reshook)) {
$object->duration_value = $duration_value;
$object->duration_unit = $duration_unit;
$object->fk_default_warehouse = GETPOST('fk_default_warehouse');
+ $object->fk_default_workstation = GETPOST('fk_default_workstation');
$object->seuil_stock_alerte = GETPOST('seuil_stock_alerte') ?GETPOST('seuil_stock_alerte') : 0;
$object->desiredstock = GETPOST('desiredstock') ?GETPOST('desiredstock') : 0;
$object->canvas = GETPOST('canvas');
@@ -704,6 +706,7 @@ if (empty($reshook)) {
$object->status_batch = GETPOST('status_batch', 'aZ09');
$object->batch_mask = GETPOST('batch_mask', 'alpha');
$object->fk_default_warehouse = GETPOST('fk_default_warehouse');
+ $object->fk_default_workstation = GETPOST('fk_default_workstation');
// removed from update view so GETPOST always empty
/*
$object->seuil_stock_alerte = GETPOST('seuil_stock_alerte');
@@ -1996,6 +1999,15 @@ if (is_object($objcanvas) && $objcanvas->displayCanvasExists($action)) {
print '';
*/
}
+
+ if($object->isService() && $conf->workstation->enabled) {
+ // Default workstation
+ print '
| '.$langs->trans("DefaultWorkstation").' | ';
+ print img_picto($langs->trans("DefaultWorkstation"), 'workstation', 'class="pictofixedwidth"');
+ print $formproduct->selectWorkstations($object->fk_default_workstation, 'fk_default_workstation', 1);
+ print ' |
';
+ }
+
/*
else
{
@@ -2475,6 +2487,15 @@ if (is_object($objcanvas) && $objcanvas->displayCanvasExists($action)) {
print '';
}
+ if($object->isService() && $conf->workstation->enabled) {
+ $workstation = new Workstation($db);
+ $workstation->fetch($object->fk_default_workstation);
+
+ print '| '.$langs->trans("DefaultWorkstation").' | ';
+ print (!empty($workstation->id) ? $workstation->getNomUrl(1) : '');
+ print ' | ';
+ }
+
// Parent product.
if (!empty($conf->variants->enabled) && ($object->isProduct() || $object->isService())) {
$combination = new ProductCombination($db);
diff --git a/htdocs/product/class/html.formproduct.class.php b/htdocs/product/class/html.formproduct.class.php
index 4ede9e1e297..d6017877375 100644
--- a/htdocs/product/class/html.formproduct.class.php
+++ b/htdocs/product/class/html.formproduct.class.php
@@ -42,6 +42,7 @@ class FormProduct
// Cache arrays
public $cache_warehouses = array();
public $cache_lot = array();
+ public $cache_workstations = array();
/**
@@ -172,6 +173,63 @@ class FormProduct
}
}
+ /**
+ * Load in cache array list of workstations
+ * If fk_product is not 0, we do not use cache
+ *
+ * @param int $fk_product Add quantity of stock in label for product with id fk_product. Nothing if 0.
+ * @param array $exclude warehouses ids to exclude
+ * @param string $orderBy [='e.ref'] Order by
+ * @return int Nb of loaded lines, 0 if already loaded, <0 if KO
+ * @throws Exception
+ */
+ public function loadWorkstations($fk_product = 0, $exclude = array(), $orderBy = 'w.ref')
+ {
+ global $conf, $langs;
+
+ if (empty($fk_product) && count($this->cache_workstations)) {
+ return 0; // Cache already loaded and we do not want a list with information specific to a product
+ }
+
+ $sql = "SELECT w.rowid, w.ref as label, w.type, w.nb_operators_required,w.thm_operator_estimated,w.thm_machine_estimated";
+ $sql .= " FROM ".$this->db->prefix()."workstation_workstation as w";
+ $sql .= " WHERE 1 = 1";
+ if (!empty($fk_product) && $fk_product > 0) {
+ $sql .= " AND w.fk_product = ".((int) $fk_product);
+ }
+ $sql .= " AND w.entity IN (".getEntity('workstation').")";
+
+ if (is_array($exclude) && !empty($exclude)) {
+ $sql .= ' AND w.rowid NOT IN('.$this->db->sanitize(implode(',', $exclude)).')';
+ }
+
+ $sql .= " ORDER BY ".$orderBy;
+
+ dol_syslog(get_class($this).'::loadWorkstations', LOG_DEBUG);
+ $resql = $this->db->query($sql);
+ if ($resql) {
+ $num = $this->db->num_rows($resql);
+ $i = 0;
+ while ($i < $num) {
+ $obj = $this->db->fetch_object($resql);
+
+ $this->cache_workstations[$obj->rowid]['id'] = $obj->rowid;
+ $this->cache_workstations[$obj->rowid]['ref'] = $obj->ref;
+ $this->cache_workstations[$obj->rowid]['label'] = $obj->label;
+ $this->cache_workstations[$obj->rowid]['type'] = $obj->type;
+ $this->cache_workstations[$obj->rowid]['nb_operators_required'] = $obj->nb_operators_required;
+ $this->cache_workstations[$obj->rowid]['thm_operator_estimated'] = $obj->thm_operator_estimated;
+ $this->cache_workstations[$obj->rowid]['thm_machine_estimated'] = $obj->thm_machine_estimated;
+ $i++;
+ }
+
+ return $num;
+ } else {
+ dol_print_error($this->db);
+ return -1;
+ }
+ }
+
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
/**
* Return full path to current warehouse in $tab (recursive function)
@@ -320,6 +378,105 @@ class FormProduct
return $out;
}
+ /**
+ * Return list of workstations
+ *
+ * @param string|int $selected Id of preselected warehouse ('' or '-1' for no value, 'ifone' and 'ifonenodefault' = select value if one value otherwise no value, '-2' to use the default value from setup)
+ * @param string $htmlname Name of html select html
+ * @param int $empty 1=Can be empty, 0 if not
+ * @param int $disabled 1=Select is disabled
+ * @param int $fk_product Add quantity of stock in label for product with id fk_product. Nothing if 0.
+ * @param string $empty_label Empty label if needed (only if $empty=1)
+ * @param int $forcecombo 1=Force combo iso ajax select2
+ * @param array $events Events to add to select2
+ * @param string $morecss Add more css classes to HTML select
+ * @param array $exclude Warehouses ids to exclude
+ * @param int $showfullpath 1=Show full path of name (parent ref into label), 0=Show only ref of current warehouse
+ * @param string $orderBy [='e.ref'] Order by
+ * @return string HTML select
+ *
+ * @throws Exception
+ */
+ public function selectWorkstations($selected = '', $htmlname = 'idworkstations', $empty = 0, $disabled = 0, $fk_product = 0, $empty_label = '', $forcecombo = 0, $events = array(), $morecss = 'minwidth200', $exclude = array(), $showfullpath = 1, $orderBy = 'e.ref')
+ {
+ global $conf, $langs, $user, $hookmanager;
+
+ dol_syslog(get_class($this)."::selectWorkstations $selected, $htmlname, $empty, $disabled, $fk_product, $empty_label, $forcecombo, $morecss", LOG_DEBUG);
+
+ $out = '';
+ if (!empty($fk_product) && $fk_product > 0) {
+ $this->cache_workstations = array();
+ }
+
+ $this->loadWorkstations($fk_product);
+ $nbofworkstations = count($this->cache_workstations);
+
+ if ($conf->use_javascript_ajax && !$forcecombo) {
+ include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
+ $comboenhancement = ajax_combobox($htmlname, $events);
+ $out .= $comboenhancement;
+ }
+
+ if (strpos($htmlname, 'search_') !== 0) {
+ if (empty($user->fk_workstation) || $user->fk_workstation == -1) {
+ if (($selected == '-2' || $selected == 'ifone') && !empty($conf->global->MAIN_DEFAULT_WORKSTATION)) {
+ $selected = $conf->global->MAIN_DEFAULT_WORKSTATION;
+ }
+ } else {
+ if (($selected == '-2' || $selected == 'ifone') && !empty($conf->global->MAIN_DEFAULT_WORKSTATION)) {
+ $selected = $user->fk_workstation;
+ }
+ }
+ }
+
+ $out .= '