dolibarr 23.0.3
mo_card.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2017-2020 Laurent Destailleur <eldy@users.sourceforge.net>
3 * Copyright (C) 2024 Alexandre Spangaro <alexandre@inovea-conseil.com>
4 * Copyright (C) 2024-2025 MDW <mdeweerd@users.noreply.github.com>
5 * Copyright (C) 2024-2025 Frédéric France <frederic.france@free.fr>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
19 */
20
28// Load Dolibarr environment
29require '../main.inc.php';
30
31require_once DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php';
32require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php';
33require_once DOL_DOCUMENT_ROOT.'/core/class/html.formprojet.class.php';
34require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
35require_once DOL_DOCUMENT_ROOT.'/mrp/class/mo.class.php';
36require_once DOL_DOCUMENT_ROOT.'/mrp/lib/mrp_mo.lib.php';
37require_once DOL_DOCUMENT_ROOT.'/bom/class/bom.class.php';
38require_once DOL_DOCUMENT_ROOT.'/bom/lib/bom.lib.php';
39
40if (isModEnabled('workstation')) {
41 require_once DOL_DOCUMENT_ROOT.'/workstation/class/workstation.class.php';
42}
43
44
54// Load translation files required by the page
55$langs->loadLangs(array('mrp', 'other'));
56
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$backtopageforcancel = GETPOST('backtopageforcancel', 'alpha');
67$TBomLineId = GETPOST('bomlineid', 'array:int');
68$lineid = GETPOSTINT('lineid');
69$socid = GETPOSTINT("socid");
70
71// Initialize a technical objects
72$object = new Mo($db);
73$objectbom = new BOM($db);
74
75$extrafields = new ExtraFields($db);
76$diroutputmassaction = $conf->mrp->dir_output.'/temp/massgeneration/'.$user->id;
77$hookmanager->initHooks(array('mocard', 'globalcard')); // Note that conf->hooks_modules contains array
78
79// Fetch optionals attributes and labels
80$extrafields->fetch_name_optionals_label($object->table_element);
81
82$search_array_options = $extrafields->getOptionalsFromPost($object->table_element, '', 'search_');
83
84// Initialize array of search criteria
85$search_all = GETPOST("search_all", 'alpha');
86$search = array();
87foreach ($object->fields as $key => $val) {
88 if (GETPOST('search_'.$key, 'alpha')) {
89 $search[$key] = GETPOST('search_'.$key, 'alpha');
90 }
91}
92
93if (empty($action) && empty($id) && empty($ref)) {
94 $action = 'view';
95}
96
97// Load object
98include DOL_DOCUMENT_ROOT.'/core/actions_fetchobject.inc.php'; // Must be 'include', not 'include_once'.
99
100if (GETPOSTINT('fk_bom') > 0) {
101 $objectbom->fetch(GETPOSTINT('fk_bom'));
102
103 if ($action != 'add') {
104 // We force calling parameters if we are not in the submit of creation of MO
105 $_POST['fk_product'] = $objectbom->fk_product;
106 $_POST['qty'] = $objectbom->qty;
107 $_POST['mrptype'] = $objectbom->bomtype;
108 $_POST['fk_warehouse'] = $objectbom->fk_warehouse;
109 $_POST['note_private'] = $objectbom->note_private;
110 }
111}
112
113// Security check - Protection if external user
114//if ($user->socid > 0) accessforbidden();
115//if ($user->socid > 0) $socid = $user->socid;
116$isdraft = (($object->status == $object::STATUS_DRAFT) ? 1 : 0);
117$result = restrictedArea($user, 'mrp', $object->id, 'mrp_mo', '', 'fk_soc', 'rowid', $isdraft);
118
119// Permissions
120$permissionnote = $user->hasRight('mrp', 'write'); // Used by the include of actions_setnotes.inc.php
121$permissiondellink = $user->hasRight('mrp', 'write'); // Used by the include of actions_dellink.inc.php
122$permissiontoadd = $user->hasRight('mrp', 'write'); // Used by the include of actions_addupdatedelete.inc.php and actions_lineupdown.inc.php
123$permissiontodelete = $user->hasRight('mrp', 'delete') || ($permissiontoadd && isset($object->status) && $object->status == $object::STATUS_DRAFT);
124$upload_dir = $conf->mrp->multidir_output[isset($object->entity) ? $object->entity : 1];
125
126
127/*
128 * Actions
129 */
130
131$parameters = array();
132$reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
133if ($reshook < 0) {
134 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
135}
136
137if (empty($reshook)) {
138 $error = 0;
139
140 $backurlforlist = dol_buildpath('/mrp/mo_list.php', 1);
141
142 $object->oldQty = (float) $object->qty;
143
144 if (empty($backtopage) || ($cancel && empty($id))) {
145 if (empty($backtopage) || ($cancel && strpos($backtopage, '__ID__'))) {
146 if (empty($id) && (($action != 'add' && $action != 'create') || $cancel)) {
147 $backtopage = $backurlforlist;
148 } else {
149 $backtopage = DOL_URL_ROOT.'/mrp/mo_card.php?id='.($id > 0 ? $id : '__ID__');
150 }
151 }
152 }
153 if ($cancel && !empty($backtopageforcancel)) {
154 $backtopage = $backtopageforcancel;
155 }
156 $triggermodname = 'MO_MODIFY'; // Name of trigger action code to execute when we modify record
157
158 // Create MO with Children
159 if ($action == 'add' && empty($id) && !empty($TBomLineId) && $permissiontoadd) {
160 $noback = 1;
161 include DOL_DOCUMENT_ROOT.'/core/actions_addupdatedelete.inc.php';
162
163 $mo_parent = $object;
164
165 $moline = new MoLine($db);
166 $objectbomchildline = new BOMLine($db);
167
168 foreach ($TBomLineId as $id_bom_line) {
169 $object = new Mo($db); // modified by the actions_addupdatedelete.inc.php
170
171 $objectbomchildline->fetch($id_bom_line);
172
173 $TMoLines = $moline->fetchAll('DESC', 'rowid', 1, 0, array('origin_id' => $id_bom_line));
174
175 foreach ($TMoLines as $tmpmoline) {
176 $_POST['fk_bom'] = $objectbomchildline->fk_bom_child;
177 $_POST['fk_parent_line'] = $tmpmoline->id;
178 $_POST['qty'] = $tmpmoline->qty;
179 $_POST['fk_product'] = $tmpmoline->fk_product;
180 }
181
182 include DOL_DOCUMENT_ROOT.'/core/actions_addupdatedelete.inc.php';
183
184 $res = $object->add_object_linked('mo', $mo_parent->id);
185 }
186
187 header("Location: ".dol_buildpath('/mrp/mo_card.php?id='.((int) $mo_parent->id), 1));
188 exit;
189 } elseif ($action == 'confirm_cancel' && $confirm == 'yes' && !empty($permissiontoadd)) {
190 $also_cancel_consumed_and_produced_lines = (GETPOST('alsoCancelConsumedAndProducedLines', 'alpha') ? 1 : 0);
191 $result = $object->cancel($user, 0, (bool) $also_cancel_consumed_and_produced_lines);
192 if ($result > 0) {
193 header("Location: " . dol_buildpath('/mrp/mo_card.php?id=' . $object->id, 1));
194 exit;
195 } else {
196 $action = '';
197 setEventMessages($object->error, $object->errors, 'errors');
198 }
199 } elseif ($action == 'confirm_delete' && $confirm == 'yes' && !empty($permissiontodelete)) {
200 $also_cancel_consumed_and_produced_lines = (GETPOST('alsoCancelConsumedAndProducedLines', 'alpha') ? 1 : 0);
201 $result = $object->delete($user, 0, (bool) $also_cancel_consumed_and_produced_lines);
202 if ($result > 0) {
203 header("Location: " . $backurlforlist);
204 exit;
205 } else {
206 $action = '';
207 setEventMessages($object->error, $object->errors, 'errors');
208 }
209 }
210
211 if ($action == 'confirm_delete' && !empty($permissiontodelete)) {
212 if (!($object->id > 0)) {
213 dol_print_error(null, 'Error, object must be fetched before being deleted');
214 exit;
215 }
216
217 $error = 0;
218 $deleteChilds = GETPOST('deletechilds', 'aZ');
219
220 // Start the database transaction
221 $db->begin();
222
223 if ($deleteChilds === 'on') {
224 $TMoChildren = $object->getAllMoChilds();
225
226 foreach ($TMoChildren as $id => $childObject) {
227 if ($childObject->delete($user) == -1) {
228 $error++;
229 if (!empty($childObject->errors)) {
230 setEventMessages(null, $childObject->errors, 'errors');
231 } else {
232 setEventMessages($childObject->error, null, 'errors');
233 }
234 }
235 }
236 }
237
238 if (!$error) {
239 $result = $object->delete($user);
240
241 if ($result > 0) {
242 setEventMessages("RecordDeleted", null, 'mesgs');
243
244 if ($deleteChilds === 'on') {
245 setEventMessages("MoChildsDeleted", null, 'mesgs');
246 }
247
248 if (empty($noback)) {
249 header("Location: " . $backurlforlist);
250 exit;
251 }
252 } else {
253 $error++;
254 if (!empty($object->errors)) {
255 setEventMessages(null, $object->errors, 'errors');
256 } else {
257 setEventMessages($object->error, null, 'errors');
258 }
259 }
260 }
261
262 // Commit or rollback the database transaction based on whether there was an error
263 if ($error) {
264 $db->rollback();
265 } else {
266 $db->commit();
267 }
268 }
269
270
271 // Allow editing qty while MO is still in draft status.
272 // IMPORTANT: this handler MUST run BEFORE actions_addupdatedelete.inc.php,
273 // which has a generic 'set<key>' matcher that would intercept 'setqty' and
274 // call $object->fetch() + update() without setting $object->oldQty, so
275 // Mo::updateProduction() would skip the line scaling (its condition is
276 // !empty($this->oldQty)).
277 if ($action == 'setqty' && $permissiontoadd && $object->status == Mo::STATUS_DRAFT) {
278 $newqty = GETPOSTFLOAT('qty');
279 if ($newqty > 0) {
280 $object->oldQty = (float) $object->qty;
281 $object->qty = $newqty;
282 $res = $object->update($user);
283 if ($res > 0) {
284 // Enforce invariant: the 'toproduce' line for the MO's main product
285 // must equal the MO qty. Mo::updateProduction() scales by ratio
286 // (newQty/oldQty) which can drift if the line state was already
287 // inconsistent (e.g. legacy data from before this patch). Realign
288 // the main product line, leaving sub-products and frozen lines
289 // untouched.
290 $object->fetchLines();
291 foreach ($object->lines as $line) {
292 if ($line->role === 'toproduce'
293 && (int) $line->fk_product === (int) $object->fk_product
294 && empty($line->qty_frozen)
295 && (float) $line->qty != (float) $object->qty) {
296 $line->qty = (float) $object->qty;
297 $line->update($user);
298 }
299 }
300 setEventMessages($langs->trans("RecordSaved"), null, 'mesgs');
301 } else {
302 setEventMessages($object->error, $object->errors, 'errors');
303 }
304 } else {
305 setEventMessages($langs->trans("ErrorFieldRequired", $langs->trans("Qty")), null, 'errors');
306 }
307 header("Location: ".$_SERVER["PHP_SELF"]."?id=".$object->id);
308 exit;
309 }
310
311 // Actions cancel, add, update, update_extras, confirm_validate, confirm_delete, confirm_deleteline, confirm_clone, confirm_close, confirm_setdraft, confirm_reopen
312 include DOL_DOCUMENT_ROOT.'/core/actions_addupdatedelete.inc.php';
313
314 // Actions when linking object each other
315 include DOL_DOCUMENT_ROOT.'/core/actions_dellink.inc.php';
316
317 // Actions when printing a doc from card
318 include DOL_DOCUMENT_ROOT.'/core/actions_printing.inc.php';
319
320 // Action to build doc
321 include DOL_DOCUMENT_ROOT.'/core/actions_builddoc.inc.php';
322
323 if ($action == 'set_thirdparty' && $permissiontoadd) {
324 $object->setValueFrom('fk_soc', GETPOSTINT('fk_soc'), '', null, 'date', '', $user, $triggermodname);
325 }
326 if ($action == 'classin' && $permissiontoadd) {
327 $object->setProject(GETPOSTINT('projectid'));
328 }
329
330 // Actions to send emails
331 $triggersendname = 'MO_SENTBYMAIL';
332 $autocopy = 'MAIN_MAIL_AUTOCOPY_MO_TO';
333 $trackid = 'mo'.$object->id;
334 include DOL_DOCUMENT_ROOT.'/core/actions_sendmails.inc.php';
335
336 // Action to move up and down lines of object
337 //include DOL_DOCUMENT_ROOT.'/core/actions_lineupdown.inc.php'; // Must be 'include', not 'include_once'
338
339 // Action close produced
340 if ($action == 'confirm_produced' && $confirm == 'yes' && $permissiontoadd) {
341 $result = $object->setStatut($object::STATUS_PRODUCED, 0, '', 'MRP_MO_PRODUCED');
342 if ($result >= 0) {
343 // Define output language
344 if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
345 $outputlangs = $langs;
346 $newlang = '';
347 if (getDolGlobalInt('MAIN_MULTILANGS') /* && empty($newlang) */ && GETPOST('lang_id', 'aZ09')) {
348 $newlang = GETPOST('lang_id', 'aZ09');
349 }
350 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
351 $newlang = $object->thirdparty->default_lang;
352 }
353 if (!empty($newlang)) {
354 $outputlangs = new Translate("", $conf);
355 $outputlangs->setDefaultLang($newlang);
356 }
357 $model = $object->model_pdf;
358 $ret = $object->fetch($id); // Reload to get new records
359
360 $object->generateDocument($model, $outputlangs, 0, 0, 0);
361 }
362 } else {
363 setEventMessages($object->error, $object->errors, 'errors');
364 }
365 }
366}
367
368
369
370
371/*
372 * View
373 */
374
375$form = new Form($db);
376$formfile = new FormFile($db);
377$formproject = new FormProjets($db);
378
379$title = $langs->trans('ManufacturingOrder')." - ".$langs->trans("Card");
380$help_url = 'EN:Module_Manufacturing_Orders|FR:Module_Ordres_de_Fabrication|DE:Modul_Fertigungsauftrag';
381
382llxHeader('', $title, $help_url, '', 0, 0, '', '', '', 'mod-mrp page-card');
383
384
385// Part to create
386if ($action == 'create') {
387 $titlelist = null;
388 if (GETPOSTINT('fk_bom') > 0) {
389 $titlelist = $langs->trans("ToConsume");
390 if ($objectbom->bomtype == 1) {
391 $titlelist = $langs->trans("ToObtain");
392 }
393 }
394
395 print load_fiche_titre($langs->trans("NewObject", $langs->transnoentitiesnoconv("Mo")), '', 'mrp');
396
397 print '<form method="POST" action="'.dolBuildUrl($_SERVER["PHP_SELF"]).'">';
398 print '<input type="hidden" name="token" value="'.newToken().'">';
399 print '<input type="hidden" name="action" value="add">';
400 if ($backtopage) {
401 print '<input type="hidden" name="backtopage" value="'.$backtopage.'">';
402 }
403 if ($backtopageforcancel) {
404 print '<input type="hidden" name="backtopageforcancel" value="'.$backtopageforcancel.'">';
405 }
406
407 print dol_get_fiche_head(array(), '');
408
409 print '<table class="border centpercent tableforfieldcreate">'."\n";
410
411 // Common attributes
412 include DOL_DOCUMENT_ROOT.'/core/tpl/commonfields_add.tpl.php';
413
414 // Other attributes
415 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_add.tpl.php';
416
417 print '</table>'."\n";
418
419 print dol_get_fiche_end();
420
422 <script>
423 $(document).ready(function () {
424 jQuery('#fk_bom').change(function() {
425 console.log('We change value of BOM with BOM of id '+jQuery('#fk_bom').val());
426 if (jQuery('#fk_bom').val() > 0)
427 {
428 // Redirect to page with fk_bom set
429 window.location.href = '<?php echo $_SERVER["PHP_SELF"] ?>?action=create&token=<?php echo newToken(); ?>&fk_bom='+jQuery('#fk_bom').val();
430 /*
431 $.getJSON('<?php echo DOL_URL_ROOT ?>/mrp/ajax/ajax_bom.php?action=getBoms&idbom='+jQuery('#fk_bom').val(), function(data) {
432 console.log(data);
433 if (typeof data.rowid != "undefined") {
434 console.log("New BOM loaded, we set values in form");
435 console.log(data);
436 $('#qty').val(data.qty);
437 $("#mrptype").val(data.bomtype); // We set bomtype into mrptype
438 $('#mrptype').trigger('change'); // Notify any JS components that the value changed
439 $("#fk_product").val(data.fk_product);
440 $('#fk_product').trigger('change'); // Notify any JS components that the value changed
441 $('#note_private').val(data.description);
442 $('#note_private').trigger('change'); // Notify any JS components that the value changed
443 $('#fk_warehouse').val(data.fk_warehouse);
444 $('#fk_warehouse').trigger('change'); // Notify any JS components that the value changed
445 if (typeof CKEDITOR != "undefined") {
446 if (typeof CKEDITOR.instances != "undefined") {
447 if (typeof CKEDITOR.instances.note_private != "undefined") {
448 console.log(CKEDITOR.instances.note_private);
449 CKEDITOR.instances.note_private.setData(data.description);
450 }
451 }
452 }
453 } else {
454 console.log("Failed to get BOM");
455 }
456 });*/
457 }
458 else if (jQuery('#fk_bom').val() < 0) {
459 // Redirect to page with all fields defined except fk_bom set
460 console.log(jQuery('#fk_product').val());
461 window.location.href = '<?php echo $_SERVER["PHP_SELF"] ?>?action=create&token=<?php echo newToken(); ?>&qty='+jQuery('#qty').val()+'&mrptype='+jQuery('#mrptype').val()+'&fk_product='+jQuery('#fk_product').val()+'&label='+jQuery('#label').val()+'&fk_project='+jQuery('#fk_project').val()+'&fk_warehouse='+jQuery('#fk_warehouse').val();
462 /*
463 $('#qty').val('');
464 $("#fk_product").val('');
465 $('#fk_product').trigger('change'); // Notify any JS components that the value changed
466 $('#note_private').val('');
467 $('#note_private').trigger('change'); // Notify any JS components that the value changed
468 $('#fk_warehouse').val('');
469 $('#fk_warehouse').trigger('change'); // Notify any JS components that the value changed
470 */
471 }
472 });
473
474 //jQuery('#fk_bom').trigger('change');
475 })
476 </script>
477 <?php
478
479 print $form->buttonsSaveCancel("Create");
480
481 if ($objectbom->id > 0) {
482 print load_fiche_titre((string) $titlelist);
483
484 print '<!-- list of product/services to consume -->'."\n";
485 print '<div class="div-table-responsive-no-min">';
486 print '<table class="noborder centpercent">';
487
488 $arrayOfMoLines = array();
489 foreach ($objectbom->lines as $key => $val) {
490 $moLine = new MoLine($db);
491 $moLine->id = $objectbom->lines[$key]->id;
492 $moLine->position = $objectbom->lines[$key]->position;
493 $moLine->fk_product = $objectbom->lines[$key]->fk_product;
494 $moLine->fk_unit = $objectbom->lines[$key]->fk_unit;
495 $moLine->qty = $objectbom->lines[$key]->qty;
496 $moLine->qty_frozen = $objectbom->lines[$key]->qty_frozen;
497 $moLine->disable_stock_change = $objectbom->lines[$key]->disable_stock_change;
498 $moLine->fk_bom_child = $objectbom->lines[$key]->fk_bom_child;
499
500 $arrayOfMoLines[] = $moLine;
501 }
502 $object->lines = $arrayOfMoLines;
503 $object->mrptype = $objectbom->bomtype;
504 $object->bom = $objectbom;
505
506 $object->printOriginLinesList('', array());
507
508 print '</table>';
509 print '</div>';
510 }
511
512 print '</form>';
513}
514
515// Part to edit record
516if (($id || $ref) && $action == 'edit') {
517 print load_fiche_titre($langs->trans("ManufacturingOrder"), '', 'mrp');
518
519 print '<form method="POST" action="'.dolBuildUrl($_SERVER["PHP_SELF"]).'">';
520 print '<input type="hidden" name="token" value="'.newToken().'">';
521 print '<input type="hidden" name="action" value="update">';
522 print '<input type="hidden" name="id" value="'.$object->id.'">';
523 if ($backtopage) {
524 print '<input type="hidden" name="backtopage" value="'.$backtopage.'">';
525 }
526 if ($backtopageforcancel) {
527 print '<input type="hidden" name="backtopageforcancel" value="'.$backtopageforcancel.'">';
528 }
529
530 print dol_get_fiche_head();
531
532 $object->fields['fk_bom']['disabled'] = 1;
533
534 print '<table class="border centpercent tableforfieldedit">'."\n";
535
536 // Common attributes
537 include DOL_DOCUMENT_ROOT.'/core/tpl/commonfields_edit.tpl.php';
538
539 // Other attributes
540 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_edit.tpl.php';
541
542 print '</table>';
543
544 print dol_get_fiche_end();
545
546 print $form->buttonsSaveCancel();
547
548 print '</form>';
549}
550
551// Part to show record
552if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'create'))) {
553 $res = $object->fetch_thirdparty();
554
555 $head = moPrepareHead($object);
556
557 print dol_get_fiche_head($head, 'card', $langs->trans("ManufacturingOrder"), -1, $object->picto);
558
559 $formconfirm = '';
560
561 // Confirmation to delete
562 if ($action == 'delete') {
563 $numberofmochilds = count($object->getAllMoChilds());
564
565 if ($numberofmochilds > 0) {
566 $label = $langs->trans("DeleteMoChild", '('.strval($numberofmochilds).')');
567 } else {
568 $label = $langs->trans("DeleteMoChild");
569 }
570
571 $formquestion = array(
572 array('type' => 'checkbox', 'name' => 'deletechilds', 'label' => $label, 'value' => 0),
573 array(
574 'label' => $langs->trans('MoCancelConsumedAndProducedLines'),
575 'name' => 'alsoCancelConsumedAndProducedLines',
576 'type' => 'checkbox',
577 'value' => !getDolGlobalString('MO_ALSO_CANCEL_CONSUMED_AND_PRODUCED_LINES_BY_DEFAULT') ? 0 : 1
578 )
579 );
580 $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('DeleteMo'), $langs->trans('ConfirmDeleteMo'), 'confirm_delete', $formquestion, 0, 1);
581 }
582 // Confirmation to delete line
583 if ($action == 'deleteline') {
584 $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id.'&lineid='.$lineid, $langs->trans('DeleteLine'), $langs->trans('ConfirmDeleteLine'), 'confirm_deleteline', '', 0, 1);
585 }
586
587 // Reload BOM to consume and produce
588 if ($action == 'reload') {
589 $object->createProduction($user, 0);
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 = (string) $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' => 0
639 ),
640 );
641 $formconfirm = $form->formconfirm(dolBuildUrl($_SERVER["PHP_SELF"], ['id' => $object->id]), $langs->trans('CancelMo'), $langs->trans('ConfirmCancelMo'), 'confirm_cancel', $formquestion, 0, 1);
642 }
643
644 // Clone confirmation
645 if ($action == 'clone') {
646 // Create an array for form
647 $formquestion = array();
648 $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('ToClone'), $langs->trans('ConfirmCloneMo', $object->ref), 'confirm_clone', $formquestion, 'yes', 1);
649 }
650
651 // Call Hook formConfirm
652 $parameters = array('formConfirm' => $formconfirm, 'lineid' => $lineid);
653 $reshook = $hookmanager->executeHooks('formConfirm', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
654 if (empty($reshook)) {
655 $formconfirm .= $hookmanager->resPrint;
656 } elseif ($reshook > 0) {
657 $formconfirm = $hookmanager->resPrint;
658 }
659
660 // Print form confirm
661 print $formconfirm;
662
663
664 // Object card
665 // ------------------------------------------------------------
666 $linkback = '<a href="'.dol_buildpath('/mrp/mo_list.php', 1).'?restore_lastsearch_values=1'.(!empty($socid) ? '&socid='.$socid : '').'">'.$langs->trans("BackToList").'</a>';
667
668 $morehtmlref = '<div class="refidno">';
669 /*
670 // Ref bis
671 $morehtmlref.=$form->editfieldkey("RefBis", 'ref_client', $object->ref_client, $object, $user->rights->mrp->creer, 'string', '', 0, 1);
672 $morehtmlref.=$form->editfieldval("RefBis", 'ref_client', $object->ref_client, $object, $user->rights->mrp->creer, 'string', '', null, null, '', 1);*/
673 // Thirdparty
674 if (is_object($object->thirdparty)) {
675 $morehtmlref .= $object->thirdparty->getNomUrl(1, 'customer');
676 if (!getDolGlobalString('MAIN_DISABLE_OTHER_LINK') && $object->thirdparty->id > 0) {
677 $morehtmlref .= ' (<a href="'.DOL_URL_ROOT.'/commande/list.php?socid='.$object->thirdparty->id.'&search_societe='.urlencode($object->thirdparty->name).'">'.$langs->trans("OtherOrders").'</a>)';
678 }
679 }
680 // Project
681 if (isModEnabled('project')) {
682 $langs->load("projects");
683 if (is_object($object->thirdparty)) {
684 $morehtmlref .= '<br>';
685 }
686 if ($permissiontoadd) {
687 $morehtmlref .= img_picto($langs->trans("Project"), 'project', 'class="pictofixedwidth"');
688 if ($action != 'classify') {
689 $morehtmlref .= '<a class="editfielda" href="'.dolBuildUrl($_SERVER['PHP_SELF'], ['action' => 'classify', 'id' => $object->id], true).'">'.img_edit($langs->transnoentitiesnoconv('SetProject')).'</a> ';
690 }
691 $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');
692 } else {
693 if (!empty($object->fk_project)) {
694 $proj = new Project($db);
695 $proj->fetch($object->fk_project);
696 $morehtmlref .= $proj->getNomUrl(1);
697 if ($proj->title) {
698 $morehtmlref .= '<span class="opacitymedium"> - '.dol_escape_htmltag($proj->title).'</span>';
699 }
700 }
701 }
702 }
703 $morehtmlref .= '</div>';
704
705
706 dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref);
707
708
709 print '<div class="fichecenter">';
710 print '<div class="fichehalfleft">';
711 print '<div class="underbanner clearboth"></div>';
712 print '<table class="border centpercent tableforfield">'."\n";
713
714 //Mo Parent
715 $mo_parent = $object->getMoParent();
716 if (is_object($mo_parent)) {
717 print '<tr class="field_fk_mo_parent">';
718 print '<td class="titlefield fieldname_fk_mo_parent">' . $langs->trans('ParentMo') . '</td>';
719 print '<td class="valuefield fieldname_fk_mo_parent">' .$mo_parent->getNomUrl(1).'</td>';
720 print '</tr>';
721 }
722
723 // Common attributes
724 $keyforbreak = 'fk_warehouse';
725 unset($object->fields['fk_project']);
726 unset($object->fields['fk_soc']);
727 // Allow inline edit of qty while MO is in draft status.
728 // Note: editfieldval() does not handle type 'real' (no <input> rendered, only
729 // Save/Cancel buttons appear). So we override the type to 'numeric' only when
730 // the user has actually clicked the edit pencil (action=editqty). This keeps
731 // the read-mode rendering (price() format) untouched.
732 if ($object->status == Mo::STATUS_DRAFT && $permissiontoadd && isset($object->fields['qty'])) {
733 $object->fields['qty']['alwayseditable'] = 1;
734 if ($action == 'editqty') {
735 $object->fields['qty']['type'] = 'numeric';
736 }
737 }
738
739 include DOL_DOCUMENT_ROOT.'/core/tpl/commonfields_view.tpl.php';
740
741 // Other attributes
742 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_view.tpl.php';
743
744 print '</table>';
745 print '</div>';
746 print '</div>';
747
748 print '<div class="clearboth"></div>';
749
750 print dol_get_fiche_end();
751
752
753 /*
754 * Lines
755 */
756
757 if (!empty($object->table_element_line)) {
758 // Show object lines
759 //$result = $object->getLinesArray();
760 $object->fetchLines();
761
762 print ' <form name="addproduct" id="addproduct" action="'.$_SERVER["PHP_SELF"].'?id='.$object->id.(($action != 'editline') ? '' : '#line_'.GETPOSTINT('lineid')).'" method="POST">
763 <input type="hidden" name="token" value="' . newToken().'">
764 <input type="hidden" name="action" value="' . (($action != 'editline') ? 'addline' : 'updateline').'">
765 <input type="hidden" name="mode" value="">
766 <input type="hidden" name="page_y" value="">
767 <input type="hidden" name="id" value="' . $object->id.'">
768 ';
769
770 /*if (!empty($conf->use_javascript_ajax) && $object->status == 0) {
771 include DOL_DOCUMENT_ROOT.'/core/tpl/ajaxrow.tpl.php';
772 }*/
773
774 if (!empty($object->lines)) {
775 print '<div class="div-table-responsive-no-min">';
776 print '<table id="tablelines" class="noborder noshadow" width="100%">';
777
778 print '<tr class="liste_titre">';
779 print '<td class="liste_titre">'.$langs->trans("Summary").'</td>';
780 print '<td></td>';
781 print '</tr>';
782
783 print '<tr class="oddeven">';
784 print '<td>'.$langs->trans("ProductsToConsume").'</td>';
785 print '<td>';
786 if (!empty($object->lines)) {
787 $i = 0;
788 foreach ($object->lines as $line) {
789 if ($line->role == 'toconsume') {
790 if ($i) {
791 print ', ';
792 }
793 $tmpproduct = new Product($db);
794 $tmpproduct->fetch($line->fk_product);
795 print $tmpproduct->getNomUrl(1);
796 $i++;
797 }
798 }
799 }
800 print '</td>';
801 print '</tr>';
802
803 print '<tr class="oddeven">';
804 print '<td>'.$langs->trans("ProductsToProduce").'</td>';
805 print '<td>';
806 if (!empty($object->lines)) {
807 $i = 0;
808 foreach ($object->lines as $line) {
809 if ($line->role == 'toproduce') {
810 if ($i) {
811 print ', ';
812 }
813 $tmpproduct = new Product($db);
814 $tmpproduct->fetch($line->fk_product);
815 print $tmpproduct->getNomUrl(1);
816 $i++;
817 }
818 }
819 }
820 print '</td>';
821 print '</tr>';
822
823 print '</table>';
824 print '</div>';
825 }
826
827 print "</form>\n";
828 }
829
830
831 // Buttons for actions
832
833 if ($action != 'presend' && $action != 'editline') {
834 print '<div class="tabsAction">'."\n";
835 $parameters = array();
836 $reshook = $hookmanager->executeHooks('addMoreActionsButtons', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
837 if ($reshook < 0) {
838 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
839 }
840
841 if (empty($reshook)) {
842 // Send
843 //if (empty($user->socid)) {
844 // print '<a class="butAction" href="' . $_SERVER["PHP_SELF"] . '?id=' . $object->id . '&action=presend&mode=init#formmailbeforetitle">' . $langs->trans('SendMail') . '</a>'."\n";
845 //}
846
847 // Back to draft
848 if ($object->status == $object::STATUS_VALIDATED) {
849 if ($permissiontoadd) {
850 // TODO Add test that production has not started
851 print '<a class="butAction" href="'.$_SERVER['PHP_SELF'].'?id='.$object->id.'&action=confirm_setdraft&confirm=yes&token='.newToken().'">'.$langs->trans("SetToDraft").'</a>';
852 }
853 }
854
855 // Modify
856 if ($object->status == $object::STATUS_DRAFT) {
857 if ($permissiontoadd) {
858 print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=edit&token='.newToken().'">'.$langs->trans("Modify").'</a>'."\n";
859 } else {
860 print '<a class="butActionRefused classfortooltip" href="#" title="'.dolPrintHTMLForAttribute($langs->trans("NotEnoughPermissions")).'">'.$langs->trans('Modify').'</a>'."\n";
861 }
862 }
863
864 // Reload BOM
865 if ($object->status == $object::STATUS_DRAFT && $object->fk_bom > 0) {
866 if ($permissiontoadd) {
867 print '<a class="butAction" href="'.$_SERVER['PHP_SELF'].'?id='.$object->id.'&action=reload&token='.newToken().'" title="'.dolPrintHTMLForAttribute($langs->trans("ReInitializeHelp")).'">'.$langs->trans("ReInitialize").'</a>';
868 } else {
869 print '<a class="butActionRefused classfortooltip" href="#" title="'.dolPrintHTMLForAttribute($langs->trans("ReInitializeHelp").'<br>'.$langs->trans("NotEnoughPermissions")).'">'.$langs->trans('ReInitialize').'</a>'."\n";
870 }
871 }
872
873 // Validate
874 if ($object->status == $object::STATUS_DRAFT) {
875 if ($permissiontoadd) {
876 if (empty($object->table_element_line) || (is_array($object->lines) && count($object->lines) > 0)) {
877 print '<a class="butAction" href="'.$_SERVER['PHP_SELF'].'?id='.$object->id.'&action=validate&token='.newToken().'">'.$langs->trans("Validate").'</a>';
878 } else {
879 $langs->load("errors");
880 print '<a class="butActionRefused" href="" title="'.$langs->trans("ErrorAddAtLeastOneLineFirst").'">'.$langs->trans("Validate").'</a>';
881 }
882 }
883 }
884
885 // Clone
886 if ($permissiontoadd) {
887 print dolGetButtonAction($langs->trans("ToClone"), '', 'default', $_SERVER['PHP_SELF'].'?id='.$object->id.(!empty($object->socid) ? '&socid='.$object->socid : "").'&action=clone&token='.newToken().'&object=mo', 'clone', $permissiontoadd);
888 }
889
890 // Cancel - Reopen
891 if ($permissiontoadd) {
892 if ($object->status == $object::STATUS_VALIDATED || $object->status == $object::STATUS_INPROGRESS) {
893 $arrayproduced = $object->fetchLinesLinked('produced', 0);
894 $nbProduced = 0;
895 foreach ($arrayproduced as $lineproduced) {
896 $nbProduced += $lineproduced['qty'];
897 }
898 if ($nbProduced > 0) { // If production has started, we can close it
899 print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=confirm_produced&confirm=yes&token='.newToken().'">'.$langs->trans("Close").'</a>'."\n";
900 } else {
901 print '<a class="butActionRefused" href="#" title="'.$langs->trans("GoOnTabProductionToProduceFirst", $langs->transnoentitiesnoconv("Production")).'">'.$langs->trans("Close").'</a>'."\n";
902 }
903
904 print '<a class="butActionDelete" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=cancel&token='.newToken().'">'.$langs->trans("Cancel").'</a>'."\n";
905 }
906
907 if ($object->status == $object::STATUS_PRODUCED || $object->status == $object::STATUS_CANCELED) {
908 print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=confirm_reopen&confirm=yes&token='.newToken().'">'.$langs->trans("ReOpen").'</a>'."\n";
909 }
910 }
911
912 // Delete
913 print dolGetButtonAction($langs->trans("Delete"), '', 'delete', $_SERVER["PHP_SELF"].'?id='.$object->id.'&action=delete&token='.newToken(), 'delete', $permissiontodelete);
914 }
915 print '</div>'."\n";
916 }
917
918
919 // Select mail models is same action as presend
920 if (GETPOST('modelselected')) {
921 $action = 'presend';
922 }
923
924 if ($action != 'presend') {
925 print '<div class="fichecenter"><div class="fichehalfleft">';
926 print '<a name="builddoc"></a>'; // ancre
927
928 // Documents
929 $objref = dol_sanitizeFileName($object->ref);
930 $relativepath = $objref.'/'.$objref.'.pdf';
931 $filedir = $conf->mrp->dir_output.'/'.$objref;
932 $urlsource = $_SERVER["PHP_SELF"]."?id=".$object->id;
933 $genallowed = $user->hasRight('mrp', 'read'); // If you can read, you can build the PDF to read content
934 $delallowed = $user->hasRight("mrp", "creer"); // If you can create/edit, you can remove a file on card
935 print $formfile->showdocuments('mrp:mo', $objref, $filedir, $urlsource, $genallowed, $delallowed, $object->model_pdf, 1, 0, 0, 28, 0, '', '', '', $mysoc->default_lang, '', $object);
936
937 // Show links to link elements
938 $tmparray = $form->showLinkToObjectBlock($object, array(), array('mo'), 1);
939 $linktoelem = $tmparray['linktoelem'];
940 $htmltoenteralink = $tmparray['htmltoenteralink'];
941 print $htmltoenteralink;
942
943 $somethingshown = $form->showLinkedObjectBlock($object, $linktoelem, array());
944
945
946 print '</div><div class="fichehalfright">';
947
948 $MAXEVENT = 10;
949
950 $morehtmlcenter = dolGetButtonTitle($langs->trans('SeeAll'), '', 'fa fa-bars imgforviewmode', DOL_URL_ROOT.'/mrp/mo_agenda.php?id='.$object->id);
951
952 // List of actions on element
953 include_once DOL_DOCUMENT_ROOT.'/core/class/html.formactions.class.php';
954 $formactions = new FormActions($db);
955 $somethingshown = $formactions->showactions($object, $object->element, $socid, 1, '', $MAXEVENT, '', $morehtmlcenter);
956
957 print '</div></div>';
958 }
959
960 //Select mail models is same action as presend
961 if (GETPOST('modelselected')) {
962 $action = 'presend';
963 }
964
965 // Presend form
966 $modelmail = 'mo';
967 $defaulttopic = 'InformationMessage';
968 $diroutput = $conf->mrp->dir_output;
969 $trackid = 'mo'.$object->id;
970
971 include DOL_DOCUMENT_ROOT.'/core/tpl/card_presend.tpl.php';
972}
973
974// End of page
975llxFooter();
976$db->close();
$id
Support class for third parties, contacts, members, users or resources.
Definition account.php:47
if(! $sortfield) if(! $sortorder) $object
Definition account.php:100
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
mrpCollapseBomManagement()
Manage collapse bom display.
Definition bom.lib.php:166
Class for BOM.
Definition bom.class.php:42
Class for BOMLine.
Class to manage standard extra fields.
Class to manage building of HTML components.
Class to offer components to list and upload files.
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 products or services.
Class to manage projects.
Class to manage translations.
global $mysoc
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)
GETPOSTINT($paramname, $method=0)
Return the value of a $_GET or $_POST supervariable, converted into integer.
dolBuildUrl($url, $params=[], $addtoken=false)
Return path of url.
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.
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.
dol_sanitizeFileName($str, $newstr='_', $unaccent=1, $includequotes=0, $allowdash=0)
Clean a string to use it as a file name.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
newToken()
Return the value of token currently saved into session with name 'newtoken'.
GETPOSTFLOAT($paramname, $rounding='', $option=2)
Return the value of a $_GET or $_POST supervariable, converted into float.
dolGetButtonAction($label, $text='', $actionType='default', $url='', $id='', $userRight=1, $params=array())
Function dolGetButtonAction.
dolPrintHTMLForAttribute($s, $escapeonlyhtmltags=0, $allowothertags=array())
Return a string ready to be output into an HTML attribute (alt, title, data-html, ....
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
dol_buildpath($path, $type=0, $returnemptyifnotfound=0)
Return path of url or filesystem.
dol_print_error($db=null, $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
load_fiche_titre($title, $morehtmlright='', $picto='generic', $pictoisfullpath=0, $id='', $morecssontable='', $morehtmlcenter='', $morecssonpicto='widthpictotitle')
Load a title with picto.
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
isModEnabled($module)
Is Dolibarr module enabled.
img_edit($titlealt='default', $float=0, $other='')
Show logo edit/modify fiche.
moPrepareHead($object)
Prepare array of tabs for Mo.
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.