From d72d69e55c6d5d0532b4a992e6dd071526b79f87 Mon Sep 17 00:00:00 2001 From: atm-jonathan <146709163+atm-jonathan@users.noreply.github.com> Date: Wed, 2 Apr 2025 12:22:59 +0200 Subject: [PATCH] NEW add home box mrp (#33549) * add box Mo * tests ok * comparaison dates * before Wysy * after wysy * Update mo.class.php * Update mo.class.php * Update conf.class.php * retour PR * add parenthesis * Update mo_list.php --------- Co-authored-by: x Co-authored-by: Laurent Destailleur --- htdocs/admin/delais.php | 7 +- htdocs/compta/facture/class/facture.class.php | 1 - htdocs/core/class/conf.class.php | 8 +++ htdocs/core/lib/functions.lib.php | 2 - htdocs/index.php | 33 +++++++-- htdocs/langs/en_US/admin.lang | 1 + htdocs/langs/en_US/mrp.lang | 4 ++ htdocs/mrp/class/mo.class.php | 69 +++++++++++++++++++ htdocs/mrp/mo_list.php | 25 +++++-- htdocs/theme/eldy/info-box.inc.php | 6 ++ htdocs/theme/md/info-box.inc.php | 6 ++ 11 files changed, 148 insertions(+), 14 deletions(-) diff --git a/htdocs/admin/delais.php b/htdocs/admin/delais.php index 092ec5bc5fc..a74c23ee267 100644 --- a/htdocs/admin/delais.php +++ b/htdocs/admin/delais.php @@ -143,6 +143,12 @@ $modules = array( 'img' => 'holiday' ), ), + 'mrp' => array( + array( + 'code' => 'MAIN_DELAY_MRP', + 'img' => 'mrp' + ), + ), ); $labelmeteo = array(0 => $langs->trans("No"), 1 => $langs->trans("Yes"), 2 => $langs->trans("OnMobileOnly")); @@ -185,7 +191,6 @@ if ($action == 'update') { } } } - dolibarr_set_const($db, "MAIN_DISABLE_METEO", GETPOST("MAIN_DISABLE_METEO"), 'chaine', 0, '', $conf->entity); dolibarr_set_const($db, "MAIN_USE_METEO_WITH_PERCENTAGE", GETPOST("MAIN_USE_METEO_WITH_PERCENTAGE"), 'chaine', 0, '', $conf->entity); diff --git a/htdocs/compta/facture/class/facture.class.php b/htdocs/compta/facture/class/facture.class.php index dd0c94694c3..3139eb4ab11 100644 --- a/htdocs/compta/facture/class/facture.class.php +++ b/htdocs/compta/facture/class/facture.class.php @@ -5128,7 +5128,6 @@ class Facture extends CommonInvoice if ($resql) { $langs->load("bills"); $now = dol_now(); - $response = new WorkboardResponse(); $response->warning_delay = $conf->facture->client->warning_delay / 60 / 60 / 24; $response->label = $langs->trans("CustomerBillsUnpaid"); diff --git a/htdocs/core/class/conf.class.php b/htdocs/core/class/conf.class.php index 137ea285287..ecaceb1d87b 100644 --- a/htdocs/core/class/conf.class.php +++ b/htdocs/core/class/conf.class.php @@ -377,6 +377,10 @@ class Conf extends stdClass */ public $category; + /** + * @var ?stdClass + */ + public $mrp; /** * Constructor @@ -1236,6 +1240,10 @@ class Conf extends stdClass $this->holiday->approve = new stdClass(); $this->holiday->approve->warning_delay = getDolGlobalInt('MAIN_DELAY_HOLIDAYS') * 86400; } + if (isset($this->mrp)) { + $this->mrp->progress = new stdClass(); + $this->mrp->progress->warning_delay = getDolGlobalInt('MAIN_DELAY_MRP') * 86400; + } if ((getDolGlobalString('PRODUIT_MULTIPRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES')) && !getDolGlobalString('PRODUIT_MULTIPRICES_LIMIT')) { $this->global->PRODUIT_MULTIPRICES_LIMIT = 5; diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php index 8268f5cba04..f45716fb67d 100644 --- a/htdocs/core/lib/functions.lib.php +++ b/htdocs/core/lib/functions.lib.php @@ -12203,7 +12203,6 @@ function natural_search($fields, $value, $mode = 0, $nofirstand = 0) if (!is_array($fields)) { $fields = array($fields); } - $i1 = 0; // count the nb of "and" criteria added (all fields / criteria) foreach ($crits as $crit) { // Loop on each AND criteria $crit = trim($crit); @@ -12341,7 +12340,6 @@ function natural_search($fields, $value, $mode = 0, $nofirstand = 0) $i2++; // a criteria for 1 more field was added to string } } - if ($newres) { $res = $res.($res ? ' AND ' : '').($i2 > 1 ? '(' : '').$newres.($i2 > 1 ? ')' : ''); } diff --git a/htdocs/index.php b/htdocs/index.php index b8e6d089292..c682ea55960 100644 --- a/htdocs/index.php +++ b/htdocs/index.php @@ -341,6 +341,12 @@ if (!getDolGlobalString('MAIN_DISABLE_GLOBAL_WORKBOARD') && getDolGlobalInt('MAI $dashboardlines[$board->element] = $board->load_board($user); } + if (isModEnabled('mrp')) { + include_once DOL_DOCUMENT_ROOT.'/mrp/class/mo.class.php'; + $board = new Mo($db); + $dashboardlines[$board->element] = $board->load_board($user); + } + $object = new stdClass(); $parameters = array(); $action = ''; @@ -353,7 +359,6 @@ if (!getDolGlobalString('MAIN_DISABLE_GLOBAL_WORKBOARD') && getDolGlobalInt('MAI if ($reshook == 0) { $dashboardlines = array_merge($dashboardlines, $hookmanager->resArray); } - /* Open object dashboard */ $dashboardgroup = array( 'action' => @@ -451,8 +456,14 @@ if (!getDolGlobalString('MAIN_DISABLE_GLOBAL_WORKBOARD') && getDolGlobalInt('MAI 'stats' => array('holiday'), ), + 'cubes' => + array( + 'groupName' => 'Mo', + 'globalStatsKey' => 'mrp', + 'stats' => + array('mo'), + ), ); - $object = new stdClass(); $parameters = array( 'dashboardgroup' => $dashboardgroup @@ -475,7 +486,6 @@ if (!getDolGlobalString('MAIN_DISABLE_GLOBAL_WORKBOARD') && getDolGlobalInt('MAI $valid_dashboardlines[$workboardid] = $tmp; } } - // We calculate $totallate. Must be defined before start of next loop because it is show in first fetch on next loop foreach ($valid_dashboardlines as $board) { if (is_numeric($board->nbtodo) && is_numeric($board->nbtodolate) && $board->nbtodolate > 0) { @@ -527,7 +537,6 @@ if (!getDolGlobalString('MAIN_DISABLE_GLOBAL_WORKBOARD') && getDolGlobalInt('MAI $openedDashBoard = ''; if (!empty($valid_dashboardlines)) { $boxwork .= '
'; - foreach ($dashboardgroup as $groupKey => $groupElement) { $boards = array(); @@ -541,6 +550,7 @@ if (!getDolGlobalString('MAIN_DISABLE_GLOBAL_WORKBOARD') && getDolGlobalInt('MAI } } + if (!empty($boards)) { if (!empty($groupElement['lang'])) { $langs->load($groupElement['lang']); @@ -583,7 +593,20 @@ if (!getDolGlobalString('MAIN_DISABLE_GLOBAL_WORKBOARD') && getDolGlobalInt('MAI } $textLateTitle = $langs->trans("NActionsLate", $board->nbtodolate); - $textLateTitle .= ' ('.$langs->trans("Late").' = '.$langs->trans("DateReference").' > '.$langs->trans("DateToday").' '.(ceil(empty($board->warning_delay) ? 0 : $board->warning_delay) >= 0 ? '+' : '').ceil(empty($board->warning_delay) ? 0 : $board->warning_delay).' '.$langs->trans("days").')'; + + $dateOrder = ''; + if ($board->id == 'mo') { + $dateOrder = $langs->trans("DateToday") . " > " . $langs->trans("DateReference"); + } else { + $dateOrder = $langs->trans("DateReference") . " > " . $langs->trans("DateToday"); + } + $warningDelay = ceil(empty($board->warning_delay) ? 0 : $board->warning_delay); + $sign = ''; + if ($warningDelay >= 0) { + $sign = '+'; + } + + $textLateTitle .= " (" . $langs->trans("Late") . " = $dateOrder $sign$warningDelay " . $langs->trans("days") . ")"; if ($board->id == 'bank_account') { $textLateTitle .= '
'.$langs->trans("IfYouDontReconcileDisableProperty", $langs->transnoentitiesnoconv("Conciliable")).''; diff --git a/htdocs/langs/en_US/admin.lang b/htdocs/langs/en_US/admin.lang index 187b172e56a..a5ce3889bcc 100644 --- a/htdocs/langs/en_US/admin.lang +++ b/htdocs/langs/en_US/admin.lang @@ -1276,6 +1276,7 @@ Delays_MAIN_DELAY_MEMBERS=Delayed membership fee Delays_MAIN_DELAY_CHEQUES_TO_DEPOSIT=Check deposit not done Delays_MAIN_DELAY_EXPENSEREPORTS=Expense report to approve Delays_MAIN_DELAY_HOLIDAYS=Leave requests to approve +Delays_MAIN_DELAY_MRP=Manufacturing order in progress SetupDescription1=Before starting to use Dolibarr some initial parameters must be defined and modules enabled/configured. SetupDescription2=The following two sections are mandatory (the two first entries in the Setup menu): SetupDescription3=%s -> %s

Basic parameters used to customize the default behavior of your application (e.g for country-related features). diff --git a/htdocs/langs/en_US/mrp.lang b/htdocs/langs/en_US/mrp.lang index 3b001370270..1cb82161728 100644 --- a/htdocs/langs/en_US/mrp.lang +++ b/htdocs/langs/en_US/mrp.lang @@ -147,6 +147,10 @@ NoRemainQtyToDispatch=No quantity remaining to divide THMOperatorEstimatedHelp=Estimated cost of operator per hour. Will be used to estimate cost of a BOM using this workstation. THMMachineEstimatedHelp=Estimated cost of machine per hour. Will be used to estimate cost of a BOM using this workstation. BadValueForquantityToConsume=Quantity to consume for a material cannot be 0 or negative +MOProgress = In progress +Mo=Manufacturing +StatusMrpValidated=Validé +StatusMrpProgress=En cours NoValidatedStatusMo = Manufacturing order %s cannot be canceled because it is not validated CancelMoValidated = Manufacturing order %s canceled ErrorObjectMustHaveStatusValidatedToBeCanceled = The object %s must have the 'Validated' status to be canceled diff --git a/htdocs/mrp/class/mo.class.php b/htdocs/mrp/class/mo.class.php index df29e878765..a4056201417 100644 --- a/htdocs/mrp/class/mo.class.php +++ b/htdocs/mrp/class/mo.class.php @@ -1980,6 +1980,75 @@ class Mo extends CommonObject } } + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps + /** + * Load indicators for dashboard (this->nbtodo and this->nbtodolate) + * + * @param User $user Object user + * @return WorkboardResponse|int Return integer <0 if KO, WorkboardResponse if OK + */ + public function load_board($user) + { + // phpcs:enable + global $conf, $langs; + if ($user->socid) { + return -1; // Protection pour éviter appel par utilisateur externe + } + + $now = dol_now(); + + $sql = "SELECT rowid, date_end_planned FROM ".$this->db->prefix()."mrp_mo"; + $sql .= " WHERE status IN (" . self::STATUS_VALIDATED . ", " . self::STATUS_INPROGRESS .")"; // 1 = Ouvert, 2 = En cours + $sql .= " AND entity IN (".getEntity('mrp_mo').")"; + + $resql = $this->db->query($sql); + if ($resql) { + $langs->load("mrp"); + $response = new WorkboardResponse(); + $warning_delay = $conf->mrp->progress->warning_delay ; + $response->warning_delay = $warning_delay / 86400; + $response->label = $langs->trans("MOProgress"); + $response->labelShort = $langs->trans("MOProgress"); + $response->url = DOL_URL_ROOT.'/mrp/mo_list.php?search_status=-2'; + $response->img = img_object('', "mrp"); + + + while ($obj = $this->db->fetch_object($resql)) { + $response->nbtodo++; + + if (!empty($obj->date_end_planned)) { + $date_end_planned = $this->db->jdate($obj->date_end_planned); + if ($now > ($date_end_planned + $warning_delay)) { + $response->nbtodolate++; + $response->url_late = DOL_URL_ROOT.'/mrp/mo_list.php?search_status=-2&search_option=late'; + } + } + } + + return $response; + } else { + dol_print_error($this->db); + $this->error = $this->db->error(); + return -1; + } + } + + /** + * Is the manufactured delayed? + * + * @return bool + */ + public function hasDelay() + { + global $conf; + + if ($this->status != Mo::STATUS_VALIDATED && $this->status != Mo::STATUS_INPROGRESS) { + return false; + } + return (dol_now() > ($this->date_end_planned + $conf->mrp->progress->warning_delay)); + } + + /** * Return clickable link of object (with eventually picto) * diff --git a/htdocs/mrp/mo_list.php b/htdocs/mrp/mo_list.php index 57e47ff3ad9..da8775f5a5f 100644 --- a/htdocs/mrp/mo_list.php +++ b/htdocs/mrp/mo_list.php @@ -97,6 +97,8 @@ $extrafields->fetch_name_optionals_label($object->table_element); $search_array_options = $extrafields->getOptionalsFromPost($object->table_element, '', 'search_'); +$search_option = GETPOST('search_option', 'alphanohtml'); + // Default sort order (if not yet defined by previous GETPOST) if (!$sortfield) { $sortfield = "t.ref"; // Set here default search field. By default 1st field in definition. @@ -117,7 +119,6 @@ foreach ($object->fields as $key => $val) { $search[$key.'_dtend'] = dol_mktime(23, 59, 59, GETPOSTINT('search_'.$key.'_dtendmonth'), GETPOSTINT('search_'.$key.'_dtendday'), GETPOSTINT('search_'.$key.'_dtendyear')); } } - // List of fields to search into when doing a "search in all" $fieldstosearchall = array(); foreach ($object->fields as $key => $val) { @@ -343,17 +344,22 @@ foreach ($search as $key => $val) { if ($key == 'status' && $search[$key] == -1) { continue; } + if ($key == 'status' && $search[$key] == -2) { + $sql .= " AND (t.status IN (".((int) $object::STATUS_VALIDATED).",".((int) $object::STATUS_INPROGRESS)."))"; + if ($search_option == 'late') { + $sql .= " AND (t.date_end_planned < '".$db->idate(dol_now() - $conf->mrp->progress->warning_delay)."')"; + } + continue; + } if ($key == 'fk_parent_line' && $search[$key] != '') { $sql .= natural_search('moparent.ref', $search[$key], 0); continue; } - if ($key == 'status') { $sql .= natural_search('t.status', (string) $search[$key], 0); continue; } - $mode_search = (($object->isInt($object->fields[$key]) || $object->isFloat($object->fields[$key])) ? 1 : 0); if ((strpos($object->fields[$key]['type'], 'integer:') === 0) || (strpos($object->fields[$key]['type'], 'sellist:') === 0) || !empty($object->fields[$key]['arrayofkeyval'])) { if ($search[$key] == '-1' || ($search[$key] === '0' && (empty($object->fields[$key]['arrayofkeyval']) || !array_key_exists('0', $object->fields[$key]['arrayofkeyval'])))) { @@ -378,9 +384,14 @@ foreach ($search as $key => $val) { } } } + + if ($search_all) { $sql .= natural_search(array_keys($fieldstosearchall), $search_all); } + + + //$sql.= dolSqlDateFilter("t.field", $search_xxxday, $search_xxxmonth, $search_xxxyear); // Add where from extra fields include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_sql.tpl.php'; @@ -388,7 +399,6 @@ include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_sql.tpl.php'; $parameters = array(); $reshook = $hookmanager->executeHooks('printFieldListWhere', $parameters, $object, $action); // Note that $action and $object may have been modified by hook $sql .= $hookmanager->resPrint; - /* If a group by is required $sql.= " GROUP BY "; foreach($object->fields as $key => $val) { @@ -433,7 +443,6 @@ $sql .= $db->order($sortfield, $sortorder); if ($limit) { $sql .= $db->plimit($limit + 1, $offset); } - $resql = $db->query($sql); if (!$resql) { dol_print_error($db); @@ -656,6 +665,9 @@ foreach ($object->fields as $key => $val) { continue; } if (!empty($val['arrayofkeyval']) && is_array($val['arrayofkeyval'])) { + if ($key == 'status') { + $val['arrayofkeyval'][-2] = $langs->trans("StatusMrpValidated").'+'.$langs->trans("StatusMrpProgress"); + } print $form->selectarray('search_'.$key, $val['arrayofkeyval'], (isset($search[$key]) ? $search[$key] : ''), $val['notnull'], 0, 0, '', 1, 0, 0, '', 'maxwidth100', 1); } elseif ((strpos($val['type'], 'integer:') === 0) || (strpos($val['type'], 'sellist:') === 0)) { print $object->showInputField($val, $key, (isset($search[$key]) ? $search[$key] : ''), '', '', 'search_', 'maxwidth125', 1); @@ -853,6 +865,9 @@ while ($i < $imaxinloop) { print $object->showOutputField($val, $key, (string) $object->id, ''); } else { print $object->showOutputField($val, $key, (string) $object->$key, ''); + if ($key == 'date_end_planned' && $object->hasDelay()) { + print img_warning($langs->trans('Alert').' - '.$langs->trans('Late')); + } } print ''; if (!$i) { diff --git a/htdocs/theme/eldy/info-box.inc.php b/htdocs/theme/eldy/info-box.inc.php index 45ac072144f..2c404ec346d 100644 --- a/htdocs/theme/eldy/info-box.inc.php +++ b/htdocs/theme/eldy/info-box.inc.php @@ -427,6 +427,9 @@ if (GETPOSTISSET('THEME_SATURATE_RATIO')) { .bg-infobox-holiday{ color: #755114 !important; } +.bg-infobox-cubes{ + color: #b0a53e !important; +} /* Disable colors on left vmenu */ a.vmenu span, span.vmenu, span.vmenu span { @@ -508,6 +511,9 @@ a.vmenu span, span.vmenu, span.vmenu span { .fa-dol-holiday:before { content: "\f5ca"; } +.fa-dol-cubes:before { + content: "\f1b3"; +} /* USING FONTAWESOME FOR WEATHER */ diff --git a/htdocs/theme/md/info-box.inc.php b/htdocs/theme/md/info-box.inc.php index c8ea748a5ba..ad284bbacd5 100644 --- a/htdocs/theme/md/info-box.inc.php +++ b/htdocs/theme/md/info-box.inc.php @@ -120,6 +120,9 @@ if (GETPOSTISSET('THEME_SATURATE_RATIO')) { .bg-infobox-holiday{ color: #755114 !important; } +.bg-infobox-cubes{ + color: #b0a53e !important; +} /* Disable colors on left vmenu */ a.vmenu span, span.vmenu, span.vmenu span { @@ -498,6 +501,9 @@ if (GETPOSTISSET('THEME_SATURATE_RATIO')) { .bg-infobox-holiday i.fa{ color: #755114 !important; } +.bg-infobox-cubes i.fa{ + color: #b0a53e !important; +} .fa-dol-action:before {