dolibarr 22.0.5
mo_production.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2019-2020 Laurent Destailleur <eldy@users.sourceforge.net>
3 * Copyright (C) 2023 Christian Humpel <christian.humpel@gmail.com>
4 * Copyright (C) 2023 Vincent de Grandpré <vincent@de-grandpre.quebec>
5 * Copyright (C) 2024-2025 Frédéric France <frederic.france@free.fr>
6 * Copyright (C) 2024-2025 MDW <mdeweerd@users.noreply.github.com>
7 * Copyright (C) 2024 Alexandre Spangaro <alexandre@inovea-conseil.com>
8 * Copyright (C) 2025 Noé Cendrier <noe.cendrier@altairis.fr>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 3 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program. If not, see <https://www.gnu.org/licenses/>.
22 */
23
30// Load Dolibarr environment
31require '../main.inc.php';
32require_once DOL_DOCUMENT_ROOT.'/bom/class/bom.class.php';
33require_once DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php';
34require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php';
35require_once DOL_DOCUMENT_ROOT.'/core/class/html.formprojet.class.php';
36require_once DOL_DOCUMENT_ROOT.'/mrp/class/mo.class.php';
37require_once DOL_DOCUMENT_ROOT.'/mrp/lib/mrp_mo.lib.php';
38require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
39require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
40require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php';
41require_once DOL_DOCUMENT_ROOT.'/product/stock/class/entrepot.class.php';
42require_once DOL_DOCUMENT_ROOT.'/product/stock/class/productlot.class.php';
43require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
44require_once DOL_DOCUMENT_ROOT.'/workstation/class/workstation.class.php';
45
46
55// Load translation files required by the page
56$langs->loadLangs(array("mrp", "stocks", "other", "product", "productbatch"));
57
58// Get parameters
59$id = GETPOSTINT('id');
60$ref = GETPOST('ref', 'alpha');
61$action = GETPOST('action', 'aZ09');
62$confirm = GETPOST('confirm', 'alpha');
63$cancel = GETPOST('cancel');
64$contextpage = GETPOST('contextpage', 'aZ') ? GETPOST('contextpage', 'aZ') : 'mocard'; // To manage different context of search
65$backtopage = GETPOST('backtopage', 'alpha');
66$lineid = GETPOSTINT('lineid');
67$fk_movement = GETPOSTINT('fk_movement');
68$fk_default_warehouse = GETPOSTINT('fk_default_warehouse');
69
70$collapse = GETPOST('collapse', 'aZ09comma');
71
72// Initialize a technical objects
73$object = new Mo($db);
74$extrafields = new ExtraFields($db);
75$diroutputmassaction = $conf->mrp->dir_output.'/temp/massgeneration/'.$user->id;
76$objectline = new MoLine($db);
77
78$hookmanager->initHooks(array('moproduction', 'globalcard')); // Note that conf->hooks_modules contains array
79
80// Fetch optionals attributes and labels
81$extrafields->fetch_name_optionals_label($object->table_element);
82
83$search_array_options = $extrafields->getOptionalsFromPost($object->table_element, '', 'search_');
84
85// Initialize array of search criteria
86$search_all = GETPOST("search_all", 'alpha');
87$search = array();
88foreach ($object->fields as $key => $val) {
89 if (GETPOST('search_'.$key, 'alpha')) {
90 $search[$key] = GETPOST('search_'.$key, 'alpha');
91 }
92}
93
94if (empty($action) && empty($id) && empty($ref)) {
95 $action = 'view';
96}
97
98// Load object
99include DOL_DOCUMENT_ROOT.'/core/actions_fetchobject.inc.php'; // Must be 'include', not 'include_once'.
100
101// Security check - Protection if external user
102//if ($user->socid > 0) accessforbidden();
103//if ($user->socid > 0) $socid = $user->socid;
104$isdraft = (($object->status == $object::STATUS_DRAFT) ? 1 : 0);
105$result = restrictedArea($user, 'mrp', $object->id, 'mrp_mo', '', 'fk_soc', 'rowid', $isdraft);
106
107// Permissions
108$permissionnote = $user->hasRight('mrp', 'write'); // Used by the include of actions_setnotes.inc.php
109$permissiondellink = $user->hasRight('mrp', 'write'); // Used by the include of actions_dellink.inc.php
110$permissiontoadd = $user->hasRight('mrp', 'write'); // Used by the include of actions_addupdatedelete.inc.php and actions_lineupdown.inc.php
111$permissiontodelete = $user->hasRight('mrp', 'delete') || ($permissiontoadd && isset($object->status) && $object->status == $object::STATUS_DRAFT);
112
113$permissiontoproduce = $permissiontoadd;
114$permissiontoupdatecost = $user->hasRight('bom', 'read'); // User who can define cost must have knowledge of pricing
115
116$upload_dir = $conf->mrp->multidir_output[isset($object->entity) ? $object->entity : 1];
117
118
119/*
120 * Actions
121 */
122
123$parameters = array();
124$reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
125if ($reshook < 0) {
126 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
127}
128
129if (empty($reshook)) {
130 $error = 0;
131
132 $backurlforlist = DOL_URL_ROOT.'/mrp/mo_list.php';
133
134 if (empty($backtopage) || ($cancel && empty($id))) {
135 //var_dump($backurlforlist);exit;
136 if (empty($id) && (($action != 'add' && $action != 'create') || $cancel)) {
137 $backtopage = $backurlforlist;
138 } else {
139 $backtopage = DOL_URL_ROOT.'/mrp/mo_production.php?id='.($id > 0 ? $id : '__ID__');
140 }
141 }
142 $triggermodname = 'MO_MODIFY'; // Name of trigger action code to execute when we modify record
143
144 if ($action == 'confirm_cancel' && $confirm == 'yes' && !empty($permissiontoadd)) {
145 $also_cancel_consumed_and_produced_lines = (GETPOST('alsoCancelConsumedAndProducedLines', 'alpha') ? 1 : 0);
146 $result = $object->cancel($user, 0, (bool) $also_cancel_consumed_and_produced_lines);
147 if ($result > 0) {
148 header("Location: " . DOL_URL_ROOT.'/mrp/mo_card.php?id=' . $object->id);
149 exit;
150 } else {
151 $action = '';
152 setEventMessages($object->error, $object->errors, 'errors');
153 }
154 } elseif ($action == 'confirm_delete' && $confirm == 'yes' && !empty($permissiontodelete)) {
155 $also_cancel_consumed_and_produced_lines = (GETPOST('alsoCancelConsumedAndProducedLines', 'alpha') ? 1 : 0);
156 $result = $object->delete($user, 0, (bool) $also_cancel_consumed_and_produced_lines);
157 if ($result > 0) {
158 header("Location: " . $backurlforlist);
159 exit;
160 } else {
161 $action = '';
162 setEventMessages($object->error, $object->errors, 'errors');
163 }
164 }
165
166 // Actions cancel, add, update, delete or clone
167 include DOL_DOCUMENT_ROOT.'/core/actions_addupdatedelete.inc.php';
168
169 // Actions when linking object each other
170 include DOL_DOCUMENT_ROOT.'/core/actions_dellink.inc.php';
171
172 // Actions when printing a doc from card
173 include DOL_DOCUMENT_ROOT.'/core/actions_printing.inc.php';
174
175 // Actions to send emails
176 $triggersendname = 'MO_SENTBYMAIL';
177 $autocopy = 'MAIN_MAIL_AUTOCOPY_MO_TO';
178 $trackid = 'mo'.$object->id;
179 include DOL_DOCUMENT_ROOT.'/core/actions_sendmails.inc.php';
180
181 // Action to move up and down lines of object
182 //include DOL_DOCUMENT_ROOT.'/core/actions_lineupdown.inc.php'; // Must be 'include', not 'include_once'
183
184 if ($action == 'set_thirdparty' && $permissiontoadd) {
185 $object->setValueFrom('fk_soc', GETPOSTINT('fk_soc'), '', null, 'date', '', $user, $triggermodname);
186 }
187 if ($action == 'classin' && $permissiontoadd) {
188 $object->setProject(GETPOSTINT('projectid'));
189 }
190
191 if ($action == 'confirm_reopen' && $permissiontoadd) {
192 $result = $object->setStatut($object::STATUS_INPROGRESS, 0, '', 'MRP_REOPEN');
193 }
194
195 if (($action == 'confirm_addconsumeline' && GETPOST('addconsumelinebutton') && $permissiontoadd)
196 || ($action == 'confirm_addproduceline' && GETPOST('addproducelinebutton') && $permissiontoadd)) {
197 $moline = new MoLine($db);
198
199 // Line to produce
200 $moline->fk_mo = $object->id;
201 $moline->qty = GETPOSTFLOAT('qtytoadd');
202 $moline->fk_product = GETPOSTINT('productidtoadd');
203 if (GETPOST('addconsumelinebutton')) {
204 $moline->role = 'toconsume';
205 } else {
206 $moline->role = 'toproduce';
207 }
208 $moline->origin_type = 'free'; // free consume line
209 $moline->position = 0;
210
211 // Is it a product or a service ?
212 if (!empty($moline->fk_product)) {
213 $tmpproduct = new Product($db);
214 $tmpproduct->fetch($moline->fk_product);
215 if ($tmpproduct->type == Product::TYPE_SERVICE) {
216 $moline->fk_default_workstation = $tmpproduct->fk_default_workstation;
217 $moline->disable_stock_change = 1;
218 if ($tmpproduct->duration_unit) {
219 $moline->qty = $tmpproduct->duration_value;
220 include_once DOL_DOCUMENT_ROOT.'/core/class/cunits.class.php';
221 $cunits = new CUnits($db);
222 $res = $cunits->fetch(0, '', $tmpproduct->duration_unit, 'time');
223 if ($res > 0) {
224 $moline->fk_unit = $cunits->id;
225 }
226 }
227 } else {
228 $moline->disable_stock_change = 0;
229 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
230 $moline->fk_unit = $tmpproduct->fk_unit;
231 }
232 }
233 }
234 // Extrafields
235 $extralabelsline = $extrafields->fetch_name_optionals_label($object->table_element_line);
236 $array_options = $extrafields->getOptionalsFromPost($object->table_element_line);
237 // Unset extrafield
238 if (is_array($extralabelsline)) {
239 // Get extra fields
240 foreach ($extralabelsline as $key => $value) {
241 unset($_POST["options_".$key]);
242 }
243 }
244 if (is_array($array_options) && count($array_options) > 0) {
245 $moline->array_options = $array_options;
246 }
247
248 $resultline = $moline->create($user, 0); // Never use triggers here
249 if ($resultline <= 0) {
250 $error++;
251 setEventMessages($moline->error, $moline->errors, 'errors');
252 }
253
254 $action = '';
255 // Redirect to refresh the tab information
256 header("Location: ".$_SERVER["PHP_SELF"].'?id='.$object->id);
257 exit;
258 }
259
260 if (in_array($action, array('confirm_consumeorproduce', 'confirm_consumeandproduceall')) && $permissiontoproduce) {
261 $stockmove = new MouvementStock($db);
262
263 $labelmovement = GETPOST('inventorylabel', 'alphanohtml');
264 $codemovement = GETPOST('inventorycode', 'alphanohtml');
265
266 $db->begin();
267 $pos = 0;
268 // Process line to consume
269 foreach ($object->lines as $line) {
270 if ($line->role == 'toconsume') {
271 $tmpproduct = new Product($db);
272 $tmpproduct->fetch($line->fk_product);
273
274 $i = 1;
275 while (GETPOSTISSET('qty-'.$line->id.'-'.$i)) {
276 $qtytoprocess = (float) price2num(GETPOST('qty-'.$line->id.'-'.$i));
277
278 if ($qtytoprocess != 0) {
279 // Check warehouse is set if we should have to
280 if (GETPOSTISSET('idwarehouse-'.$line->id.'-'.$i)) { // If there is a warehouse to set
281 if (!(GETPOST('idwarehouse-'.$line->id.'-'.$i) > 0)) { // If there is no warehouse set.
282 $langs->load("errors");
283 setEventMessages($langs->trans("ErrorFieldRequiredForProduct", $langs->transnoentitiesnoconv("Warehouse"), $tmpproduct->ref), null, 'errors');
284 $error++;
285 }
286 if ($tmpproduct->status_batch && (!GETPOST('batch-'.$line->id.'-'.$i))) {
287 $langs->load("errors");
288 setEventMessages($langs->trans("ErrorFieldRequiredForProduct", $langs->transnoentitiesnoconv("Batch"), $tmpproduct->ref), null, 'errors');
289 $error++;
290 }
291 }
292
293 $idstockmove = 0;
294 if (!$error && GETPOST('idwarehouse-'.$line->id.'-'.$i) > 0) {
295 // Record stock movement
296 $id_product_batch = 0;
297 $stockmove->setOrigin($object->element, $object->id);
298 $stockmove->context['mrp_role'] = 'toconsume';
299
300 if ($qtytoprocess >= 0) {
301 $idstockmove = $stockmove->livraison($user, $line->fk_product, GETPOSTINT('idwarehouse-'.$line->id.'-'.$i), $qtytoprocess, 0, $labelmovement, dol_now(), '', '', GETPOST('batch-'.$line->id.'-'.$i), $id_product_batch, $codemovement);
302 } else {
303 $idstockmove = $stockmove->reception($user, $line->fk_product, GETPOSTINT('idwarehouse-'.$line->id.'-'.$i), $qtytoprocess * -1, 0, $labelmovement, dol_now(), '', '', GETPOST('batch-'.$line->id.'-'.$i), $id_product_batch, $codemovement);
304 }
305 if ($idstockmove < 0) {
306 $error++;
307 setEventMessages($stockmove->error, $stockmove->errors, 'errors');
308 }
309 }
310
311 if (!$error) {
312 // Record consumption
313 $moline = new MoLine($db);
314 $moline->fk_mo = $object->id;
315 $moline->position = $pos;
316 $moline->fk_product = $line->fk_product;
317 $moline->fk_warehouse = GETPOSTINT('idwarehouse-'.$line->id.'-'.$i);
318 $moline->qty = $qtytoprocess;
319 $moline->batch = GETPOST('batch-'.$line->id.'-'.$i);
320 $moline->role = 'consumed';
321 $moline->fk_mrp_production = $line->id;
322 $moline->fk_stock_movement = $idstockmove == 0 ? null : $idstockmove;
323 $moline->fk_user_creat = $user->id;
324
325 $resultmoline = $moline->create($user);
326 if ($resultmoline <= 0) {
327 $error++;
328 setEventMessages($moline->error, $moline->errors, 'errors');
329 }
330
331 $pos++;
332 }
333 }
334
335 $i++;
336 }
337 }
338 }
339
340 // Process line to produce
341 $pos = 0;
342
343 foreach ($object->lines as $line) {
344 if ($line->role == 'toproduce') {
345 $tmpproduct = new Product($db);
346 $tmpproduct->fetch($line->fk_product);
347
348 $i = 1;
349 while (GETPOSTISSET('qtytoproduce-'.$line->id.'-'.$i)) {
350 $qtytoprocess = (float) price2num(GETPOST('qtytoproduce-'.$line->id.'-'.$i));
351 $pricetoprocess = GETPOST('pricetoproduce-'.$line->id.'-'.$i) ? price2num(GETPOST('pricetoproduce-'.$line->id.'-'.$i)) : 0;
352
353 if ($qtytoprocess != 0) {
354 // Check warehouse is set if we should have to
355 if (GETPOSTISSET('idwarehousetoproduce-'.$line->id.'-'.$i)) { // If there is a warehouse to set
356 if (!(GETPOST('idwarehousetoproduce-'.$line->id.'-'.$i) > 0)) { // If there is no warehouse set.
357 $langs->load("errors");
358 setEventMessages($langs->trans("ErrorFieldRequiredForProduct", $langs->transnoentitiesnoconv("Warehouse"), $tmpproduct->ref), null, 'errors');
359 $error++;
360 }
361 if (isModEnabled('productbatch') && $tmpproduct->status_batch && (!GETPOST('batchtoproduce-'.$line->id.'-'.$i))) {
362 $langs->load("errors");
363 setEventMessages($langs->trans("ErrorFieldRequiredForProduct", $langs->transnoentitiesnoconv("Batch"), $tmpproduct->ref), null, 'errors');
364 $error++;
365 }
366 }
367
368 $idstockmove = 0;
369 if (!$error && GETPOST('idwarehousetoproduce-'.$line->id.'-'.$i) > 0) {
370 // Record stock movement
371 $id_product_batch = 0;
372 $stockmove->origin_type = $object->element;
373 $stockmove->origin_id = $object->id;
374 $stockmove->context['mrp_role'] = 'toproduce';
375
376 $idstockmove = $stockmove->reception($user, $line->fk_product, GETPOSTINT('idwarehousetoproduce-'.$line->id.'-'.$i), $qtytoprocess, $pricetoprocess, $labelmovement, '', '', GETPOST('batchtoproduce-'.$line->id.'-'.$i), dol_now(), $id_product_batch, $codemovement);
377 if ($idstockmove < 0) {
378 $error++;
379 setEventMessages($stockmove->error, $stockmove->errors, 'errors');
380 }
381 }
382
383 if (!$error) {
384 // Record production
385 $moline = new MoLine($db);
386 $moline->fk_mo = $object->id;
387 $moline->position = $pos;
388 $moline->fk_product = $line->fk_product;
389 $moline->fk_warehouse = GETPOSTINT('idwarehousetoproduce-'.$line->id.'-'.$i);
390 $moline->qty = $qtytoprocess;
391 $moline->batch = GETPOST('batchtoproduce-'.$line->id.'-'.$i);
392 $moline->role = 'produced';
393 $moline->fk_mrp_production = $line->id;
394 $moline->fk_stock_movement = $idstockmove;
395 $moline->fk_user_creat = $user->id;
396
397 $resultmoline = $moline->create($user);
398 if ($resultmoline <= 0) {
399 $error++;
400 setEventMessages($moline->error, $moline->errors, 'errors');
401 }
402
403 $pos++;
404 }
405 }
406
407 $i++;
408 }
409 }
410 }
411
412 if (!$error) {
413 $consumptioncomplete = true;
414 $productioncomplete = true;
415
416 if (GETPOSTINT('autoclose')) {
417 foreach ($object->lines as $line) {
418 $tmpproduct = new Product($db);
419 $tmpproduct->fetch($line->fk_product);
420 if ((int) $tmpproduct->stockable_product > 0) {
421 if ($line->role == 'toconsume') {
422 $arrayoflines = $object->fetchLinesLinked('consumed', $line->id);
423 $alreadyconsumed = 0;
424 foreach ($arrayoflines as $line2) {
425 $alreadyconsumed += $line2['qty'];
426 }
427
428 if ($alreadyconsumed < $line->qty) {
429 $consumptioncomplete = false;
430 }
431 }
432 if ($line->role == 'toproduce') {
433 $arrayoflines = $object->fetchLinesLinked('produced', $line->id);
434 $alreadyproduced = 0;
435 foreach ($arrayoflines as $line2) {
436 $alreadyproduced += $line2['qty'];
437 }
438
439 if ($alreadyproduced < $line->qty) {
440 $productioncomplete = false;
441 }
442 }
443 }
444 }
445 } else {
446 $consumptioncomplete = false;
447 $productioncomplete = false;
448 }
449
450 // Update status of MO
451 dol_syslog("consumptioncomplete = ".json_encode($consumptioncomplete)." productioncomplete = ".json_encode($productioncomplete));
452 if ($consumptioncomplete && $productioncomplete) {
453 $result = $object->setStatut($object::STATUS_PRODUCED, 0, '', 'MRP_MO_PRODUCED');
454 } else {
455 $result = $object->setStatut($object::STATUS_INPROGRESS, 0, '', 'MRP_MO_PRODUCED');
456 }
457 if ($result <= 0) {
458 $error++;
459 setEventMessages($object->error, $object->errors, 'errors');
460 }
461 }
462
463 if ($error) {
464 $action = str_replace('confirm_', '', $action);
465 $db->rollback();
466 } else {
467 $db->commit();
468
469 // Redirect to avoid to action done a second time if we make a back from browser
470 header("Location: ".$_SERVER["PHP_SELF"].'?id='.$object->id);
471 exit;
472 }
473 }
474
475 // Action close produced
476 if ($action == 'confirm_produced' && $confirm == 'yes' && $permissiontoadd) {
477 $result = $object->setStatut($object::STATUS_PRODUCED, 0, '', 'MRP_MO_PRODUCED');
478 if ($result >= 0) {
479 // Define output language
480 if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
481 $outputlangs = $langs;
482 $newlang = '';
483 if (getDolGlobalInt('MAIN_MULTILANGS') /* && empty($newlang) */ && GETPOST('lang_id', 'aZ09')) {
484 $newlang = GETPOST('lang_id', 'aZ09');
485 }
486 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
487 $newlang = $object->thirdparty->default_lang;
488 }
489 if (!empty($newlang)) {
490 $outputlangs = new Translate("", $conf);
491 $outputlangs->setDefaultLang($newlang);
492 }
493 $model = $object->model_pdf;
494 $ret = $object->fetch($id); // Reload to get new records
495
496 $object->generateDocument($model, $outputlangs, 0, 0, 0);
497 }
498 } else {
499 setEventMessages($object->error, $object->errors, 'errors');
500 }
501 }
502
503 if ($action == 'confirm_editline' && $permissiontoadd) {
504 $moline = new MoLine($db);
505 $res = $moline->fetch(GETPOSTINT('lineid'));
506 if ($result > 0) {
507 $extrafields->fetch_name_optionals_label($moline->element);
508 foreach ($extrafields->attributes[$moline->table_element]['label'] as $key => $label) {
509 $value = GETPOST('options_'.$key, 'alphanohtml');
510 $moline->array_options["options_".$key] = $value;
511 }
512 $moline->qty = GETPOSTFLOAT('qty_lineProduce');
513 if (GETPOSTISSET('warehouse_lineProduce')) {
514 $moline->fk_warehouse = (GETPOSTINT('warehouse_lineProduce') > 0 ? GETPOSTINT('warehouse_lineProduce') : 0);
515 }
516 if (GETPOSTISSET('workstation_lineProduce')) {
517 $moline->fk_default_workstation = (GETPOSTINT('workstation_lineProduce') > 0 ? GETPOSTINT('workstation_lineProduce') : 0);
518 }
519
520 $res = $moline->update($user);
521
522 if ($res < 0) {
523 setEventMessages($moline->error, $moline->errors, 'errors');
524 header("Location: ".$_SERVER["PHP_SELF"].'?id='.$object->id);
525 exit;
526 }
527 header("Location: ".$_SERVER["PHP_SELF"].'?id='.$object->id);
528 exit;
529 }
530 }
531}
532
533
534
535/*
536 * View
537 */
538
539$form = new Form($db);
540$formproject = new FormProjets($db);
541$formproduct = new FormProduct($db);
542$tmpwarehouse = new Entrepot($db);
543$tmpbatch = new Productlot($db);
544$tmpstockmovement = new MouvementStock($db);
545
546$title = $langs->trans('Mo');
547$help_url = 'EN:Module_Manufacturing_Orders|FR:Module_Ordres_de_Fabrication|DE:Modul_Fertigungsauftrag';
548$morejs = array('/mrp/js/lib_dispatch.js.php');
549llxHeader('', $title, $help_url, '', 0, 0, $morejs, '', '', 'mod-mrp page-card_production');
550
551$newToken = newToken();
552
553// Part to show record
554if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'create'))) {
555 $res = $object->fetch_thirdparty();
556 $res = $object->fetch_optionals();
557
558 if (getDolGlobalString('STOCK_CONSUMPTION_FROM_MANUFACTURING_WAREHOUSE') && $object->fk_warehouse > 0) {
559 $tmpwarehouse->fetch($object->fk_warehouse);
560 $fk_default_warehouse = $object->fk_warehouse;
561 }
562
563 $head = moPrepareHead($object);
564
565 print dol_get_fiche_head($head, 'production', $langs->trans("ManufacturingOrder"), -1, $object->picto);
566
567 $formconfirm = '';
568
569 // Confirmation to delete
570 if ($action == 'delete') {
571 $formquestion = array(
572 array(
573 'label' => $langs->trans('MoCancelConsumedAndProducedLines'),
574 'name' => 'alsoCancelConsumedAndProducedLines',
575 'type' => 'checkbox',
576 'value' => 0
577 ),
578 );
579 $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('DeleteMo'), $langs->trans('ConfirmDeleteMo'), 'confirm_delete', $formquestion, 0, 1);
580 }
581 // Confirmation to delete line
582 if ($action == 'deleteline') {
583 $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id.'&lineid='.$lineid.'&fk_movement='.$fk_movement, $langs->trans('DeleteLine'), $langs->trans('ConfirmDeleteLine'), 'confirm_deleteline', '', 0, 1);
584 }
585 // Clone confirmation
586 if ($action == 'clone') {
587 // Create an array for form
588 $formquestion = array();
589 $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('ToClone'), $langs->trans('ConfirmCloneMo', $object->ref), 'confirm_clone', $formquestion, 'yes', 1);
590 }
591
592 // Confirmation of validation
593 if ($action == 'validate') {
594 // We check that object has a temporary ref
595 $ref = substr($object->ref, 1, 4);
596 if ($ref == 'PROV') {
597 $object->fetch_product();
598 $numref = $object->getNextNumRef($object->product);
599 } else {
600 $numref = $object->ref;
601 }
602
603 $text = $langs->trans('ConfirmValidateMo', $numref);
604 /*if (isModEnabled('notification'))
605 {
606 require_once DOL_DOCUMENT_ROOT . '/core/class/notify.class.php';
607 $notify = new Notify($db);
608 $text .= '<br>';
609 $text .= $notify->confirmMessage('BOM_VALIDATE', $object->socid, $object);
610 }*/
611
612 $formquestion = array();
613 if (isModEnabled('mrp')) {
614 $langs->load("mrp");
615 require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php';
616 $formproduct = new FormProduct($db);
617 $forcecombo = 0;
618 if ($conf->browser->name == 'ie') {
619 $forcecombo = 1; // There is a bug in IE10 that make combo inside popup crazy
620 }
621 $formquestion = array(
622 // 'text' => $langs->trans("ConfirmClone"),
623 // array('type' => 'checkbox', 'name' => 'clone_content', 'label' => $langs->trans("CloneMainAttributes"), 'value' => 1),
624 // array('type' => 'checkbox', 'name' => 'update_prices', 'label' => $langs->trans("PuttingPricesUpToDate"), 'value' => 1),
625 );
626 }
627
628 $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('Validate'), $text, 'confirm_validate', $formquestion, 0, 1, 220);
629 }
630
631 // Confirmation to cancel
632 if ($action == 'cancel') {
633 $formquestion = array(
634 array(
635 'label' => $langs->trans('MoCancelConsumedAndProducedLines'),
636 'name' => 'alsoCancelConsumedAndProducedLines',
637 'type' => 'checkbox',
638 'value' => !getDolGlobalString('MO_ALSO_CANCEL_CONSUMED_AND_PRODUCED_LINES_BY_DEFAULT') ? 0 : 1
639 ),
640 );
641 $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"] . '?id=' . $object->id, $langs->trans('CancelMo'), $langs->trans('ConfirmCancelMo'), 'confirm_cancel', $formquestion, 0, 1);
642 }
643
644 // Call Hook formConfirm
645 $parameters = array('formConfirm' => $formconfirm, 'lineid' => $lineid);
646 $reshook = $hookmanager->executeHooks('formConfirm', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
647 if (empty($reshook)) {
648 $formconfirm .= $hookmanager->resPrint;
649 } elseif ($reshook > 0) {
650 $formconfirm = $hookmanager->resPrint;
651 }
652
653 // Print form confirm
654 print $formconfirm;
655
656
657 // MO file
658 // ------------------------------------------------------------
659 $linkback = '<a href="'.DOL_URL_ROOT.'/mrp/mo_list.php?restore_lastsearch_values=1'.(!empty($socid) ? '&socid='.$socid : '').'">'.$langs->trans("BackToList").'</a>';
660
661 $morehtmlref = '<div class="refidno">';
662
663 /*
664 // Ref bis
665 $morehtmlref.=$form->editfieldkey("RefBis", 'ref_client', $object->ref_client, $object, $user->rights->mrp->creer, 'string', '', 0, 1);
666 $morehtmlref.=$form->editfieldval("RefBis", 'ref_client', $object->ref_client, $object, $user->rights->mrp->creer, 'string', '', null, null, '', 1);
667 */
668
669 // Thirdparty
670 if (is_object($object->thirdparty)) {
671 $morehtmlref .= $object->thirdparty->getNomUrl(1, 'customer');
672 if (!getDolGlobalString('MAIN_DISABLE_OTHER_LINK') && $object->thirdparty->id > 0) {
673 $morehtmlref .= ' (<a href="'.DOL_URL_ROOT.'/commande/list.php?socid='.$object->thirdparty->id.'&search_societe='.urlencode($object->thirdparty->name).'">'.$langs->trans("OtherOrders").'</a>)';
674 }
675 }
676
677 // Project
678 if (isModEnabled('project')) {
679 $langs->load("projects");
680 if (is_object($object->thirdparty)) {
681 $morehtmlref .= '<br>';
682 }
683 if ($permissiontoadd) {
684 $morehtmlref .= img_picto($langs->trans("Project"), 'project', 'class="pictofixedwidth"');
685 if ($action != 'classify') {
686 $morehtmlref .= '<a class="editfielda" href="'.$_SERVER['PHP_SELF'].'?action=classify&token='.newToken().'&id='.$object->id.'">'.img_edit($langs->transnoentitiesnoconv('SetProject')).'</a> ';
687 }
688 $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'].'?id='.$object->id, $object->socid, (string) $object->fk_project, ($action == 'classify' ? 'projectid' : 'none'), 0, 0, 0, 1, '', 'maxwidth300');
689 } else {
690 if (!empty($object->fk_project)) {
691 $proj = new Project($db);
692 $proj->fetch($object->fk_project);
693 $morehtmlref .= $proj->getNomUrl(1);
694 if ($proj->title) {
695 $morehtmlref .= '<span class="opacitymedium"> - '.dol_escape_htmltag($proj->title).'</span>';
696 }
697 }
698 }
699 }
700 $morehtmlref .= '</div>';
701
702
703 dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref);
704
705
706 print '<div class="fichecenter">';
707 print '<div class="fichehalfleft">';
708 print '<div class="underbanner clearboth"></div>';
709 print '<table class="border centpercent tableforfield">'."\n";
710
711 // Common attributes
712 $keyforbreak = 'fk_warehouse';
713 unset($object->fields['fk_project']);
714 unset($object->fields['fk_soc']);
715 include DOL_DOCUMENT_ROOT.'/core/tpl/commonfields_view.tpl.php';
716
717 // Other attributes
718 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_view.tpl.php';
719
720 print '</table>';
721 print '</div>';
722 print '</div>';
723
724 print '<div class="clearboth"></div>';
725
726 print dol_get_fiche_end();
727
728
729 if (!in_array($action, array('consumeorproduce', 'consumeandproduceall'))) {
730 print '<div class="tabsAction">';
731
732 $parameters = array();
733 // Note that $action and $object may be modified by hook
734 $reshook = $hookmanager->executeHooks('addMoreActionsButtons', $parameters, $object, $action);
735 if (empty($reshook)) {
736 // Validate
737 if ($object->status == $object::STATUS_DRAFT) {
738 if ($permissiontoadd) {
739 if (empty($object->table_element_line) || (is_array($object->lines) && count($object->lines) > 0)) {
740 print '<a class="butAction" href="'.$_SERVER['PHP_SELF'].'?id='.$object->id.'&action=validate&token='.$newToken.'">'.$langs->trans("Validate").'</a>';
741 } else {
742 $langs->load("errors");
743 print '<a class="butActionRefused" href="" title="'.$langs->trans("ErrorAddAtLeastOneLineFirst").'">'.$langs->trans("Validate").'</a>';
744 }
745 }
746 }
747
748 // Consume or produce
749 if ($object->status == Mo::STATUS_VALIDATED || $object->status == Mo::STATUS_INPROGRESS) {
750 if ($permissiontoproduce) {
751 print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=consumeorproduce&token='.$newToken.'">'.$langs->trans('ConsumeOrProduce').'</a>';
752 } else {
753 print '<a class="butActionRefused classfortooltip" href="#" title="'.$langs->trans("NotEnoughPermissions").'">'.$langs->trans('ConsumeOrProduce').'</a>';
754 }
755 } elseif ($object->status == Mo::STATUS_DRAFT) {
756 print '<a class="butActionRefused classfortooltip" href="#" title="'.$langs->trans("ValidateBefore").'">'.$langs->trans('ConsumeOrProduce').'</a>';
757 }
758
759 // ConsumeAndProduceAll
760 if ($object->status == Mo::STATUS_VALIDATED || $object->status == Mo::STATUS_INPROGRESS) {
761 if ($permissiontoproduce) {
762 print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=consumeandproduceall&token='.$newToken.'">'.$langs->trans('ConsumeAndProduceAll').'</a>';
763 } else {
764 print '<a class="butActionRefused classfortooltip" href="#" title="'.$langs->trans("NotEnoughPermissions").'">'.$langs->trans('ConsumeAndProduceAll').'</a>';
765 }
766 } elseif ($object->status == Mo::STATUS_DRAFT) {
767 print '<a class="butActionRefused classfortooltip" href="#" title="'.$langs->trans("ValidateBefore").'">'.$langs->trans('ConsumeAndProduceAll').'</a>';
768 }
769
770 // Cancel - Reopen
771 if ($permissiontoadd) {
772 if ($object->status == $object::STATUS_VALIDATED || $object->status == $object::STATUS_INPROGRESS) {
773 $arrayproduced = $object->fetchLinesLinked('produced', 0);
774 $nbProduced = 0;
775 foreach ($arrayproduced as $lineproduced) {
776 $nbProduced += $lineproduced['qty'];
777 }
778 if ($nbProduced > 0) { // If production has started, we can close it
779 print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=confirm_produced&confirm=yes&token='.$newToken.'">'.$langs->trans("Close").'</a>'."\n";
780 } else {
781 print '<a class="butActionRefused" href="#" title="'.$langs->trans("GoOnTabProductionToProduceFirst", $langs->transnoentitiesnoconv("Production")).'">'.$langs->trans("Close").'</a>'."\n";
782 }
783
784 print '<a class="butActionDelete" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=cancel&token='.$newToken.'">'.$langs->trans("Cancel").'</a>'."\n";
785 }
786
787 if ($object->status == $object::STATUS_CANCELED) {
788 print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=confirm_reopen&confirm=yes&token='.$newToken.'">'.$langs->trans("ReOpen").'</a>'."\n";
789 }
790
791 if ($object->status == $object::STATUS_PRODUCED) {
792 if ($permissiontoproduce) {
793 print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=confirm_reopen&token='.$newToken.'">'.$langs->trans('ReOpen').'</a>';
794 } else {
795 print '<a class="butActionRefused classfortooltip" href="#" title="'.$langs->trans("NotEnoughPermissions").'">'.$langs->trans('ReOpen').'</a>';
796 }
797 }
798 }
799 }
800
801 print '</div>';
802 }
803
804 if (in_array($action, array('consumeorproduce', 'consumeandproduceall', 'addconsumeline', 'addproduceline', 'editline'))) {
805 print '<form method="POST" action="'.$_SERVER["PHP_SELF"].'">';
806 print '<input type="hidden" name="token" value="'.newToken().'">';
807 print '<input type="hidden" name="action" value="confirm_'.$action.'">';
808 print '<input type="hidden" name="backtopage" value="'.$backtopage.'">';
809 print '<input type="hidden" name="id" value="'.$id.'">';
810 // Note: closing form is add end of page
811
812 if (in_array($action, array('consumeorproduce', 'consumeandproduceall'))) {
813 $defaultstockmovementlabel = GETPOST('inventorylabel', 'alphanohtml') ? GETPOST('inventorylabel', 'alphanohtml') : $langs->trans("ProductionForRef", $object->ref);
814 $defaultstockmovementcode = GETPOST('inventorycode', 'alphanohtml') ? GETPOST('inventorycode', 'alphanohtml') : dol_print_date(dol_now(), 'dayhourlog');
815
816 print '<div class="center'.(in_array($action, array('consumeorproduce', 'consumeandproduceall')) ? ' formconsumeproduce' : '').'">';
817 print '<div class="opacitymedium hideonsmartphone paddingbottom">'.$langs->trans("ConfirmProductionDesc", $langs->transnoentitiesnoconv("Confirm")).'<br></div>';
818 print '<span class="fieldrequired">'.$langs->trans("InventoryCode").':</span> <input type="text" class="minwidth150 maxwidth200" name="inventorycode" value="'.$defaultstockmovementcode.'"> &nbsp; ';
819 print '<span class="clearbothonsmartphone"></span>';
820 print $langs->trans("MovementLabel").': <input type="text" class="minwidth300" name="inventorylabel" value="'.$defaultstockmovementlabel.'"><br><br>';
821 print '<input type="checkbox" id="autoclose" name="autoclose" value="1"'.(GETPOSTISSET('inventorylabel') ? (GETPOST('autoclose') ? ' checked="checked"' : '') : ' checked="checked"').'> <label for="autoclose">'.$langs->trans("AutoCloseMO").'</label><br>';
822 print '<input type="submit" class="button" value="'.$langs->trans("Confirm").'" name="confirm">';
823 print ' &nbsp; ';
824 print '<input class="button button-cancel" type="submit" value="'.$langs->trans("Cancel").'" name="cancel">';
825 print '<br><br>';
826 print '</div>';
827
828 print '<br>';
829 }
830 }
831
832
833 /*
834 * Lines
835 */
836 $collapse = 1;
837
838 if (!empty($object->table_element_line)) {
839 // Show object lines
840 $object->fetchLines();
841
842 $bomcost = 0;
843 if ($object->fk_bom > 0) {
844 $bom = new BOM($db);
845 $res = $bom->fetch($object->fk_bom);
846 if ($res > 0) {
847 $bom->calculateCosts();
848 $bomcost = $bom->unit_cost;
849 }
850 }
851
852 // Lines to consume
853
854 print '<!-- Lines to consume -->'."\n";
855 print '<div class="fichecenter">';
856 print '<div class="fichehalfleft">';
857 print '<div class="clearboth"></div>';
858
859 $url = $_SERVER["PHP_SELF"].'?id='.$object->id.'&action=addconsumeline&token='.newToken();
860 $permissiontoaddaconsumeline = ($object->status != $object::STATUS_PRODUCED && $object->status != $object::STATUS_CANCELED) ? 1 : -2;
861 $parameters = array('morecss' => 'reposition');
862 $helpText = '';
863 if ($permissiontoaddaconsumeline == -2) {
864 $helpText = $langs->trans('MOIsClosed');
865 }
866
867 $newcardbutton = '';
868 if ($action != 'consumeorproduce' && $action != 'consumeandproduceall') {
869 $newcardbutton = dolGetButtonTitle($langs->trans('AddNewConsumeLines'), $helpText, 'fa fa-plus-circle size15x', $url, '', $permissiontoaddaconsumeline, $parameters);
870 }
871
872 print load_fiche_titre($langs->trans('Consumption'), $newcardbutton, '', 0, '', '', '');
873
874 print '<div class="div-table-responsive-no-min">';
875 print '<table class="noborder noshadow centpercent nobottom">';
876
877 print '<!-- Line of title for products to consume -->'."\n";
878 print '<tr class="liste_titre trheight5em">';
879 // Product
880 print '<td>'.$langs->trans("Product").'</td>';
881 // Qty
882 print '<td class="right">'.$langs->trans("Qty").'</td>';
883 // Unit
884 print '<td></td>';
885 // Cost price
886 if ($permissiontoupdatecost && getDolGlobalString('MRP_SHOW_COST_FOR_CONSUMPTION')) {
887 print '<td class="right">'.$langs->trans("UnitCost").'</td>';
888 }
889 // Qty already consumed
890 print '<td class="right classfortooltip" title="'.$langs->trans("QtyAlreadyConsumed").'">';
891 print $langs->trans("QtyAlreadyConsumedShort");
892 print '</td>';
893 // Warehouse
894 print '<td>';
895 if ($collapse || in_array($action, array('consumeorproduce', 'consumeandproduceall'))) {
896 print $langs->trans("Warehouse");
897 if (isModEnabled('workstation')) {
898 print ' '.$langs->trans("or").' '.$langs->trans("Workstation");
899 }
900 // Select warehouse to force it everywhere
901 if (in_array($action, array('consumeorproduce', 'consumeandproduceall'))) {
902 $listwarehouses = $tmpwarehouse->list_array(1);
903 if (count($listwarehouses) > 1) {
904 print '<br>'.$form->selectarray('fk_default_warehouse', $listwarehouses, $fk_default_warehouse, $langs->trans("ForceTo"), 0, 0, '', 0, 0, 0, '', 'minwidth100 maxwidth200', 1);
905 } elseif (count($listwarehouses) == 1) {
906 print '<br>'.$form->selectarray('fk_default_warehouse', $listwarehouses, $fk_default_warehouse, 0, 0, 0, '', 0, 0, 0, '', 'minwidth100 maxwidth200', 1);
907 }
908 }
909 }
910 print '</td>';
911
912 if (isModEnabled('stock')) {
913 // Available
914 print '<td align="right">';
915 if ($collapse || in_array($action, array('consumeorproduce', 'consumeandproduceall'))) {
916 print $langs->trans("Stock");
917 }
918 print '</td>';
919 }
920 // Lot - serial
921 if (isModEnabled('productbatch')) {
922 print '<td>';
923 if ($collapse || in_array($action, array('consumeorproduce', 'consumeandproduceall'))) {
924 print $langs->trans("Batch");
925 }
926 print '</td>';
927 }
928
929 // Split
930 print '<td></td>';
931
932 // SplitAll
933 print '<td></td>';
934
935 // Edit Line
936 if ($object->status == Mo::STATUS_DRAFT) {
937 print '<td></td>';
938 }
939
940 // Action
941 if ($permissiontodelete) {
942 print '<td></td>';
943 }
944
945 print '</tr>';
946
947 if ($action == 'addconsumeline') {
948 print '<!-- Add line to consume -->'."\n";
949 print '<tr class="liste_titre">';
950 // Product
951 print '<td>';
952 print $form->select_produits(0, 'productidtoadd', '', 0, 0, -1, 2, '', 1, array(), 0, '1', 0, 'maxwidth150');
953 print '</td>';
954 // Qty
955 print '<td class="right"><input type="text" name="qtytoadd" value="1" class="width40 right"></td>';
956 // Unit
957 print '<td>';
958 //if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
959 //...
960 //}
961 print '</td>';
962 // Cost price
963 if ($permissiontoupdatecost && getDolGlobalString('MRP_SHOW_COST_FOR_CONSUMPTION')) {
964 print '<td></td>';
965 }
966
967 $colspan = 3;
968 if (isModEnabled('stock')) {
969 $colspan++;
970 }
971 if (isModEnabled('productbatch')) {
972 $colspan++;
973 }
974 // Qty already consumed + Warehouse
975 print '<td colspan="'.$colspan.'">';
976 print '<input type="submit" class="button buttongen button-add" name="addconsumelinebutton" value="'.$langs->trans("Add").'">';
977 print '<input type="submit" class="button buttongen button-cancel" name="canceladdconsumelinebutton" value="'.$langs->trans("Cancel").'">';
978 print '</td>';
979 // Split All
980 print '<td></td>';
981 // Edit Line
982 if ($object->status == Mo::STATUS_DRAFT) {
983 print '<td></td>';
984 }
985 // Action
986 if ($permissiontodelete) {
987 print '<td></td>';
988 }
989 print '</tr>';
990
991 // Extrafields Line
992 if (is_object($objectline)) {
993 $extrafields->fetch_name_optionals_label($object->table_element_line);
994 $temps = $objectline->showOptionals($extrafields, 'edit', array(), '', '', '1', 'line');
995 if (!empty($temps)) {
996 print '<tr class="liste_titre"><td style="padding-top: 20px" colspan="9" id="extrafield_lines_area_edit" name="extrafield_lines_area_edit">';
997 print $temps;
998 print '</td></tr>';
999 }
1000 }
1001 }
1002
1003 // Lines to consume
1004
1005 $bomcostupdated = 0; // We will recalculate the unitary cost to produce a product using the real "products to consume into MO"
1006
1007 if (!empty($object->lines)) {
1008 $nblinetoconsume = 0;
1009 foreach ($object->lines as $line) {
1010 if ($line->role == 'toconsume') {
1011 $nblinetoconsume++;
1012 }
1013 }
1014
1015 $nblinetoconsumecursor = 0;
1016 foreach ($object->lines as $line) {
1017 if ($line->role == 'toconsume') {
1018 $nblinetoconsumecursor++;
1019
1020 $tmpproduct = new Product($db);
1021 $tmpproduct->fetch($line->fk_product);
1022 $linecost = price2num($tmpproduct->pmp, 'MT');
1023
1024 if ($object->qty > 0) {
1025 // add free consume line cost to $bomcostupdated
1026 $costprice = price2num((!empty($tmpproduct->cost_price)) ? $tmpproduct->cost_price : $tmpproduct->pmp);
1027 if (empty($costprice)) {
1028 require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.product.class.php';
1029 $productFournisseur = new ProductFournisseur($db);
1030 if ($productFournisseur->find_min_price_product_fournisseur($line->fk_product, $line->qty) > 0) {
1031 $costprice = $productFournisseur->fourn_unitprice;
1032 } else {
1033 $costprice = 0;
1034 }
1035 }
1036
1037 $useunit = (($tmpproduct->type == Product::TYPE_PRODUCT && getDolGlobalInt('PRODUCT_USE_UNITS')) || (($tmpproduct->type == Product::TYPE_SERVICE) && ($line->fk_unit)));
1038
1039 if ($useunit && $line->fk_unit > 0) {
1040 $reg = [];
1041 $qtyhourservice = 0;
1042 if (preg_match('/^(\d+)([a-z]+)$/', $tmpproduct->duration, $reg)) {
1043 $qtyhourservice = convertDurationtoHour((float) $reg[1], (string) $reg[2]);
1044 }
1045 $qtyhourforline = 0;
1046 if ($line->fk_unit) {
1047 $unitforline = measuringUnitString($line->fk_unit, '', null, 1);
1048 $qtyhourforline = convertDurationtoHour($line->qty, $unitforline);
1049 }
1050
1051 if ($qtyhourservice && $qtyhourforline) {
1052 $linecost = price2num(($qtyhourforline / $qtyhourservice * $costprice) / $object->qty, 'MT'); // price for line for all quantities
1053 $bomcostupdated += price2num(($qtyhourforline / $qtyhourservice * $costprice) / $object->qty, 'MU'); // same but with full accuracy
1054 } else {
1055 $linecost = price2num(($line->qty * $costprice) / $object->qty, 'MT'); // price for line for all quantities
1056 $bomcostupdated += price2num(($line->qty * $costprice) / $object->qty, 'MU'); // same but with full accuracy
1057 }
1058 } else {
1059 $linecost = price2num(($line->qty * $costprice) / $object->qty, 'MT'); // price for line for all quantities
1060 $bomcostupdated += price2num(($line->qty * $costprice) / $object->qty, 'MU'); // same but with full accuracy
1061 }
1062 }
1063
1064 $bomcostupdated = price2num($bomcostupdated, 'MU');
1065 $arrayoflines = $object->fetchLinesLinked('consumed', $line->id);
1066 $alreadyconsumed = 0;
1067 foreach ($arrayoflines as $line2) {
1068 $alreadyconsumed += $line2['qty'];
1069 }
1070
1071 if ($action == 'editline' && $lineid == $line->id) {
1072 $linecost = price2num($tmpproduct->pmp, 'MT');
1073
1074 $arrayoflines = $object->fetchLinesLinked('consumed', $line->id);
1075 $alreadyconsumed = 0;
1076 if (is_array($arrayoflines) && !empty($arrayoflines)) {
1077 foreach ($arrayoflines as $line2) {
1078 $alreadyconsumed += $line2['qty'];
1079 }
1080 }
1081 $suffix = '_' . $line->id;
1082 print '<!-- Line to dispatch ' . $suffix . ' (line edited) -->' . "\n";
1083 // hidden fields for js function
1084 print '<input id="qty_ordered' . $suffix . '" type="hidden" value="' . $line->qty . '">';
1085 // Duration - Time spent
1086 print '<input id="qty_dispatched' . $suffix . '" type="hidden" value="' . $alreadyconsumed . '">';
1087 print '<tr>';
1088 print '<input name="lineid" type="hidden" value="' . $line->id . '">';
1089
1090 // Product
1091 print '<td>' . $tmpproduct->getNomUrl(1);
1092 print '<br><div class="opacitymedium small tdoverflowmax150" title="' . dol_escape_htmltag($tmpproduct->label) . '">' . $tmpproduct->label . '</span>';
1093 print '</td>';
1094
1095 // Qty
1096 print '<td class="right nowraponall">';
1097 print '<input class="width40 right" name="qty_lineProduce" value="'. $line->qty.'">';
1098 print '</td>';
1099
1100 // Unit
1101 print '<td class="right nowraponall">';
1102 $useunit = (($tmpproduct->type == Product::TYPE_PRODUCT && getDolGlobalInt('PRODUCT_USE_UNITS')) || (($tmpproduct->type == Product::TYPE_SERVICE) && ($line->fk_unit)));
1103 if ($useunit) {
1104 print measuringUnitString($line->fk_unit, '', null, 2);
1105 }
1106 print '</td>';
1107
1108 // Cost price
1109 if ($permissiontoupdatecost && getDolGlobalString('MRP_SHOW_COST_FOR_CONSUMPTION')) {
1110 print '<td></td>';
1111 }
1112
1113 // Qty consumed
1114 print '<td class="right">';
1115 print ' ' . price2num($alreadyconsumed, 'MS');
1116 print '</td>';
1117
1118 // Warehouse / Workstation
1119 print '<td>';
1120 if ($tmpproduct->type == Product::TYPE_PRODUCT) {
1121 print $formproduct->selectWarehouses($line->fk_warehouse, 'warehouse_lineProduce', 'warehouseopen', 1);
1122 } elseif (isModEnabled('workstation')) {
1123 print $formproduct->selectWorkstations($line->fk_default_workstation, 'workstation_lineProduce', 1);
1124 }
1125 print '</td>';
1126
1127 // Stock
1128 if (isModEnabled('stock')) {
1129 print '<td class="nowraponall right">';
1130 if ($tmpproduct->isStockManaged()) {
1131 if ($tmpproduct->stock_reel < ($line->qty - $alreadyconsumed)) {
1132 print img_warning($langs->trans('StockTooLow')).' ';
1133 }
1134 print '<span class="left">'. $tmpproduct->stock_reel .' </span>';
1135 }
1136 print '</td>';
1137 }
1138
1139 // Lot - serial
1140 if (isModEnabled('productbatch')) {
1141 print '<td></td>';
1142 }
1143 // Split + SplitAll + Edit line + Delete
1144 print '<td colspan="'.(3 + ($object->status == Mo::STATUS_DRAFT ? 1 : 0) + ($permissiontodelete ? 1 : 0)).'">';
1145 print '<input type="submit" class="button buttongen button-add small nominwidth" name="save" value="' . $langs->trans("Save") . '">';
1146 print '<input type="submit" class="button buttongen button-cancel small nominwidth" name="cancel" value="' . $langs->trans("Cancel") . '">';
1147 print '</td>';
1148
1149 print '</tr>';
1150
1151 // Extrafields Line
1152 if (!empty($extrafields)) {
1153 $line->fetch_optionals();
1154 $temps = $line->showOptionals($extrafields, 'edit', array(), '', '', '1', 'line');
1155 if (!empty($temps)) {
1156 $colspan = 10;
1157 print '<tr><td colspan="'.$colspan.'"><div style="padding-top: 20px" id="extrafield_lines_area_edit" name="extrafield_lines_area_edit">';
1158 print $temps;
1159 print '</div></td></tr>';
1160 }
1161 }
1162 } else {
1163 $suffix = '_' . $line->id;
1164 print '<!-- Line to dispatch ' . $suffix . ' -->' . "\n";
1165 // hidden fields for js function
1166 print '<input id="qty_ordered' . $suffix . '" type="hidden" value="' . $line->qty . '">';
1167 print '<input id="qty_dispatched' . $suffix . '" type="hidden" value="' . $alreadyconsumed . '">';
1168
1169 print '<tr data-line-id="' . $line->id . '">';
1170
1171 // Product
1172 print '<td>' . $tmpproduct->getNomUrl(1);
1173 print '<br><div class="opacitymedium small tdoverflowmax150" title="' . dol_escape_htmltag($tmpproduct->label) . '">' . $tmpproduct->label . '</div>';
1174 print '</td>';
1175
1176 // Qty
1177 print '<td class="right nowraponall">';
1178 $help = '';
1179 if ($line->qty_frozen) {
1180 $help = ($help ? '<br>' : '') . '<strong>' . $langs->trans("QuantityFrozen") . '</strong>: ' . yn(1) . ' (' . $langs->trans("QuantityConsumedInvariable") . ')';
1181 print $form->textwithpicto('', $help, -1, 'lock') . ' ';
1182 }
1183 if ($line->disable_stock_change) {
1184 $help = ($help ? '<br>' : '') . '<strong>' . $langs->trans("DisableStockChange") . '</strong>: ' . yn(1) . ' (' . (($tmpproduct->type == Product::TYPE_SERVICE && !getDolGlobalString('STOCK_SUPPORTS_SERVICES')) ? $langs->trans("NoStockChangeOnServices") : $langs->trans("DisableStockChangeHelp")) . ')';
1185 print $form->textwithpicto('', $help, -1, 'help') . ' ';
1186 }
1187 print price2num($line->qty, 'MS');
1188 print '</td>';
1189
1190 // Unit
1191 print '<td class="right nowraponall">';
1192 $useunit = (($tmpproduct->type == Product::TYPE_PRODUCT && getDolGlobalInt('PRODUCT_USE_UNITS')) || (($tmpproduct->type == Product::TYPE_SERVICE) && ($line->fk_unit)));
1193 if ($useunit) {
1194 print measuringUnitString($line->fk_unit, '', null, 2);
1195 }
1196 print '</td>';
1197
1198 // Cost price
1199 if ($permissiontoupdatecost && getDolGlobalString('MRP_SHOW_COST_FOR_CONSUMPTION')) {
1200 print '<td class="right nowraponall">';
1201 print price($linecost);
1202 print '</td>';
1203 }
1204
1205 // Already consumed
1206 print '<td class="right">';
1207 if ($alreadyconsumed) {
1208 print '<script>';
1209 print 'jQuery(document).ready(function() {
1210 jQuery("#expandtoproduce' . $line->id . '").click(function() {
1211 console.log("Expand mrp_production line ' . $line->id . '");
1212 jQuery(".expanddetail' . $line->id . '").toggle();';
1213 if ($nblinetoconsume == $nblinetoconsumecursor) { // If it is the last line
1214 print 'if (jQuery("#tablelines").hasClass("nobottom")) { jQuery("#tablelines").removeClass("nobottom"); } else { jQuery("#tablelines").addClass("nobottom"); }';
1215 }
1216 print '
1217 });
1218 });';
1219 print '</script>';
1220 if (empty($conf->use_javascript_ajax)) {
1221 print '<a href="' . $_SERVER["PHP_SELF"] . '?collapse=' . $collapse . ',' . $line->id . '">';
1222 }
1223 print img_picto($langs->trans("ShowDetails"), "chevron-down", 'id="expandtoproduce' . $line->id . '"');
1224 if (empty($conf->use_javascript_ajax)) {
1225 print '</a>';
1226 }
1227 } else {
1228 if ($nblinetoconsume == $nblinetoconsumecursor) { // If it is the last line
1229 print '<script>jQuery("#tablelines").removeClass("nobottom");</script>';
1230 }
1231 }
1232 print ' ' . price2num($alreadyconsumed, 'MS');
1233 print '</td>';
1234
1235 // Warehouse and/or workstation
1236 print '<td class="tdoverflowmax100">';
1237 if ($tmpproduct->isStockManaged()) {
1238 // When STOCK_CONSUMPTION_FROM_MANUFACTURING_WAREHOUSE is set, we always use the warehouse of the MO, the same than production.
1239 if (getDolGlobalString('STOCK_CONSUMPTION_FROM_MANUFACTURING_WAREHOUSE') && $tmpwarehouse->id > 0) {
1240 print img_picto('', $tmpwarehouse->picto) . " " . $tmpwarehouse->label;
1241 } else {
1242 if ($line->fk_warehouse > 0) {
1243 $warehouseline = new Entrepot($db);
1244 $warehouseline->fetch($line->fk_warehouse);
1245 print $warehouseline->getNomUrl(1);
1246 }
1247 }
1248 }
1249 if (isModEnabled('workstation') && $line->fk_default_workstation > 0) {
1250 $tmpworkstation = new Workstation($db);
1251 $tmpworkstation->fetch($line->fk_default_workstation);
1252 print $tmpworkstation->getNomUrl(1);
1253 }
1254 print '</td>';
1255
1256 // Stock
1257 if (isModEnabled('stock')) {
1258 print '<td class="nowraponall right">';
1259 if (!getDolGlobalString('STOCK_SUPPORTS_SERVICES') && $tmpproduct->type != Product::TYPE_SERVICE) {
1260 if (!$line->disable_stock_change && $tmpproduct->stock_reel < ($line->qty - $alreadyconsumed)) {
1261 print img_warning($langs->trans('StockTooLow')) . ' ';
1262 }
1263 if (!getDolGlobalString('STOCK_CONSUMPTION_FROM_MANUFACTURING_WAREHOUSE') || empty($tmpwarehouse->id)) {
1264 print price2num($tmpproduct->stock_reel, 'MS'); // Available
1265 } else {
1266 // Print only the stock in the selected warehouse
1267 $tmpproduct->load_stock();
1268 $wh_stock = $tmpproduct->stock_warehouse[$tmpwarehouse->id];
1269 if (!empty($wh_stock)) {
1270 print price2num($wh_stock->real, 'MS');
1271 } else {
1272 print "0";
1273 }
1274 }
1275 }
1276 print '</td>';
1277 }
1278
1279 // Lot
1280 if (isModEnabled('productbatch')) {
1281 print '<td></td>';
1282 }
1283
1284 // Split
1285 print '<td></td>';
1286
1287 // Split All
1288 print '<td></td>';
1289
1290 // Action Edit line
1291 if ($object->status == Mo::STATUS_DRAFT) {
1292 $href = $_SERVER["PHP_SELF"] . '?id=' . ((int) $object->id) . '&action=editline&token=' . newToken() . '&lineid=' . ((int) $line->id);
1293 print '<td class="center">';
1294 print '<a class="reposition editfielda" href="' . $href . '">';
1295 print img_picto($langs->trans('TooltipEditAndRevertStockMovement'), 'edit');
1296 print '</a>';
1297 print '</td>';
1298 }
1299
1300 // Action delete line, if no consumption has occurred for this product
1301 if ($permissiontodelete && empty($arrayoflines)) {
1302 $href = $_SERVER["PHP_SELF"] . '?id=' . ((int) $object->id) . '&action=deleteline&token=' . newToken() . '&lineid=' . ((int) $line->id);
1303 print '<td class="center">';
1304 print '<a class="reposition" href="' . $href . '">';
1305 print img_picto($langs->trans('TooltipDeleteAndRevertStockMovement'), 'delete');
1306 print '</a>';
1307 print '</td>';
1308 }
1309
1310 print '</tr>';
1311
1312 // Extrafields Line
1313 if (!empty($extrafields)) {
1314 $line->fetch_optionals();
1315 $temps = $line->showOptionals($extrafields, 'view', array(), '', '', '1', 'line');
1316 if (!empty($temps)) {
1317 $colspan = 10;
1318 print '<tr><td colspan="'.$colspan.'"><div id="extrafield_lines_area_'.$line->id.'" name="extrafield_lines_area_'.$line->id.'">';
1319 print $temps;
1320 print '</div></td></tr>';
1321 }
1322 }
1323 }
1324
1325 // Show detailed of already consumed with js code to collapse
1326 foreach ($arrayoflines as $line2) {
1327 print '<tr class="expanddetail'.$line->id.' hideobject opacitylow">';
1328
1329 // Date
1330 print '<td>';
1331 $tmpstockmovement->id = $line2['fk_stock_movement'];
1332 print '<a href="'.DOL_URL_ROOT.'/product/stock/movement_list.php?search_ref='.$tmpstockmovement->id.'">'.img_picto($langs->trans("StockMovement"), 'movement', 'class="paddingright"').'</a>';
1333 print dol_print_date($line2['date'], 'dayhour', 'tzuserrel');
1334 print '</td>';
1335
1336 // Qty
1337 print '<td></td>';
1338
1339 // Unit
1340 print '<td></td>';
1341
1342 // Cost price
1343 if ($permissiontoupdatecost && getDolGlobalString('MRP_SHOW_COST_FOR_CONSUMPTION')) {
1344 print '<td></td>';
1345 }
1346
1347 //Already consumed
1348 print '<td class="right">'.$line2['qty'].'</td>';
1349
1350 // Warehouse
1351 print '<td class="tdoverflowmax150">';
1352 if ($line2['fk_warehouse'] > 0) {
1353 $result = $tmpwarehouse->fetch($line2['fk_warehouse']);
1354 if ($result > 0) {
1355 print $tmpwarehouse->getNomUrl(1);
1356 }
1357 }
1358 print '</td>';
1359
1360 // Stock
1361 if (isModEnabled('stock')) {
1362 print '<td></td>';
1363 }
1364
1365 // Lot Batch
1366 if (isModEnabled('productbatch')) {
1367 print '<td>';
1368 if ($line2['batch'] != '') {
1369 $tmpbatch->fetch(0, $line2['fk_product'], $line2['batch']);
1370 print $tmpbatch->getNomUrl(1);
1371 }
1372 print '</td>';
1373 }
1374
1375 // Split
1376 print '<td></td>';
1377
1378 // Split All
1379 print '<td></td>';
1380
1381 // Action Edit line
1382 if ($object->status == Mo::STATUS_DRAFT) {
1383 $href = $_SERVER["PHP_SELF"] . '?id=' . ((int) $object->id) . '&action=editline&token=' . newToken() . '&lineid=' . ((int) $line2['rowid']);
1384 print '<td class="center">';
1385 print '<a class="reposition" href="' . $href . '">';
1386 print img_picto($langs->trans('TooltipEditAndRevertStockMovement'), 'edit');
1387 print '</a>';
1388 print '</td>';
1389 }
1390
1391 // Action delete line
1392 if ($permissiontodelete) {
1393 $href = $_SERVER["PHP_SELF"].'?id='.((int) $object->id).'&action=deleteline&token='.newToken().'&lineid='.((int) $line2['rowid']).'&fk_movement='.((int) $line2['fk_stock_movement']);
1394 print '<td class="center">';
1395 print '<a class="reposition" href="'.$href.'">';
1396 print img_picto($langs->trans('TooltipDeleteAndRevertStockMovement'), 'delete');
1397 print '</a>';
1398 print '</td>';
1399 }
1400
1401 print '</tr>';
1402 }
1403
1404 if (in_array($action, array('consumeorproduce', 'consumeandproduceall'))) {
1405 $i = 1;
1406 print '<!-- Enter line to consume -->'."\n";
1407 $maxQty = 1;
1408 print '<tr data-max-qty="'.$maxQty.'" name="batch_'.$line->id.'_'.$i.'">';
1409 // Ref
1410 print '<td><span class="opacitymedium">'.$langs->trans("ToConsume").'</span></td>';
1411 $preselected = (GETPOSTISSET('qty-'.$line->id.'-'.$i) ? GETPOST('qty-'.$line->id.'-'.$i) : max(0, $line->qty - $alreadyconsumed));
1412 if ($action == 'consumeorproduce' && !getDolGlobalString('MRP_AUTO_SET_REMAINING_QUANTITIES_TO_BE_CONSUMED') && !GETPOSTISSET('qty-'.$line->id.'-'.$i)) {
1413 $preselected = 0;
1414 }
1415
1416 $disable = '';
1417 if (getDolGlobalString('MRP_NEVER_CONSUME_MORE_THAN_EXPECTED') && ($line->qty - $alreadyconsumed) <= 0) {
1418 $disable = 'disabled';
1419 }
1420
1421 // input hidden with fk_product of line
1422 print '<input type="hidden" name="product-'.$line->id.'-'.$i.'" value="'.$line->fk_product.'">';
1423
1424 // Qty
1425 print '<td class="right">';
1426 if ((int) $tmpproduct->stockable_product > 0) {
1427 print '<input type="text" class="width50 right" id="qtytoconsume-' . $line->id . '-' . $i . '" name="qty-' . $line->id . '-' . $i . '" value="' . $preselected . '" ' . $disable . '>';
1428 } else {
1429 print '<input type="hidden" id="qtytoconsume-' . $line->id . '-' . $i . '" name="qty-' . $line->id . '-' . $i . '" value="0">';
1430 print '<span class="opacitymedium">' . $langs->trans("StockDisabled") . '</span>';
1431 }
1432 print '</td>';
1433
1434 // Unit
1435 print '<td></td>';
1436
1437 // Cost
1438 if ($permissiontoupdatecost && getDolGlobalString('MRP_SHOW_COST_FOR_CONSUMPTION')) {
1439 print '<td></td>';
1440 }
1441
1442 // Already consumed
1443 print '<td></td>';
1444
1445 // Warehouse
1446 print '<td>';
1447 if (($tmpproduct->type == Product::TYPE_PRODUCT || getDolGlobalString('STOCK_SUPPORTS_SERVICES'))
1448 && ((int) $tmpproduct->stockable_product > 0)) {
1449 if (empty($line->disable_stock_change)) {
1450 $preselected = (GETPOSTISSET('idwarehouse-'.$line->id.'-'.$i) ? GETPOST('idwarehouse-'.$line->id.'-'.$i) : ($tmpproduct->fk_default_warehouse > 0 ? $tmpproduct->fk_default_warehouse : 'ifone'));
1451 print $formproduct->selectWarehouses($preselected, 'idwarehouse-'.$line->id.'-'.$i, '', 1, 0, $line->fk_product, '', 1, 0, array(), 'maxwidth200 csswarehouse_'.$line->id.'_'.$i);
1452 } else {
1453 print '<span class="opacitymedium">'.$langs->trans("DisableStockChange").'</span>';
1454 }
1455 } else {
1456 if ((int) $tmpproduct->stockable_product > 0) {
1457 print '<span class="opacitymedium">' . $langs->trans("StockDisabled") . '</span>';
1458 } else {
1459 print '<span class="opacitymedium">' . $langs->trans("NoStockChangeOnServices") . '</span>';
1460 }
1461 }
1462 print '</td>';
1463
1464 // Stock
1465 if (isModEnabled('stock')) {
1466 print '<td></td>';
1467 }
1468
1469 // Lot / Batch
1470 if (isModEnabled('productbatch')) {
1471 print '<td class="nowraponall">';
1472 if ($tmpproduct->status_batch) {
1473 $preselected = (GETPOSTISSET('batch-'.$line->id.'-'.$i) ? GETPOST('batch-'.$line->id.'-'.$i) : '');
1474 print '<input type="text" class="width75" name="batch-'.$line->id.'-'.$i.'" value="'.$preselected.'" list="batch-'.$line->id.'-'.$i.'">';
1475 print $formproduct->selectLotDataList('batch-'.$line->id.'-'.$i, 0, $line->fk_product, 0, array());
1476 }
1477 print '</td>';
1478 }
1479
1480 // Split
1481 $type = 'batch';
1482 print '<td align="right" class="split">';
1483 print ' '.img_picto($langs->trans('AddStockLocationLine'), 'split.png', 'class="splitbutton" onClick="addDispatchLine('.((int) $line->id).', \''.dol_escape_js($type).'\', \'qtymissingconsume\')"');
1484 print '</td>';
1485
1486 // Split All
1487 print '<td align="right" class="splitall">';
1488 if (($action == 'consumeorproduce' || $action == 'consumeandproduceall') && $tmpproduct->status_batch == 2) {
1489 print img_picto($langs->trans('SplitAllQuantity'), 'split.png', 'class="splitbutton splitallbutton field-error-icon" data-max-qty="1" onClick="addDispatchLine('.$line->id.', \'batch\', \'allmissingconsume\')"');
1490 }
1491 print '</td>';
1492
1493 // Edit Line
1494 if ($object->status == Mo::STATUS_DRAFT) {
1495 print '<td></td>';
1496 }
1497
1498 // Action delete line
1499 if ($permissiontodelete) {
1500 print '<td></td>';
1501 }
1502
1503 print '</tr>';
1504 }
1505 }
1506 }
1507 }
1508
1509 print '</table>';
1510 print '</div>';
1511
1512 // default warehouse processing
1513 print '<script type="text/javascript">
1514 $(document).ready(function () {
1515 $("select[name=fk_default_warehouse]").change(function() {
1516 var fk_default_warehouse = $("option:selected", this).val();
1517 $("select[name^=idwarehouse-]").val(fk_default_warehouse).change();
1518 });
1519 });
1520 </script>';
1521
1522 if (in_array($action, array('consumeorproduce', 'consumeandproduceall')) &&
1523 getDolGlobalString('STOCK_CONSUMPTION_FROM_MANUFACTURING_WAREHOUSE')) {
1524 print '<script>$(document).ready(function () {
1525 $("#fk_default_warehouse").change();
1526 });</script>';
1527 }
1528
1529
1530 // Lines to produce
1531
1532 print '</div>';
1533 print '<div class="fichehalfright">';
1534 print '<div class="clearboth"></div>';
1535
1536 $nblinetoproduce = 0;
1537 foreach ($object->lines as $line) {
1538 if ($line->role == 'toproduce') {
1539 $nblinetoproduce++;
1540 }
1541 }
1542
1543 $newcardbutton = '';
1544 $url = $_SERVER["PHP_SELF"].'?id='.$object->id.'&action=addproduceline&token='.newToken();
1545 $permissiontoaddaproductline = $object->status != $object::STATUS_PRODUCED && $object->status != $object::STATUS_CANCELED;
1546 $parameters = array('morecss' => 'reposition');
1547 if ($action != 'consumeorproduce' && $action != 'consumeandproduceall') {
1548 if ($nblinetoproduce == 0 || $object->mrptype == 1) {
1549 $newcardbutton = dolGetButtonTitle($langs->trans('AddNewProduceLines'), '', 'fa fa-plus-circle size15x', $url, '', (int) $permissiontoaddaproductline, $parameters);
1550 }
1551 }
1552
1553 print load_fiche_titre($langs->trans('Production'), $newcardbutton, '', 0, '', '');
1554
1555 print '<div class="div-table-responsive-no-min">';
1556 print '<table id="tablelinestoproduce" class="noborder noshadow nobottom centpercent">';
1557
1558 print '<tr class="liste_titre trheight5em">';
1559 // Product
1560 print '<td>'.$langs->trans("Product").'</td>';
1561 // Qty
1562 print '<td class="right">'.$langs->trans("Qty").'</td>';
1564 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
1565 print '<td class="right">'.$langs->trans("Unit").'</td>';
1566 }
1567 // Cost price
1568 if ($permissiontoupdatecost) {
1569 if (empty($bomcostupdated)) {
1570 print '<td class="right classfortooltip" title="'.$langs->trans("AmountUsedToUpdateWAP").'">';
1571 print $langs->trans("UnitCost");
1572 print '</td>';
1573 } else {
1574 print '<td class="right classfortooltip" title="'.$langs->trans("AmountUsedToUpdateWAP").'">';
1575 print $langs->trans("ManufacturingPrice");
1576 print '</td>';
1577 }
1578 }
1579 // Already produced
1580 print '<td class="right classfortooltip" title="'.$langs->trans("QtyAlreadyProduced").'">';
1581 print $langs->trans("QtyAlreadyProducedShort");
1582 print '</td>';
1583 // Warehouse
1584 print '<td>';
1585 if ($collapse || in_array($action, array('consumeorproduce', 'consumeandproduceall'))) {
1586 print $langs->trans("Warehouse");
1587 }
1588 print '</td>';
1589
1590 // Lot
1591 if (isModEnabled('productbatch')) {
1592 print '<td>';
1593 if ($collapse || in_array($action, array('consumeorproduce', 'consumeandproduceall'))) {
1594 print $langs->trans("Batch");
1595 }
1596 print '</td>';
1597
1598 // Split
1599 print '<td></td>';
1600
1601 // Split All
1602 print '<td></td>';
1603 }
1604
1605 // Action delete
1606 if ($permissiontodelete) {
1607 print '<td></td>';
1608 }
1609
1610 print '</tr>';
1611
1612 if ($action == 'addproduceline') {
1613 print '<!-- Add line to produce -->'."\n";
1614 print '<tr class="liste_titre">';
1615
1616 // Product
1617 print '<td>';
1618 print $form->select_produits(0, 'productidtoadd', '', 0, 0, -1, 2, '', 1, array(), 0, '1', 0, 'maxwidth300');
1619 print '</td>';
1620 // Qty
1621 print '<td class="right"><input type="text" name="qtytoadd" value="1" class="width50 right"></td>';
1622 //Unit
1623 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
1624 print '<td></td>';
1625 }
1626 // Cost price
1627 if ($permissiontoupdatecost) {
1628 print '<td></td>';
1629 }
1630 // Action (cost price + already produced)
1631 print '<td colspan="2">';
1632 print '<input type="submit" class="button buttongen button-add" name="addproducelinebutton" value="'.$langs->trans("Add").'">';
1633 print '<input type="submit" class="button buttongen button-cancel" name="canceladdproducelinebutton" value="'.$langs->trans("Cancel").'">';
1634 print '</td>';
1635 // Lot - serial
1636 if (isModEnabled('productbatch')) {
1637 print '<td></td>';
1638
1639 // Split
1640 print '<td></td>';
1641
1642 // Split All
1643 print '<td></td>';
1644 }
1645 // Action delete
1646 if ($permissiontodelete) {
1647 print '<td></td>';
1648 }
1649 print '</tr>';
1650 }
1651
1652 if (!empty($object->lines)) {
1653 $nblinetoproduce = 0;
1654 foreach ($object->lines as $line) {
1655 if ($line->role == 'toproduce') {
1656 $nblinetoproduce++;
1657 }
1658 }
1659
1660 $nblinetoproducecursor = 0;
1661 foreach ($object->lines as $line) {
1662 if ($line->role == 'toproduce') {
1663 $i = 1;
1664
1665 $nblinetoproducecursor++;
1666
1667 $tmpproduct = new Product($db);
1668 $tmpproduct->fetch($line->fk_product);
1669
1670 $arrayoflines = $object->fetchLinesLinked('produced', $line->id);
1671 $alreadyproduced = 0;
1672 foreach ($arrayoflines as $line2) {
1673 $alreadyproduced += $line2['qty'];
1674 }
1675
1676 $suffix = '_'.$line->id;
1677 print '<!-- Line to dispatch '.$suffix.' (toproduce) -->'."\n";
1678 // hidden fields for js function
1679 print '<input id="qty_ordered'.$suffix.'" type="hidden" value="'.$line->qty.'">';
1680 print '<input id="qty_dispatched'.$suffix.'" type="hidden" value="'.$alreadyproduced.'">';
1681
1682 print '<tr>';
1683 // Product
1684 print '<td>'.$tmpproduct->getNomUrl(1);
1685 print '<br><span class="opacitymedium small">'.$tmpproduct->label.'</span>';
1686 print '</td>';
1687 // Qty
1688 print '<td class="right">'.$line->qty.'</td>';
1689 // Unit
1690 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
1691 print '<td class="right">'.measuringUnitString($line->fk_unit, '', null, 1).'</td>';
1692 }
1693 // Cost price
1694 if ($permissiontoupdatecost) {
1695 // Defined $manufacturingcost
1696 $manufacturingcost = 0;
1697 $manufacturingcostsrc = '';
1698 if ($object->mrptype == 0) { // If MO is a "Manufacture" type (and not "Disassemble")
1699 $manufacturingcost = $bomcostupdated;
1700 $manufacturingcostsrc = $langs->trans("CalculatedFromProductsToConsume");
1701 if (empty($manufacturingcost)) {
1702 $manufacturingcost = $bomcost;
1703 $manufacturingcostsrc = $langs->trans("ValueFromBom");
1704 }
1705 if (empty($manufacturingcost)) {
1706 $manufacturingcost = price2num($tmpproduct->cost_price, 'MU');
1707 $manufacturingcostsrc = $langs->trans("CostPrice");
1708 }
1709 if (empty($manufacturingcost)) {
1710 $manufacturingcost = price2num($tmpproduct->pmp, 'MU');
1711 $manufacturingcostsrc = $langs->trans("PMPValue");
1712 }
1713 }
1714
1715 print '<td class="right nowraponall" title="'.dol_escape_htmltag($manufacturingcostsrc).'">';
1716 if ($manufacturingcost) {
1717 print price($manufacturingcost);
1718 }
1719 print '</td>';
1720 }
1721 // Already produced
1722 print '<td class="right nowraponall">';
1723 if ($alreadyproduced) {
1724 print '<script>';
1725 print 'jQuery(document).ready(function() {
1726 jQuery("#expandtoproduce'.$line->id.'").click(function() {
1727 console.log("Expand mrp_production line '.$line->id.'");
1728 jQuery(".expanddetailtoproduce'.$line->id.'").toggle();';
1729 if ($nblinetoproduce == $nblinetoproducecursor) {
1730 print 'if (jQuery("#tablelinestoproduce").hasClass("nobottom")) { jQuery("#tablelinestoproduce").removeClass("nobottom"); } else { jQuery("#tablelinestoproduce").addClass("nobottom"); }';
1731 }
1732 print '
1733 });
1734 });';
1735 print '</script>';
1736 if (empty($conf->use_javascript_ajax)) {
1737 print '<a href="'.$_SERVER["PHP_SELF"].'?collapse='.$collapse.','.$line->id.'">';
1738 }
1739 print img_picto($langs->trans("ShowDetails"), "chevron-down", 'id="expandtoproduce'.$line->id.'"');
1740 if (empty($conf->use_javascript_ajax)) {
1741 print '</a>';
1742 }
1743 }
1744 print ' '.$alreadyproduced;
1745 print '</td>';
1746 // Warehouse
1747 print '<td>';
1748 print '</td>';
1749 // Lot
1750 if (isModEnabled('productbatch')) {
1751 print '<td></td>';
1752
1753 // Split
1754 print '<td></td>';
1755
1756 // Split All
1757 print '<td></td>';
1758 }
1759 // Delete
1760 if ($permissiontodelete) {
1761 if ($line->origin_type == 'free') {
1762 $href = $_SERVER["PHP_SELF"];
1763 $href .= '?id='.$object->id;
1764 $href .= '&action=deleteline';
1765 $href .= '&token='.newToken();
1766 $href .= '&lineid='.$line->id;
1767 print '<td class="center">';
1768 print '<a class="reposition" href="'.$href.'">';
1769 print img_picto($langs->trans('TooltipDeleteAndRevertStockMovement'), "delete");
1770 print '</a>';
1771 print '</td>';
1772 } else {
1773 print '<td></td>';
1774 }
1775 }
1776 print '</tr>';
1777
1778 // Show detailed of already consumed with js code to collapse
1779 foreach ($arrayoflines as $line2) {
1780 print '<tr class="expanddetailtoproduce'.$line->id.' hideobject opacitylow">';
1781 // Product
1782 print '<td>';
1783 $tmpstockmovement->id = $line2['fk_stock_movement'];
1784 print '<a href="'.DOL_URL_ROOT.'/product/stock/movement_list.php?search_ref='.$tmpstockmovement->id.'">'.img_picto($langs->trans("StockMovement"), 'movement', 'class="paddingright"').'</a>';
1785 print dol_print_date($line2['date'], 'dayhour', 'tzuserrel');
1786 print '</td>';
1787 // Qty
1788 print '<td></td>';
1789 // Unit
1790 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
1791 print '<td></td>';
1792 }
1793 // Cost price
1794 if ($permissiontoupdatecost) {
1795 print '<td></td>';
1796 }
1797 // Already produced
1798 print '<td class="right">'.$line2['qty'].'</td>';
1799 // Warehouse
1800 print '<td class="tdoverflowmax150">';
1801 if ($line2['fk_warehouse'] > 0) {
1802 $result = $tmpwarehouse->fetch($line2['fk_warehouse']);
1803 if ($result > 0) {
1804 print $tmpwarehouse->getNomUrl(1);
1805 }
1806 }
1807 print '</td>';
1808 // Lot
1809 if (isModEnabled('productbatch')) {
1810 print '<td>';
1811 if ($line2['batch'] != '') {
1812 $tmpbatch->fetch(0, $line2['fk_product'], $line2['batch']);
1813 print $tmpbatch->getNomUrl(1);
1814 }
1815 print '</td>';
1816
1817 // Split
1818 print '<td></td>';
1819
1820 // Split All
1821 print '<td></td>';
1822 }
1823 // Action delete
1824 if ($permissiontodelete) {
1825 print '<td></td>';
1826 }
1827 print '</tr>';
1828 }
1829
1830 if (in_array($action, array('consumeorproduce', 'consumeandproduceall'))) {
1831 print '<!-- Enter line to produce -->'."\n";
1832 $maxQty = 1;
1833 print '<tr data-max-qty="'.$maxQty.'" name="batch_'.$line->id.'_'.$i.'">';
1834 // Product
1835 print '<td><span class="opacitymedium">'.$langs->trans("ToProduce").'</span></td>';
1836 $preselected = (GETPOSTISSET('qtytoproduce-'.$line->id.'-'.$i) ? GETPOST('qtytoproduce-'.$line->id.'-'.$i) : max(0, $line->qty - $alreadyproduced));
1837 if ($action == 'consumeorproduce' && !GETPOSTISSET('qtytoproduce-'.$line->id.'-'.$i)) {
1838 $preselected = 0;
1839 }
1840 // Qty
1841 print '<td class="right"><input type="text" class="width50 right" id="qtytoproduce-'.$line->id.'-'.$i.'" name="qtytoproduce-'.$line->id.'-'.$i.'" value="'.$preselected.'"></td>';
1842 //Unit
1843 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
1844 print '<td class="right"></td>';
1845 }
1846 // Cost
1847 if ($permissiontoupdatecost) {
1848 // Defined $manufacturingcost
1849 $manufacturingcost = 0;
1850 $manufacturingcostsrc = '';
1851 if ($object->mrptype == 0) { // If MO is a "Manufacture" type (and not "Disassemble")
1852 $manufacturingcost = $bomcostupdated;
1853 $manufacturingcostsrc = $langs->trans("CalculatedFromProductsToConsume");
1854 if (empty($manufacturingcost)) {
1855 $manufacturingcost = $bomcost;
1856 $manufacturingcostsrc = $langs->trans("ValueFromBom");
1857 }
1858 if (empty($manufacturingcost)) {
1859 $manufacturingcost = price2num($tmpproduct->cost_price, 'MU');
1860 $manufacturingcostsrc = $langs->trans("CostPrice");
1861 }
1862 if (empty($manufacturingcost)) {
1863 $manufacturingcost = price2num($tmpproduct->pmp, 'MU');
1864 $manufacturingcostsrc = $langs->trans("PMPValue");
1865 }
1866 }
1867
1868 if ($tmpproduct->type == Product::TYPE_PRODUCT || getDolGlobalString('STOCK_SUPPORTS_SERVICES')) {
1869 $preselected = (GETPOSTISSET('pricetoproduce-'.$line->id.'-'.$i) ? GETPOST('pricetoproduce-'.$line->id.'-'.$i) : ($manufacturingcost ? price($manufacturingcost) : ''));
1870 print '<td class="right"><input type="text" class="width75 right" name="pricetoproduce-'.$line->id.'-'.$i.'" value="'.$preselected.'"></td>';
1871 } else {
1872 print '<td><input type="hidden" class="width50 right" name="pricetoproduce-'.$line->id.'-'.$i.'" value="'.($manufacturingcost ? $manufacturingcost : '').'"></td>';
1873 }
1874 }
1875 // Already produced
1876 print '<td></td>';
1877 // Warehouse
1878 print '<td>';
1879 if ($tmpproduct->type == Product::TYPE_PRODUCT || getDolGlobalString('STOCK_SUPPORTS_SERVICES')) {
1880 $preselected = (GETPOSTISSET('idwarehousetoproduce-'.$line->id.'-'.$i) ? GETPOST('idwarehousetoproduce-'.$line->id.'-'.$i) : ($object->fk_warehouse > 0 ? $object->fk_warehouse : 'ifone'));
1881 print $formproduct->selectWarehouses($preselected, 'idwarehousetoproduce-'.$line->id.'-'.$i, '', 1, 0, $line->fk_product, '', 1, 0, array(), 'maxwidth200 csswarehouse_'.$line->id.'_'.$i);
1882 } else {
1883 print '<span class="opacitymedium">'.$langs->trans("NoStockChangeOnServices").'</span>';
1884 }
1885 print '</td>';
1886 // Lot
1887 if (isModEnabled('productbatch')) {
1888 print '<td>';
1889 if ($tmpproduct->status_batch) {
1890 $preselected = (GETPOSTISSET('batchtoproduce-'.$line->id.'-'.$i) ? GETPOST('batchtoproduce-'.$line->id.'-'.$i) : '');
1891 print '<input type="text" class="width75" name="batchtoproduce-'.$line->id.'-'.$i.'" value="'.$preselected.'">';
1892 }
1893 print '</td>';
1894 // Batch number in same column than the stock movement picto
1895 if ($tmpproduct->status_batch) {
1896 $type = 'batch';
1897 print '<td align="right" class="split">';
1898 print img_picto($langs->trans('AddStockLocationLine'), 'split.png', 'class="splitbutton" onClick="addDispatchLine('.$line->id.', \''.$type.'\', \'qtymissing\')"');
1899 print '</td>';
1900
1901 print '<td align="right" class="splitall">';
1902 if (($action == 'consumeorproduce' || $action == 'consumeandproduceall') && $tmpproduct->status_batch == 2) {
1903 print img_picto($langs->trans('SplitAllQuantity'), 'split.png', 'class="splitbutton splitallbutton field-error-icon" onClick="addDispatchLine('.$line->id.', \'batch\', \'alltoproduce\')"');
1904 } //
1905 print '</td>';
1906 } else {
1907 print '<td></td>';
1908
1909 print '<td></td>';
1910 }
1911 }
1912
1913 // Action delete
1914 print '<td></td>';
1915
1916 print '</tr>';
1917 }
1918 }
1919 }
1920 }
1921
1922 print '</table>';
1923 print '</div>';
1924
1925 print '</div>';
1926 print '</div>';
1927 }
1928
1929 if (in_array($action, array('consumeorproduce', 'consumeandproduceall', 'addconsumeline'))) {
1930 print "</form>\n";
1931 } ?>
1932
1933 <script type="text/javascript" language="javascript">
1934
1935 $(document).ready(function() {
1936 //Consumption : When a warehouse is selected, only the lot/serial numbers that are available in it are offered
1937 updateselectbatchbywarehouse();
1938 //Consumption : When a lot/serial number is selected and it is only available in one warehouse, the warehouse is automatically selected
1939 updateselectwarehousebybatch();
1940 });
1941
1942 function updateselectbatchbywarehouse() {
1943 $(document).on('change', "select[name*='idwarehouse']", function () {
1944 console.log("We change warehouse so we update the list of possible batch number");
1945
1946 var selectwarehouse = $(this);
1947
1948 var selectbatch_name = selectwarehouse.attr('name').replace('idwarehouse', 'batch');
1949 var selectbatch = $("datalist[id*='" + selectbatch_name + "']");
1950 var selectedbatch = selectbatch.val();
1951
1952 var product_element_name = selectwarehouse.attr('name').replace('idwarehouse', 'product');
1953
1954 $.ajax({
1955 type: "POST",
1956 url: "<?php echo DOL_URL_ROOT . '/mrp/ajax/interface.php'; ?>",
1957 data: {
1958 action: "updateselectbatchbywarehouse",
1959 permissiontoproduce: <?php echo $permissiontoproduce ?>,
1960 warehouse_id: $(this).val(),
1961 token: '<?php echo currentToken(); ?>',
1962 product_id: $("input[name='" + product_element_name + "']").val()
1963 }
1964 }).done(function (data) {
1965
1966 selectbatch.empty();
1967
1968 if (typeof data == "object") {
1969 console.log("data is already type object, no need to parse it");
1970 } else {
1971 console.log("data is type "+(typeof data));
1972 data = JSON.parse(data);
1973 }
1974
1975 selectbatch.append($('<option>', {
1976 value: '',
1977 }));
1978
1979 $.each(data, function (key, value) {
1980
1981 if(selectwarehouse.val() == -1) {
1982 var label = key + " (<?php echo $langs->trans('TotalStock') ?> : " + value + ")";
1983 } else {
1984 var label = key + " (<?php echo $langs->trans('Stock') ?> : " + value + ")";
1985 }
1986
1987 if(key === selectedbatch) {
1988 var option ='<option value="'+key+'" selected>'+ label +'</option>';
1989 } else {
1990 var option ='<option value="'+key+'">'+ label +'</option>';
1991 }
1992
1993 selectbatch.append(option);
1994 });
1995 });
1996 });
1997 }
1998
1999 function updateselectwarehousebybatch() {
2000 $(document).on('change', 'input[name*=batch]', function(){
2001 console.log("We change batch so we update the list of possible warehouses");
2002
2003 var selectbatch = $(this);
2004
2005 var selectwarehouse_name = selectbatch.attr('name').replace('batch', 'idwarehouse');
2006 var selectwarehouse = $("select[name*='" + selectwarehouse_name + "']");
2007 var selectedwarehouse = selectwarehouse.val();
2008
2009 if(selectedwarehouse != -1){
2010 return;
2011 }
2012
2013 var product_element_name = selectbatch.attr('name').replace('batch', 'product');
2014
2015 $.ajax({
2016 type: "POST",
2017 url: "<?php echo DOL_URL_ROOT . '/mrp/ajax/interface.php'; ?>",
2018 data: {
2019 action: "updateselectwarehousebybatch",
2020 permissiontoproduce: <?php echo $permissiontoproduce ?>,
2021 batch: $(this).val(),
2022 token: '<?php echo currentToken(); ?>',
2023 product_id: $("input[name='" + product_element_name + "']").val()
2024 }
2025 }).done(function (data) {
2026
2027 if (typeof data == "object") {
2028 console.log("data is already type object, no need to parse it");
2029 } else {
2030 console.log("data is type "+(typeof data));
2031 data = JSON.parse(data);
2032 }
2033
2034 if(data != 0){
2035 selectwarehouse.val(data).change();
2036 }
2037 });
2038 });
2039 }
2040
2041 </script>
2042
2043 <?php
2044}
2045
2046// End of page
2047llxFooter();
2048$db->close();
$id
Support class for third parties, contacts, members, users or resources.
Definition account.php:48
if( $user->socid > 0) if(! $user->hasRight('accounting', 'chartofaccount')) $object
Definition card.php:67
llxFooter($comment='', $zone='private', $disabledoutputofmessages=0)
Empty footer.
Definition wrapper.php:91
if(!defined('NOREQUIRESOC')) if(!defined( 'NOREQUIRETRAN')) if(!defined('NOTOKENRENEWAL')) if(!defined( 'NOREQUIREMENU')) if(!defined('NOREQUIREHTML')) if(!defined( 'NOREQUIREAJAX')) llxHeader($head='', $title='', $help_url='', $target='', $disablejs=0, $disablehead=0, $arrayofjs='', $arrayofcss='', $morequerystring='', $morecssonbody='', $replacemainareaby='', $disablenofollow=0, $disablenoindex=0)
Empty header.
Definition wrapper.php:73
$object ref
Definition info.php:90
Class for BOM.
Definition bom.class.php:42
Class of dictionary type of thirdparty (used by imports)
Class to manage warehouses.
Class to manage standard extra fields.
Class to manage generation of HTML components Only common components must be here.
Class with static methods for building HTML components related to products Only components common to ...
Class to manage building of HTML components.
Class for Mo.
Definition mo.class.php:35
Class MoLine.
Class to manage stock movements.
Class to manage predefined suppliers products.
Class to manage products or services.
const TYPE_PRODUCT
Regular product.
const TYPE_SERVICE
Service.
Class with list of lots and properties.
Class to manage projects.
Class to manage translations.
Class for Workstation.
convertDurationtoHour($duration_value, $duration_unit)
Convert duration to hour.
Definition date.lib.php:338
load_fiche_titre($title, $morehtmlright='', $picto='generic', $pictoisfullpath=0, $id='', $morecssontable='', $morehtmlcenter='')
Load a title with picto.
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='', $noduplicate=0, $attop=0)
Set event messages in dol_events session object.
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2, $allowothertags=array())
Show picto whatever it's its name (generic function)
img_warning($titlealt='default', $moreatt='', $morecss='pictowarning')
Show warning logo.
GETPOSTINT($paramname, $method=0)
Return the value of a $_GET or $_POST supervariable, converted into integer.
dol_get_fiche_head($links=array(), $active='', $title='', $notab=0, $picto='', $pictoisfullpath=0, $morehtmlright='', $morecss='', $limittoshow=0, $moretabssuffix='', $dragdropfile=0, $morecssdiv='')
Show tabs of a record.
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
dolGetButtonTitle($label, $helpText='', $iconClass='fa fa-file', $url='', $id='', $status=1, $params=array())
Function dolGetButtonTitle : this kind of buttons are used in title in list.
dol_get_fiche_end($notab=0)
Return tab footer of a card.
price($amount, $form=0, $outlangs='', $trunc=1, $rounding=-1, $forcerounding=-1, $currency_code='')
Function to format a value into an amount for visual output Function used into PDF and HTML pages.
dol_now($mode='auto')
Return date for now.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
dol_escape_js($stringtoescape, $mode=0, $noescapebackslashn=0)
Returns text escaped for inclusion into javascript code.
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs=null, $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
newToken()
Return the value of token currently saved into session with name 'newtoken'.
yn($yesno, $format=1, $color=0)
Return yes or no in current language.
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
GETPOSTFLOAT($paramname, $rounding='')
Return the value of a $_GET or $_POST supervariable, converted into float.
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
img_edit($titlealt='default', $float=0, $other='')
Show logo edit/modify fiche.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0, $cleanalsojavascript=0)
Returns text escaped for inclusion in HTML alt or title or value tags, or into values of HTML input f...
global $conf
The following vars must be defined: $type2label $form $conf, $lang, The following vars may also be de...
Definition member.php:79
moPrepareHead($object)
Prepare array of tabs for Mo.
measuringUnitString($unitid, $measuring_style='', $unitscale=null, $use_short_label=0, $outputlangs=null)
Return translation label of a unit key.
if(preg_match('/(crypted|dolcrypt):/i', $dolibarr_main_db_pass)||!empty($dolibarr_main_db_encrypted_pass)) $conf db type
Definition repair.php:158
restrictedArea(User $user, $features, $object=0, $tableandshare='', $feature2='', $dbt_keyfield='fk_soc', $dbt_select='rowid', $isdraft=0, $mode=0)
Check permissions of a user to show a page and an object.