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.'">'.$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 // Add the workstation cost for the manufacturing order cost when a workstation is set
1052 if (isModEnabled('workstation') && $line->fk_default_workstation > 0) {
1053 $workstation = new Workstation($db);
1054 $workstation->fetch($line->fk_default_workstation);
1055 $linecost = price2num($qtyhourforline * ($workstation->thm_operator_estimated + $workstation->thm_machine_estimated) / $object->qty, 'MT'); //if global const MRP_SHOW_COST_FOR_CONSUMPTION is used to show price for each line
1056 $bomcostupdated += price2num($qtyhourforline * ($workstation->thm_operator_estimated + $workstation->thm_machine_estimated) / $object->qty, 'MU');
1057 } elseif ($qtyhourservice && $qtyhourforline) {
1058 $linecost = price2num(($qtyhourforline / $qtyhourservice * $costprice) / $object->qty, 'MT'); // price for line for all quantities
1059 $bomcostupdated += price2num(($qtyhourforline / $qtyhourservice * $costprice) / $object->qty, 'MU'); // same but with full accuracy
1060 } else {
1061 $linecost = price2num(($line->qty * $costprice) / $object->qty, 'MT'); // price for line for all quantities
1062 $bomcostupdated += price2num(($line->qty * $costprice) / $object->qty, 'MU'); // same but with full accuracy
1063 }
1064 } else {
1065 $linecost = price2num(($line->qty * $costprice) / $object->qty, 'MT'); // price for line for all quantities
1066 $bomcostupdated += price2num(($line->qty * $costprice) / $object->qty, 'MU'); // same but with full accuracy
1067 }
1068 }
1069
1070 $bomcostupdated = price2num($bomcostupdated, 'MU');
1071 $arrayoflines = $object->fetchLinesLinked('consumed', $line->id);
1072 $alreadyconsumed = 0;
1073 foreach ($arrayoflines as $line2) {
1074 $alreadyconsumed += $line2['qty'];
1075 }
1076
1077 if ($action == 'editline' && $lineid == $line->id) {
1078 $linecost = price2num($tmpproduct->pmp, 'MT');
1079
1080 $arrayoflines = $object->fetchLinesLinked('consumed', $line->id);
1081 $alreadyconsumed = 0;
1082 if (is_array($arrayoflines) && !empty($arrayoflines)) {
1083 foreach ($arrayoflines as $line2) {
1084 $alreadyconsumed += $line2['qty'];
1085 }
1086 }
1087 $suffix = '_' . $line->id;
1088 print '<!-- Line to dispatch ' . $suffix . ' (line edited) -->' . "\n";
1089 // hidden fields for js function
1090 print '<input id="qty_ordered' . $suffix . '" type="hidden" value="' . $line->qty . '">';
1091 // Duration - Time spent
1092 print '<input id="qty_dispatched' . $suffix . '" type="hidden" value="' . $alreadyconsumed . '">';
1093 print '<tr>';
1094 print '<input name="lineid" type="hidden" value="' . $line->id . '">';
1095
1096 // Product
1097 print '<td>' . $tmpproduct->getNomUrl(1);
1098 print '<br><div class="opacitymedium small tdoverflowmax150" title="' . dol_escape_htmltag($tmpproduct->label) . '">' . $tmpproduct->label . '</span>';
1099 print '</td>';
1100
1101 // Qty
1102 print '<td class="right nowraponall">';
1103 print '<input class="width40 right" name="qty_lineProduce" value="'. $line->qty.'">';
1104 print '</td>';
1105
1106 // Unit
1107 print '<td class="right nowraponall">';
1108 $useunit = (($tmpproduct->type == Product::TYPE_PRODUCT && getDolGlobalInt('PRODUCT_USE_UNITS')) || (($tmpproduct->type == Product::TYPE_SERVICE) && ($line->fk_unit)));
1109 if ($useunit) {
1110 print measuringUnitString($line->fk_unit, '', null, 2);
1111 }
1112 print '</td>';
1113
1114 // Cost price
1115 if ($permissiontoupdatecost && getDolGlobalString('MRP_SHOW_COST_FOR_CONSUMPTION')) {
1116 print '<td></td>';
1117 }
1118
1119 // Qty consumed
1120 print '<td class="right">';
1121 print ' ' . price2num($alreadyconsumed, 'MS');
1122 print '</td>';
1123
1124 // Warehouse / Workstation
1125 print '<td>';
1126 if ($tmpproduct->type == Product::TYPE_PRODUCT) {
1127 print $formproduct->selectWarehouses($line->fk_warehouse, 'warehouse_lineProduce', 'warehouseopen', 1);
1128 } elseif (isModEnabled('workstation')) {
1129 print $formproduct->selectWorkstations($line->fk_default_workstation, 'workstation_lineProduce', 1);
1130 }
1131 print '</td>';
1132
1133 // Stock
1134 if (isModEnabled('stock')) {
1135 print '<td class="nowraponall right">';
1136 if ($tmpproduct->isStockManaged()) {
1137 if ($tmpproduct->stock_reel < ($line->qty - $alreadyconsumed)) {
1138 print img_warning($langs->trans('StockTooLow')).' ';
1139 }
1140 print '<span class="left">'. $tmpproduct->stock_reel .' </span>';
1141 }
1142 print '</td>';
1143 }
1144
1145 // Lot - serial
1146 if (isModEnabled('productbatch')) {
1147 print '<td></td>';
1148 }
1149 // Split + SplitAll + Edit line + Delete
1150 print '<td colspan="'.(3 + ($object->status == Mo::STATUS_DRAFT ? 1 : 0) + ($permissiontodelete ? 1 : 0)).'">';
1151 print '<input type="submit" class="button buttongen button-add small nominwidth" name="save" value="' . $langs->trans("Save") . '">';
1152 print '<input type="submit" class="button buttongen button-cancel small nominwidth" name="cancel" value="' . $langs->trans("Cancel") . '">';
1153 print '</td>';
1154
1155 print '</tr>';
1156
1157 // Extrafields Line
1158 if (!empty($extrafields)) {
1159 $line->fetch_optionals();
1160 $temps = $line->showOptionals($extrafields, 'edit', array(), '', '', '1', 'line');
1161 if (!empty($temps)) {
1162 $colspan = 10;
1163 print '<tr><td colspan="'.$colspan.'"><div style="padding-top: 20px" id="extrafield_lines_area_edit" name="extrafield_lines_area_edit">';
1164 print $temps;
1165 print '</div></td></tr>';
1166 }
1167 }
1168 } else {
1169 $suffix = '_' . $line->id;
1170 print '<!-- Line to dispatch ' . $suffix . ' -->' . "\n";
1171 // hidden fields for js function
1172 print '<input id="qty_ordered' . $suffix . '" type="hidden" value="' . $line->qty . '">';
1173 print '<input id="qty_dispatched' . $suffix . '" type="hidden" value="' . $alreadyconsumed . '">';
1174
1175 print '<tr data-line-id="' . $line->id . '">';
1176
1177 // Product
1178 print '<td>' . $tmpproduct->getNomUrl(1);
1179 print '<br><div class="opacitymedium small tdoverflowmax150" title="' . dol_escape_htmltag($tmpproduct->label) . '">' . $tmpproduct->label . '</div>';
1180 print '</td>';
1181
1182 // Qty
1183 print '<td class="right nowraponall">';
1184 $help = '';
1185 if ($line->qty_frozen) {
1186 $help = ($help ? '<br>' : '') . '<strong>' . $langs->trans("QuantityFrozen") . '</strong>: ' . yn(1) . ' (' . $langs->trans("QuantityConsumedInvariable") . ')';
1187 print $form->textwithpicto('', $help, -1, 'lock') . ' ';
1188 }
1189 if ($line->disable_stock_change) {
1190 $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")) . ')';
1191 print $form->textwithpicto('', $help, -1, 'help') . ' ';
1192 }
1193 print price2num($line->qty, 'MS');
1194 print '</td>';
1195
1196 // Unit
1197 print '<td class="right nowraponall">';
1198 $useunit = (($tmpproduct->type == Product::TYPE_PRODUCT && getDolGlobalInt('PRODUCT_USE_UNITS')) || (($tmpproduct->type == Product::TYPE_SERVICE) && ($line->fk_unit)));
1199 if ($useunit) {
1200 print measuringUnitString($line->fk_unit, '', null, 2);
1201 }
1202 print '</td>';
1203
1204 // Cost price
1205 if ($permissiontoupdatecost && getDolGlobalString('MRP_SHOW_COST_FOR_CONSUMPTION')) {
1206 print '<td class="right nowraponall">';
1207 print price($linecost);
1208 print '</td>';
1209 }
1210
1211 // Already consumed
1212 print '<td class="right">';
1213 if ($alreadyconsumed) {
1214 print '<script>';
1215 print 'jQuery(document).ready(function() {
1216 jQuery("#expandtoproduce' . $line->id . '").click(function() {
1217 console.log("Expand mrp_production line ' . $line->id . '");
1218 jQuery(".expanddetail' . $line->id . '").toggle();';
1219 if ($nblinetoconsume == $nblinetoconsumecursor) { // If it is the last line
1220 print 'if (jQuery("#tablelines").hasClass("nobottom")) { jQuery("#tablelines").removeClass("nobottom"); } else { jQuery("#tablelines").addClass("nobottom"); }';
1221 }
1222 print '
1223 });
1224 });';
1225 print '</script>';
1226 if (empty($conf->use_javascript_ajax)) {
1227 print '<a href="' . $_SERVER["PHP_SELF"] . '?collapse=' . $collapse . ',' . $line->id . '">';
1228 }
1229 print img_picto($langs->trans("ShowDetails"), "chevron-down", 'id="expandtoproduce' . $line->id . '"');
1230 if (empty($conf->use_javascript_ajax)) {
1231 print '</a>';
1232 }
1233 } else {
1234 if ($nblinetoconsume == $nblinetoconsumecursor) { // If it is the last line
1235 print '<script>jQuery("#tablelines").removeClass("nobottom");</script>';
1236 }
1237 }
1238 print ' ' . price2num($alreadyconsumed, 'MS');
1239 print '</td>';
1240
1241 // Warehouse and/or workstation
1242 print '<td class="tdoverflowmax100">';
1243 if ($tmpproduct->isStockManaged()) {
1244 // When STOCK_CONSUMPTION_FROM_MANUFACTURING_WAREHOUSE is set, we always use the warehouse of the MO, the same than production.
1245 if (getDolGlobalString('STOCK_CONSUMPTION_FROM_MANUFACTURING_WAREHOUSE') && $tmpwarehouse->id > 0) {
1246 print img_picto('', $tmpwarehouse->picto) . " " . $tmpwarehouse->label;
1247 } else {
1248 if ($line->fk_warehouse > 0) {
1249 $warehouseline = new Entrepot($db);
1250 $warehouseline->fetch($line->fk_warehouse);
1251 print $warehouseline->getNomUrl(1);
1252 }
1253 }
1254 }
1255 if (isModEnabled('workstation') && $line->fk_default_workstation > 0) {
1256 $tmpworkstation = new Workstation($db);
1257 $tmpworkstation->fetch($line->fk_default_workstation);
1258 print $tmpworkstation->getNomUrl(1);
1259 }
1260 print '</td>';
1261
1262 // Stock
1263 if (isModEnabled('stock')) {
1264 print '<td class="nowraponall right">';
1265 if (!getDolGlobalString('STOCK_SUPPORTS_SERVICES') && $tmpproduct->type != Product::TYPE_SERVICE) {
1266 if (!$line->disable_stock_change && $tmpproduct->stock_reel < ($line->qty - $alreadyconsumed)) {
1267 print img_warning($langs->trans('StockTooLow')) . ' ';
1268 }
1269 if (!getDolGlobalString('STOCK_CONSUMPTION_FROM_MANUFACTURING_WAREHOUSE') || empty($tmpwarehouse->id)) {
1270 print price2num($tmpproduct->stock_reel, 'MS'); // Available
1271 } else {
1272 // Print only the stock in the selected warehouse
1273 $tmpproduct->load_stock();
1274 $wh_stock = $tmpproduct->stock_warehouse[$tmpwarehouse->id];
1275 if (!empty($wh_stock)) {
1276 print price2num($wh_stock->real, 'MS');
1277 } else {
1278 print "0";
1279 }
1280 }
1281 }
1282 print '</td>';
1283 }
1284
1285 // Lot
1286 if (isModEnabled('productbatch')) {
1287 print '<td></td>';
1288 }
1289
1290 // Split
1291 print '<td></td>';
1292
1293 // Split All
1294 print '<td></td>';
1295
1296 // Action Edit line
1297 if ($object->status == Mo::STATUS_DRAFT) {
1298 $href = $_SERVER["PHP_SELF"] . '?id=' . ((int) $object->id) . '&action=editline&token=' . newToken() . '&lineid=' . ((int) $line->id);
1299 print '<td class="center">';
1300 print '<a class="reposition editfielda" href="' . $href . '">';
1301 print img_picto($langs->trans('TooltipEditAndRevertStockMovement'), 'edit');
1302 print '</a>';
1303 print '</td>';
1304 }
1305
1306 // Action delete line, if no consumption has occurred for this product
1307 if ($permissiontodelete && empty($arrayoflines)) {
1308 $href = $_SERVER["PHP_SELF"] . '?id=' . ((int) $object->id) . '&action=deleteline&token=' . newToken() . '&lineid=' . ((int) $line->id);
1309 print '<td class="center">';
1310 print '<a class="reposition" href="' . $href . '">';
1311 print img_picto($langs->trans('TooltipDeleteAndRevertStockMovement'), 'delete');
1312 print '</a>';
1313 print '</td>';
1314 }
1315
1316 print '</tr>';
1317
1318 // Extrafields Line
1319 if (!empty($extrafields)) {
1320 $line->fetch_optionals();
1321 $temps = $line->showOptionals($extrafields, 'view', array(), '', '', '1', 'line');
1322 if (!empty($temps)) {
1323 $colspan = 10;
1324 print '<tr><td colspan="'.$colspan.'"><div id="extrafield_lines_area_'.$line->id.'" name="extrafield_lines_area_'.$line->id.'">';
1325 print $temps;
1326 print '</div></td></tr>';
1327 }
1328 }
1329 }
1330
1331 // Show detailed of already consumed with js code to collapse
1332 foreach ($arrayoflines as $line2) {
1333 print '<tr class="expanddetail'.$line->id.' hideobject opacitylow">';
1334
1335 // Date
1336 print '<td>';
1337 $tmpstockmovement->id = $line2['fk_stock_movement'];
1338 print '<a href="'.DOL_URL_ROOT.'/product/stock/movement_list.php?search_ref='.$tmpstockmovement->id.'">'.img_picto($langs->trans("StockMovement"), 'movement', 'class="paddingright"').'</a>';
1339 print dol_print_date($line2['date'], 'dayhour', 'tzuserrel');
1340 print '</td>';
1341
1342 // Qty
1343 print '<td></td>';
1344
1345 // Unit
1346 print '<td></td>';
1347
1348 // Cost price
1349 if ($permissiontoupdatecost && getDolGlobalString('MRP_SHOW_COST_FOR_CONSUMPTION')) {
1350 print '<td></td>';
1351 }
1352
1353 //Already consumed
1354 print '<td class="right">'.$line2['qty'].'</td>';
1355
1356 // Warehouse
1357 print '<td class="tdoverflowmax150">';
1358 if ($line2['fk_warehouse'] > 0) {
1359 $result = $tmpwarehouse->fetch($line2['fk_warehouse']);
1360 if ($result > 0) {
1361 print $tmpwarehouse->getNomUrl(1);
1362 }
1363 }
1364 print '</td>';
1365
1366 // Stock
1367 if (isModEnabled('stock')) {
1368 print '<td></td>';
1369 }
1370
1371 // Lot Batch
1372 if (isModEnabled('productbatch')) {
1373 print '<td>';
1374 if ($line2['batch'] != '') {
1375 $tmpbatch->fetch(0, $line2['fk_product'], $line2['batch']);
1376 print $tmpbatch->getNomUrl(1);
1377 }
1378 print '</td>';
1379 }
1380
1381 // Split
1382 print '<td></td>';
1383
1384 // Split All
1385 print '<td></td>';
1386
1387 // Action Edit line
1388 if ($object->status == Mo::STATUS_DRAFT) {
1389 $href = $_SERVER["PHP_SELF"] . '?id=' . ((int) $object->id) . '&action=editline&token=' . newToken() . '&lineid=' . ((int) $line2['rowid']);
1390 print '<td class="center">';
1391 print '<a class="reposition" href="' . $href . '">';
1392 print img_picto($langs->trans('TooltipEditAndRevertStockMovement'), 'edit');
1393 print '</a>';
1394 print '</td>';
1395 }
1396
1397 // Action delete line
1398 if ($permissiontodelete) {
1399 $href = $_SERVER["PHP_SELF"].'?id='.((int) $object->id).'&action=deleteline&token='.newToken().'&lineid='.((int) $line2['rowid']).'&fk_movement='.((int) $line2['fk_stock_movement']);
1400 print '<td class="center">';
1401 print '<a class="reposition" href="'.$href.'">';
1402 print img_picto($langs->trans('TooltipDeleteAndRevertStockMovement'), 'delete');
1403 print '</a>';
1404 print '</td>';
1405 }
1406
1407 print '</tr>';
1408 }
1409
1410 if (in_array($action, array('consumeorproduce', 'consumeandproduceall'))) {
1411 $i = 1;
1412 print '<!-- Enter line to consume -->'."\n";
1413 $maxQty = 1;
1414 print '<tr data-max-qty="'.$maxQty.'" name="batch_'.$line->id.'_'.$i.'">';
1415 // Ref
1416 print '<td><span class="opacitymedium">'.$langs->trans("ToConsume").'</span></td>';
1417 $preselected = (GETPOSTISSET('qty-'.$line->id.'-'.$i) ? GETPOST('qty-'.$line->id.'-'.$i) : max(0, $line->qty - $alreadyconsumed));
1418 if ($action == 'consumeorproduce' && !getDolGlobalString('MRP_AUTO_SET_REMAINING_QUANTITIES_TO_BE_CONSUMED') && !GETPOSTISSET('qty-'.$line->id.'-'.$i)) {
1419 $preselected = 0;
1420 }
1421
1422 $disable = '';
1423 if (getDolGlobalString('MRP_NEVER_CONSUME_MORE_THAN_EXPECTED') && ($line->qty - $alreadyconsumed) <= 0) {
1424 $disable = 'disabled';
1425 }
1426
1427 // input hidden with fk_product of line
1428 print '<input type="hidden" name="product-'.$line->id.'-'.$i.'" value="'.$line->fk_product.'">';
1429
1430 // Qty
1431 print '<td class="right">';
1432 if ((int) $tmpproduct->stockable_product > 0) {
1433 print '<input type="text" class="width50 right" id="qtytoconsume-' . $line->id . '-' . $i . '" name="qty-' . $line->id . '-' . $i . '" value="' . $preselected . '" ' . $disable . '>';
1434 } else {
1435 print '<input type="hidden" id="qtytoconsume-' . $line->id . '-' . $i . '" name="qty-' . $line->id . '-' . $i . '" value="0">';
1436 print '<span class="opacitymedium">' . $langs->trans("StockDisabled") . '</span>';
1437 }
1438 print '</td>';
1439
1440 // Unit
1441 print '<td></td>';
1442
1443 // Cost
1444 if ($permissiontoupdatecost && getDolGlobalString('MRP_SHOW_COST_FOR_CONSUMPTION')) {
1445 print '<td></td>';
1446 }
1447
1448 // Already consumed
1449 print '<td></td>';
1450
1451 // Warehouse
1452 print '<td>';
1453 if (($tmpproduct->type == Product::TYPE_PRODUCT || getDolGlobalString('STOCK_SUPPORTS_SERVICES'))
1454 && ((int) $tmpproduct->stockable_product > 0)) {
1455 if (empty($line->disable_stock_change)) {
1456 $preselected = (GETPOSTISSET('idwarehouse-'.$line->id.'-'.$i) ? GETPOST('idwarehouse-'.$line->id.'-'.$i) : ($tmpproduct->fk_default_warehouse > 0 ? $tmpproduct->fk_default_warehouse : 'ifone'));
1457 print $formproduct->selectWarehouses($preselected, 'idwarehouse-'.$line->id.'-'.$i, '', 1, 0, $line->fk_product, '', 1, 0, array(), 'maxwidth200 csswarehouse_'.$line->id.'_'.$i);
1458 } else {
1459 print '<span class="opacitymedium">'.$langs->trans("DisableStockChange").'</span>';
1460 }
1461 } else {
1462 if ((int) $tmpproduct->stockable_product > 0) {
1463 print '<span class="opacitymedium">' . $langs->trans("StockDisabled") . '</span>';
1464 } else {
1465 print '<span class="opacitymedium">' . $langs->trans("NoStockChangeOnServices") . '</span>';
1466 }
1467 }
1468 print '</td>';
1469
1470 // Stock
1471 if (isModEnabled('stock')) {
1472 print '<td></td>';
1473 }
1474
1475 // Lot / Batch
1476 if (isModEnabled('productbatch')) {
1477 print '<td class="nowraponall">';
1478 if ($tmpproduct->status_batch) {
1479 $preselected = (GETPOSTISSET('batch-'.$line->id.'-'.$i) ? GETPOST('batch-'.$line->id.'-'.$i) : '');
1480 print '<input type="text" class="width75" name="batch-'.$line->id.'-'.$i.'" value="'.$preselected.'" list="batch-'.$line->id.'-'.$i.'">';
1481 print $formproduct->selectLotDataList('batch-'.$line->id.'-'.$i, 0, $line->fk_product, 0, array());
1482 }
1483 print '</td>';
1484 }
1485
1486 // Split
1487 $type = 'batch';
1488 print '<td align="right" class="split">';
1489 print ' '.img_picto($langs->trans('AddStockLocationLine'), 'split.png', 'class="splitbutton" onClick="addDispatchLine('.((int) $line->id).', \''.dol_escape_js($type).'\', \'qtymissingconsume\')"');
1490 print '</td>';
1491
1492 // Split All
1493 print '<td align="right" class="splitall">';
1494 if (($action == 'consumeorproduce' || $action == 'consumeandproduceall') && $tmpproduct->status_batch == 2) {
1495 print img_picto($langs->trans('SplitAllQuantity'), 'split.png', 'class="splitbutton splitallbutton field-error-icon" data-max-qty="1" onClick="addDispatchLine('.$line->id.', \'batch\', \'allmissingconsume\')"');
1496 }
1497 print '</td>';
1498
1499 // Edit Line
1500 if ($object->status == Mo::STATUS_DRAFT) {
1501 print '<td></td>';
1502 }
1503
1504 // Action delete line
1505 if ($permissiontodelete) {
1506 print '<td></td>';
1507 }
1508
1509 print '</tr>';
1510 }
1511 }
1512 }
1513 }
1514
1515 print '</table>';
1516 print '</div>';
1517
1518 // default warehouse processing
1519 print '<script type="text/javascript">
1520 $(document).ready(function () {
1521 $("select[name=fk_default_warehouse]").change(function() {
1522 var fk_default_warehouse = $("option:selected", this).val();
1523 $("select[name^=idwarehouse-]").val(fk_default_warehouse).change();
1524 });
1525 });
1526 </script>';
1527
1528 if (in_array($action, array('consumeorproduce', 'consumeandproduceall')) &&
1529 getDolGlobalString('STOCK_CONSUMPTION_FROM_MANUFACTURING_WAREHOUSE')) {
1530 print '<script>$(document).ready(function () {
1531 $("#fk_default_warehouse").change();
1532 });</script>';
1533 }
1534
1535
1536 // Lines to produce
1537
1538 print '</div>';
1539 print '<div class="fichehalfright">';
1540 print '<div class="clearboth"></div>';
1541
1542 $nblinetoproduce = 0;
1543 foreach ($object->lines as $line) {
1544 if ($line->role == 'toproduce') {
1545 $nblinetoproduce++;
1546 }
1547 }
1548
1549 $newcardbutton = '';
1550 $url = $_SERVER["PHP_SELF"].'?id='.$object->id.'&action=addproduceline&token='.newToken();
1551 $permissiontoaddaproductline = $object->status != $object::STATUS_PRODUCED && $object->status != $object::STATUS_CANCELED;
1552 $parameters = array('morecss' => 'reposition');
1553 if ($action != 'consumeorproduce' && $action != 'consumeandproduceall') {
1554 if ($nblinetoproduce == 0 || $object->mrptype == 1) {
1555 $newcardbutton = dolGetButtonTitle($langs->trans('AddNewProduceLines'), '', 'fa fa-plus-circle size15x', $url, '', (int) $permissiontoaddaproductline, $parameters);
1556 }
1557 }
1558
1559 print load_fiche_titre($langs->trans('Production'), $newcardbutton, '', 0, '', '');
1560
1561 print '<div class="div-table-responsive-no-min">';
1562 print '<table id="tablelinestoproduce" class="noborder noshadow nobottom centpercent">';
1563
1564 print '<tr class="liste_titre trheight5em">';
1565 // Product
1566 print '<td>'.$langs->trans("Product").'</td>';
1567 // Qty
1568 print '<td class="right">'.$langs->trans("Qty").'</td>';
1570 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
1571 print '<td class="right">'.$langs->trans("Unit").'</td>';
1572 }
1573 // Cost price
1574 if ($permissiontoupdatecost) {
1575 if (empty($bomcostupdated)) {
1576 print '<td class="right classfortooltip" title="'.$langs->trans("AmountUsedToUpdateWAP").'">';
1577 print $langs->trans("UnitCost");
1578 print '</td>';
1579 } else {
1580 print '<td class="right classfortooltip" title="'.$langs->trans("AmountUsedToUpdateWAP").'">';
1581 print $langs->trans("ManufacturingPrice");
1582 print '</td>';
1583 }
1584 }
1585 // Already produced
1586 print '<td class="right classfortooltip" title="'.$langs->trans("QtyAlreadyProduced").'">';
1587 print $langs->trans("QtyAlreadyProducedShort");
1588 print '</td>';
1589 // Warehouse
1590 print '<td>';
1591 if ($collapse || in_array($action, array('consumeorproduce', 'consumeandproduceall'))) {
1592 print $langs->trans("Warehouse");
1593 }
1594 print '</td>';
1595
1596 // Lot
1597 if (isModEnabled('productbatch')) {
1598 print '<td>';
1599 if ($collapse || in_array($action, array('consumeorproduce', 'consumeandproduceall'))) {
1600 print $langs->trans("Batch");
1601 }
1602 print '</td>';
1603
1604 // Split
1605 print '<td></td>';
1606
1607 // Split All
1608 print '<td></td>';
1609 }
1610
1611 // Action delete
1612 if ($permissiontodelete) {
1613 print '<td></td>';
1614 }
1615
1616 print '</tr>';
1617
1618 if ($action == 'addproduceline') {
1619 print '<!-- Add line to produce -->'."\n";
1620 print '<tr class="liste_titre">';
1621
1622 // Product
1623 print '<td>';
1624 print $form->select_produits(0, 'productidtoadd', '', 0, 0, -1, 2, '', 1, array(), 0, '1', 0, 'maxwidth300');
1625 print '</td>';
1626 // Qty
1627 print '<td class="right"><input type="text" name="qtytoadd" value="1" class="width50 right"></td>';
1628 //Unit
1629 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
1630 print '<td></td>';
1631 }
1632 // Cost price
1633 if ($permissiontoupdatecost) {
1634 print '<td></td>';
1635 }
1636 // Action (cost price + already produced)
1637 print '<td colspan="2">';
1638 print '<input type="submit" class="button buttongen button-add" name="addproducelinebutton" value="'.$langs->trans("Add").'">';
1639 print '<input type="submit" class="button buttongen button-cancel" name="canceladdproducelinebutton" value="'.$langs->trans("Cancel").'">';
1640 print '</td>';
1641 // Lot - serial
1642 if (isModEnabled('productbatch')) {
1643 print '<td></td>';
1644
1645 // Split
1646 print '<td></td>';
1647
1648 // Split All
1649 print '<td></td>';
1650 }
1651 // Action delete
1652 if ($permissiontodelete) {
1653 print '<td></td>';
1654 }
1655 print '</tr>';
1656 }
1657
1658 if (!empty($object->lines)) {
1659 $nblinetoproduce = 0;
1660 foreach ($object->lines as $line) {
1661 if ($line->role == 'toproduce') {
1662 $nblinetoproduce++;
1663 }
1664 }
1665
1666 $nblinetoproducecursor = 0;
1667 foreach ($object->lines as $line) {
1668 if ($line->role == 'toproduce') {
1669 $i = 1;
1670
1671 $nblinetoproducecursor++;
1672
1673 $tmpproduct = new Product($db);
1674 $tmpproduct->fetch($line->fk_product);
1675
1676 $arrayoflines = $object->fetchLinesLinked('produced', $line->id);
1677 $alreadyproduced = 0;
1678 foreach ($arrayoflines as $line2) {
1679 $alreadyproduced += $line2['qty'];
1680 }
1681
1682 $suffix = '_'.$line->id;
1683 print '<!-- Line to dispatch '.$suffix.' (toproduce) -->'."\n";
1684 // hidden fields for js function
1685 print '<input id="qty_ordered'.$suffix.'" type="hidden" value="'.$line->qty.'">';
1686 print '<input id="qty_dispatched'.$suffix.'" type="hidden" value="'.$alreadyproduced.'">';
1687
1688 print '<tr>';
1689 // Product
1690 print '<td>'.$tmpproduct->getNomUrl(1);
1691 print '<br><span class="opacitymedium small">'.$tmpproduct->label.'</span>';
1692 print '</td>';
1693 // Qty
1694 print '<td class="right">'.$line->qty.'</td>';
1695 // Unit
1696 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
1697 print '<td class="right">'.measuringUnitString($line->fk_unit, '', null, 1).'</td>';
1698 }
1699 // Cost price
1700 if ($permissiontoupdatecost) {
1701 // Defined $manufacturingcost
1702 $manufacturingcost = 0;
1703 $manufacturingcostsrc = '';
1704 if ($object->mrptype == 0) { // If MO is a "Manufacture" type (and not "Disassemble")
1705 $manufacturingcost = $bomcostupdated;
1706 $manufacturingcostsrc = $langs->trans("CalculatedFromProductsToConsume");
1707 if (empty($manufacturingcost)) {
1708 $manufacturingcost = $bomcost;
1709 $manufacturingcostsrc = $langs->trans("ValueFromBom");
1710 }
1711 if (empty($manufacturingcost)) {
1712 $manufacturingcost = price2num($tmpproduct->cost_price, 'MU');
1713 $manufacturingcostsrc = $langs->trans("CostPrice");
1714 }
1715 if (empty($manufacturingcost)) {
1716 $manufacturingcost = price2num($tmpproduct->pmp, 'MU');
1717 $manufacturingcostsrc = $langs->trans("PMPValue");
1718 }
1719 }
1720
1721 print '<td class="right nowraponall" title="'.dol_escape_htmltag($manufacturingcostsrc).'">';
1722 if ($manufacturingcost) {
1723 print price($manufacturingcost);
1724 }
1725 print '</td>';
1726 }
1727 // Already produced
1728 print '<td class="right nowraponall">';
1729 if ($alreadyproduced) {
1730 print '<script>';
1731 print 'jQuery(document).ready(function() {
1732 jQuery("#expandtoproduce'.$line->id.'").click(function() {
1733 console.log("Expand mrp_production line '.$line->id.'");
1734 jQuery(".expanddetailtoproduce'.$line->id.'").toggle();';
1735 if ($nblinetoproduce == $nblinetoproducecursor) {
1736 print 'if (jQuery("#tablelinestoproduce").hasClass("nobottom")) { jQuery("#tablelinestoproduce").removeClass("nobottom"); } else { jQuery("#tablelinestoproduce").addClass("nobottom"); }';
1737 }
1738 print '
1739 });
1740 });';
1741 print '</script>';
1742 if (empty($conf->use_javascript_ajax)) {
1743 print '<a href="'.$_SERVER["PHP_SELF"].'?collapse='.$collapse.','.$line->id.'">';
1744 }
1745 print img_picto($langs->trans("ShowDetails"), "chevron-down", 'id="expandtoproduce'.$line->id.'"');
1746 if (empty($conf->use_javascript_ajax)) {
1747 print '</a>';
1748 }
1749 }
1750 print ' '.$alreadyproduced;
1751 print '</td>';
1752 // Warehouse
1753 print '<td>';
1754 print '</td>';
1755 // Lot
1756 if (isModEnabled('productbatch')) {
1757 print '<td></td>';
1758
1759 // Split
1760 print '<td></td>';
1761
1762 // Split All
1763 print '<td></td>';
1764 }
1765 // Delete
1766 if ($permissiontodelete) {
1767 if ($line->origin_type == 'free') {
1768 $href = $_SERVER["PHP_SELF"];
1769 $href .= '?id='.$object->id;
1770 $href .= '&action=deleteline';
1771 $href .= '&token='.newToken();
1772 $href .= '&lineid='.$line->id;
1773 print '<td class="center">';
1774 print '<a class="reposition" href="'.$href.'">';
1775 print img_picto($langs->trans('TooltipDeleteAndRevertStockMovement'), "delete");
1776 print '</a>';
1777 print '</td>';
1778 } else {
1779 print '<td></td>';
1780 }
1781 }
1782 print '</tr>';
1783
1784 // Show detailed of already consumed with js code to collapse
1785 foreach ($arrayoflines as $line2) {
1786 print '<tr class="expanddetailtoproduce'.$line->id.' hideobject opacitylow">';
1787 // Product
1788 print '<td>';
1789 $tmpstockmovement->id = $line2['fk_stock_movement'];
1790 print '<a href="'.DOL_URL_ROOT.'/product/stock/movement_list.php?search_ref='.$tmpstockmovement->id.'">'.img_picto($langs->trans("StockMovement"), 'movement', 'class="paddingright"').'</a>';
1791 print dol_print_date($line2['date'], 'dayhour', 'tzuserrel');
1792 print '</td>';
1793 // Qty
1794 print '<td></td>';
1795 // Unit
1796 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
1797 print '<td></td>';
1798 }
1799 // Cost price
1800 if ($permissiontoupdatecost) {
1801 print '<td></td>';
1802 }
1803 // Already produced
1804 print '<td class="right">'.$line2['qty'].'</td>';
1805 // Warehouse
1806 print '<td class="tdoverflowmax150">';
1807 if ($line2['fk_warehouse'] > 0) {
1808 $result = $tmpwarehouse->fetch($line2['fk_warehouse']);
1809 if ($result > 0) {
1810 print $tmpwarehouse->getNomUrl(1);
1811 }
1812 }
1813 print '</td>';
1814 // Lot
1815 if (isModEnabled('productbatch')) {
1816 print '<td>';
1817 if ($line2['batch'] != '') {
1818 $tmpbatch->fetch(0, $line2['fk_product'], $line2['batch']);
1819 print $tmpbatch->getNomUrl(1);
1820 }
1821 print '</td>';
1822
1823 // Split
1824 print '<td></td>';
1825
1826 // Split All
1827 print '<td></td>';
1828 }
1829 // Action delete
1830 if ($permissiontodelete) {
1831 print '<td></td>';
1832 }
1833 print '</tr>';
1834 }
1835
1836 if (in_array($action, array('consumeorproduce', 'consumeandproduceall'))) {
1837 print '<!-- Enter line to produce -->'."\n";
1838 $maxQty = 1;
1839 print '<tr data-max-qty="'.$maxQty.'" name="batch_'.$line->id.'_'.$i.'">';
1840 // Product
1841 print '<td><span class="opacitymedium">'.$langs->trans("ToProduce").'</span></td>';
1842 $preselected = (GETPOSTISSET('qtytoproduce-'.$line->id.'-'.$i) ? GETPOST('qtytoproduce-'.$line->id.'-'.$i) : max(0, $line->qty - $alreadyproduced));
1843 if ($action == 'consumeorproduce' && !GETPOSTISSET('qtytoproduce-'.$line->id.'-'.$i)) {
1844 $preselected = 0;
1845 }
1846 // Qty
1847 print '<td class="right"><input type="text" class="width50 right" id="qtytoproduce-'.$line->id.'-'.$i.'" name="qtytoproduce-'.$line->id.'-'.$i.'" value="'.$preselected.'"></td>';
1848 //Unit
1849 if (getDolGlobalInt('PRODUCT_USE_UNITS')) {
1850 print '<td class="right"></td>';
1851 }
1852 // Cost
1853 if ($permissiontoupdatecost) {
1854 // Defined $manufacturingcost
1855 $manufacturingcost = 0;
1856 $manufacturingcostsrc = '';
1857 if ($object->mrptype == 0) { // If MO is a "Manufacture" type (and not "Disassemble")
1858 $manufacturingcost = $bomcostupdated;
1859 $manufacturingcostsrc = $langs->trans("CalculatedFromProductsToConsume");
1860 if (empty($manufacturingcost)) {
1861 $manufacturingcost = $bomcost;
1862 $manufacturingcostsrc = $langs->trans("ValueFromBom");
1863 }
1864 if (empty($manufacturingcost)) {
1865 $manufacturingcost = price2num($tmpproduct->cost_price, 'MU');
1866 $manufacturingcostsrc = $langs->trans("CostPrice");
1867 }
1868 if (empty($manufacturingcost)) {
1869 $manufacturingcost = price2num($tmpproduct->pmp, 'MU');
1870 $manufacturingcostsrc = $langs->trans("PMPValue");
1871 }
1872 }
1873
1874 if ($tmpproduct->type == Product::TYPE_PRODUCT || getDolGlobalString('STOCK_SUPPORTS_SERVICES')) {
1875 $preselected = (GETPOSTISSET('pricetoproduce-'.$line->id.'-'.$i) ? GETPOST('pricetoproduce-'.$line->id.'-'.$i) : ($manufacturingcost ? price($manufacturingcost) : ''));
1876 print '<td class="right"><input type="text" class="width75 right" name="pricetoproduce-'.$line->id.'-'.$i.'" value="'.$preselected.'"></td>';
1877 } else {
1878 print '<td><input type="hidden" class="width50 right" name="pricetoproduce-'.$line->id.'-'.$i.'" value="'.($manufacturingcost ? $manufacturingcost : '').'"></td>';
1879 }
1880 }
1881 // Already produced
1882 print '<td></td>';
1883 // Warehouse
1884 print '<td>';
1885 if ($tmpproduct->type == Product::TYPE_PRODUCT || getDolGlobalString('STOCK_SUPPORTS_SERVICES')) {
1886 $preselected = (GETPOSTISSET('idwarehousetoproduce-'.$line->id.'-'.$i) ? GETPOST('idwarehousetoproduce-'.$line->id.'-'.$i) : ($object->fk_warehouse > 0 ? $object->fk_warehouse : 'ifone'));
1887 print $formproduct->selectWarehouses($preselected, 'idwarehousetoproduce-'.$line->id.'-'.$i, '', 1, 0, $line->fk_product, '', 1, 0, array(), 'maxwidth200 csswarehouse_'.$line->id.'_'.$i);
1888 } else {
1889 print '<span class="opacitymedium">'.$langs->trans("NoStockChangeOnServices").'</span>';
1890 }
1891 print '</td>';
1892 // Lot
1893 if (isModEnabled('productbatch')) {
1894 print '<td>';
1895 if ($tmpproduct->status_batch) {
1896 $preselected = (GETPOSTISSET('batchtoproduce-'.$line->id.'-'.$i) ? GETPOST('batchtoproduce-'.$line->id.'-'.$i) : '');
1897 print '<input type="text" class="width75" name="batchtoproduce-'.$line->id.'-'.$i.'" value="'.$preselected.'">';
1898 }
1899 print '</td>';
1900 // Batch number in same column than the stock movement picto
1901 if ($tmpproduct->status_batch) {
1902 $type = 'batch';
1903 print '<td align="right" class="split">';
1904 print img_picto($langs->trans('AddStockLocationLine'), 'split.png', 'class="splitbutton" onClick="addDispatchLine('.$line->id.', \''.$type.'\', \'qtymissing\')"');
1905 print '</td>';
1906
1907 print '<td align="right" class="splitall">';
1908 if (($action == 'consumeorproduce' || $action == 'consumeandproduceall') && $tmpproduct->status_batch == 2) {
1909 print img_picto($langs->trans('SplitAllQuantity'), 'split.png', 'class="splitbutton splitallbutton field-error-icon" onClick="addDispatchLine('.$line->id.', \'batch\', \'alltoproduce\')"');
1910 } //
1911 print '</td>';
1912 } else {
1913 print '<td></td>';
1914
1915 print '<td></td>';
1916 }
1917 }
1918
1919 // Action delete
1920 print '<td></td>';
1921
1922 print '</tr>';
1923 }
1924 }
1925 }
1926 }
1927
1928 print '</table>';
1929 print '</div>';
1930
1931 print '</div>';
1932 print '</div>';
1933 }
1934
1935 if (in_array($action, array('consumeorproduce', 'consumeandproduceall', 'addconsumeline'))) {
1936 print "</form>\n";
1937 } ?>
1938
1939 <script type="text/javascript" language="javascript">
1940
1941 $(document).ready(function() {
1942 //Consumption : When a warehouse is selected, only the lot/serial numbers that are available in it are offered
1943 updateselectbatchbywarehouse();
1944 //Consumption : When a lot/serial number is selected and it is only available in one warehouse, the warehouse is automatically selected
1945 updateselectwarehousebybatch();
1946 });
1947
1948 function updateselectbatchbywarehouse() {
1949 $(document).on('change', "select[name*='idwarehouse']", function () {
1950 console.log("We change warehouse so we update the list of possible batch number");
1951
1952 var selectwarehouse = $(this);
1953
1954 var selectbatch_name = selectwarehouse.attr('name').replace('idwarehouse', 'batch');
1955 var selectbatch = $("datalist[id*='" + selectbatch_name + "']");
1956 var selectedbatch = selectbatch.val();
1957
1958 var product_element_name = selectwarehouse.attr('name').replace('idwarehouse', 'product');
1959
1960 $.ajax({
1961 type: "POST",
1962 url: "<?php echo DOL_URL_ROOT . '/mrp/ajax/interface.php'; ?>",
1963 data: {
1964 action: "updateselectbatchbywarehouse",
1965 permissiontoproduce: <?php echo $permissiontoproduce ?>,
1966 warehouse_id: $(this).val(),
1967 token: '<?php echo currentToken(); ?>',
1968 product_id: $("input[name='" + product_element_name + "']").val()
1969 }
1970 }).done(function (data) {
1971
1972 selectbatch.empty();
1973
1974 if (typeof data == "object") {
1975 console.log("data is already type object, no need to parse it");
1976 } else {
1977 console.log("data is type "+(typeof data));
1978 data = JSON.parse(data);
1979 }
1980
1981 selectbatch.append($('<option>', {
1982 value: '',
1983 }));
1984
1985 $.each(data, function (key, value) {
1986
1987 if(selectwarehouse.val() == -1) {
1988 var label = key + " (<?php echo $langs->trans('TotalStock') ?> : " + value + ")";
1989 } else {
1990 var label = key + " (<?php echo $langs->trans('Stock') ?> : " + value + ")";
1991 }
1992
1993 if(key === selectedbatch) {
1994 var option ='<option value="'+key+'" selected>'+ label +'</option>';
1995 } else {
1996 var option ='<option value="'+key+'">'+ label +'</option>';
1997 }
1998
1999 selectbatch.append(option);
2000 });
2001 });
2002 });
2003 }
2004
2005 function updateselectwarehousebybatch() {
2006 $(document).on('change', 'input[name*=batch]', function(){
2007 console.log("We change batch so we update the list of possible warehouses");
2008
2009 var selectbatch = $(this);
2010
2011 var selectwarehouse_name = selectbatch.attr('name').replace('batch', 'idwarehouse');
2012 var selectwarehouse = $("select[name*='" + selectwarehouse_name + "']");
2013 var selectedwarehouse = selectwarehouse.val();
2014
2015 if(selectedwarehouse != -1){
2016 return;
2017 }
2018
2019 var product_element_name = selectbatch.attr('name').replace('batch', 'product');
2020
2021 $.ajax({
2022 type: "POST",
2023 url: "<?php echo DOL_URL_ROOT . '/mrp/ajax/interface.php'; ?>",
2024 data: {
2025 action: "updateselectwarehousebybatch",
2026 permissiontoproduce: <?php echo $permissiontoproduce ?>,
2027 batch: $(this).val(),
2028 token: '<?php echo currentToken(); ?>',
2029 product_id: $("input[name='" + product_element_name + "']").val()
2030 }
2031 }).done(function (data) {
2032
2033 if (typeof data == "object") {
2034 console.log("data is already type object, no need to parse it");
2035 } else {
2036 console.log("data is type "+(typeof data));
2037 data = JSON.parse(data);
2038 }
2039
2040 if(data != 0){
2041 selectwarehouse.val(data).change();
2042 }
2043 });
2044 });
2045 }
2046
2047 </script>
2048
2049 <?php
2050}
2051
2052// End of page
2053llxFooter();
2054$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.