dolibarr  17.0.4
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  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <https://www.gnu.org/licenses/>.
17  */
18 
25 // Load Dolibarr environment
26 require '../main.inc.php';
27 
28 require_once DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php';
29 require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php';
30 require_once DOL_DOCUMENT_ROOT.'/core/class/html.formprojet.class.php';
31 require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
32 require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
33 require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php';
34 require_once DOL_DOCUMENT_ROOT.'/product/stock/class/entrepot.class.php';
35 require_once DOL_DOCUMENT_ROOT.'/product/stock/class/productlot.class.php';
36 require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
37 dol_include_once('/mrp/class/mo.class.php');
38 dol_include_once('/bom/class/bom.class.php');
39 dol_include_once('/mrp/lib/mrp_mo.lib.php');
40 
41 // Load translation files required by the page
42 $langs->loadLangs(array("mrp", "stocks", "other", "product", "productbatch"));
43 
44 // Get parameters
45 $id = GETPOST('id', 'int');
46 $ref = GETPOST('ref', 'alpha');
47 $action = GETPOST('action', 'aZ09');
48 $confirm = GETPOST('confirm', 'alpha');
49 $cancel = GETPOST('cancel', 'aZ09');
50 $contextpage = GETPOST('contextpage', 'aZ') ?GETPOST('contextpage', 'aZ') : 'mocard'; // To manage different context of search
51 $backtopage = GETPOST('backtopage', 'alpha');
52 $lineid = GETPOST('lineid', 'int');
53 $fk_movement = GETPOST('fk_movement', 'int');
54 $fk_default_warehouse = GETPOST('fk_default_warehouse', 'int');
55 
56 $collapse = GETPOST('collapse', 'aZ09comma');
57 
58 // Initialize technical objects
59 $object = new Mo($db);
60 $extrafields = new ExtraFields($db);
61 $diroutputmassaction = $conf->mrp->dir_output.'/temp/massgeneration/'.$user->id;
62 $hookmanager->initHooks(array('mocard', 'globalcard')); // Note that conf->hooks_modules contains array
63 
64 // Fetch optionals attributes and labels
65 $extrafields->fetch_name_optionals_label($object->table_element);
66 
67 $search_array_options = $extrafields->getOptionalsFromPost($object->table_element, '', 'search_');
68 
69 // Initialize array of search criterias
70 $search_all = GETPOST("search_all", 'alpha');
71 $search = array();
72 foreach ($object->fields as $key => $val) {
73  if (GETPOST('search_'.$key, 'alpha')) {
74  $search[$key] = GETPOST('search_'.$key, 'alpha');
75  }
76 }
77 
78 if (empty($action) && empty($id) && empty($ref)) {
79  $action = 'view';
80 }
81 
82 // Load object
83 include DOL_DOCUMENT_ROOT.'/core/actions_fetchobject.inc.php'; // Must be include, not include_once.
84 
85 // Security check - Protection if external user
86 //if ($user->socid > 0) accessforbidden();
87 //if ($user->socid > 0) $socid = $user->socid;
88 $isdraft = (($object->status == $object::STATUS_DRAFT) ? 1 : 0);
89 $result = restrictedArea($user, 'mrp', $object->id, 'mrp_mo', '', 'fk_soc', 'rowid', $isdraft);
90 
91 $permissionnote = $user->rights->mrp->write; // Used by the include of actions_setnotes.inc.php
92 $permissiondellink = $user->rights->mrp->write; // Used by the include of actions_dellink.inc.php
93 $permissiontoadd = $user->rights->mrp->write; // Used by the include of actions_addupdatedelete.inc.php and actions_lineupdown.inc.php
94 $permissiontodelete = $user->rights->mrp->delete || ($permissiontoadd && isset($object->status) && $object->status == $object::STATUS_DRAFT);
95 $upload_dir = $conf->mrp->multidir_output[isset($object->entity) ? $object->entity : 1];
96 
97 $permissiontoproduce = $permissiontoadd;
98 $permissiontoupdatecost = $user->rights->bom->read; // User who can define cost must have knowledge of pricing
99 
100 
101 /*
102  * Actions
103  */
104 
105 $parameters = array();
106 $reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
107 if ($reshook < 0) {
108  setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
109 }
110 
111 if (empty($reshook)) {
112  $error = 0;
113 
114  $backurlforlist = dol_buildpath('/mrp/mo_list.php', 1);
115 
116  if (empty($backtopage) || ($cancel && empty($id))) {
117  //var_dump($backurlforlist);exit;
118  if (empty($id) && (($action != 'add' && $action != 'create') || $cancel)) {
119  $backtopage = $backurlforlist;
120  } else {
121  $backtopage = DOL_URL_ROOT.'/mrp/mo_production.php?id='.($id > 0 ? $id : '__ID__');
122  }
123  }
124  $triggermodname = 'MO_MODIFY'; // Name of trigger action code to execute when we modify record
125 
126  // Actions cancel, add, update, delete or clone
127  include DOL_DOCUMENT_ROOT.'/core/actions_addupdatedelete.inc.php';
128 
129  // Actions when linking object each other
130  include DOL_DOCUMENT_ROOT.'/core/actions_dellink.inc.php';
131 
132  // Actions when printing a doc from card
133  include DOL_DOCUMENT_ROOT.'/core/actions_printing.inc.php';
134 
135  // Actions to send emails
136  $triggersendname = 'MO_SENTBYMAIL';
137  $autocopy = 'MAIN_MAIL_AUTOCOPY_MO_TO';
138  $trackid = 'mo'.$object->id;
139  include DOL_DOCUMENT_ROOT.'/core/actions_sendmails.inc.php';
140 
141  // Action to move up and down lines of object
142  //include DOL_DOCUMENT_ROOT.'/core/actions_lineupdown.inc.php'; // Must be include, not include_once
143 
144  if ($action == 'set_thirdparty' && $permissiontoadd) {
145  $object->setValueFrom('fk_soc', GETPOST('fk_soc', 'int'), '', '', 'date', '', $user, $triggermodname);
146  }
147  if ($action == 'classin' && $permissiontoadd) {
148  $object->setProject(GETPOST('projectid', 'int'));
149  }
150 
151  if ($action == 'confirm_reopen' && $permissiontoadd) {
152  $result = $object->setStatut($object::STATUS_INPROGRESS, 0, '', 'MRP_REOPEN');
153  }
154 
155  if (($action == 'confirm_addconsumeline' && GETPOST('addconsumelinebutton') && $permissiontoadd)
156  || ($action == 'confirm_addproduceline' && GETPOST('addproducelinebutton') && $permissiontoadd)) {
157  $moline = new MoLine($db);
158 
159  // Line to produce
160  $moline->fk_mo = $object->id;
161  $moline->qty = GETPOST('qtytoadd', 'int'); ;
162  $moline->fk_product = GETPOST('productidtoadd', 'int');
163  if (GETPOST('addconsumelinebutton')) {
164  $moline->role = 'toconsume';
165  } else {
166  $moline->role = 'toproduce';
167  }
168  $moline->origin_type = 'free'; // free consume line
169  $moline->position = 0;
170 
171  // Is it a product or a service ?
172  $tmpproduct = new Product($db);
173  $tmpproduct->fetch($moline->fk_product);
174  $moline->disable_stock_change = ($tmpproduct->type == Product::TYPE_SERVICE ? 1 : 0);
175 
176  $resultline = $moline->create($user, false); // Never use triggers here
177  if ($resultline <= 0) {
178  $error++;
179  setEventMessages($moline->error, $molines->errors, 'errors');
180  }
181 
182  $action = '';
183  // Redirect to refresh the tab information
184  header("Location: ".$_SERVER["PHP_SELF"].'?id='.$object->id);
185  }
186 
187  if (in_array($action, array('confirm_consumeorproduce', 'confirm_consumeandproduceall')) && $permissiontoproduce) {
188  $stockmove = new MouvementStock($db);
189 
190  $labelmovement = GETPOST('inventorylabel', 'alphanohtml');
191  $codemovement = GETPOST('inventorycode', 'alphanohtml');
192 
193  $db->begin();
194  $pos = 0;
195  // Process line to consume
196  foreach ($object->lines as $line) {
197  if ($line->role == 'toconsume') {
198  $tmpproduct = new Product($db);
199  $tmpproduct->fetch($line->fk_product);
200 
201  $i = 1;
202  while (GETPOSTISSET('qty-'.$line->id.'-'.$i)) {
203  $qtytoprocess = price2num(GETPOST('qty-'.$line->id.'-'.$i));
204 
205  if ($qtytoprocess != 0) {
206  // Check warehouse is set if we should have to
207  if (GETPOSTISSET('idwarehouse-'.$line->id.'-'.$i)) { // If there is a warehouse to set
208  if (!(GETPOST('idwarehouse-'.$line->id.'-'.$i) > 0)) { // If there is no warehouse set.
209  $langs->load("errors");
210  setEventMessages($langs->trans("ErrorFieldRequiredForProduct", $langs->transnoentitiesnoconv("Warehouse"), $tmpproduct->ref), null, 'errors');
211  $error++;
212  }
213  if ($tmpproduct->status_batch && (!GETPOST('batch-'.$line->id.'-'.$i))) {
214  $langs->load("errors");
215  setEventMessages($langs->trans("ErrorFieldRequiredForProduct", $langs->transnoentitiesnoconv("Batch"), $tmpproduct->ref), null, 'errors');
216  $error++;
217  }
218  }
219 
220  $idstockmove = 0;
221  if (!$error && GETPOST('idwarehouse-'.$line->id.'-'.$i) > 0) {
222  // Record stock movement
223  $id_product_batch = 0;
224  $stockmove->setOrigin($object->element, $object->id);
225 
226  if ($qtytoprocess >= 0) {
227  $idstockmove = $stockmove->livraison($user, $line->fk_product, GETPOST('idwarehouse-'.$line->id.'-'.$i), $qtytoprocess, 0, $labelmovement, dol_now(), '', '', GETPOST('batch-'.$line->id.'-'.$i), $id_product_batch, $codemovement);
228  } else {
229  $idstockmove = $stockmove->reception($user, $line->fk_product, GETPOST('idwarehouse-'.$line->id.'-'.$i), $qtytoprocess * -1, 0, $labelmovement, dol_now(), '', '', GETPOST('batch-'.$line->id.'-'.$i), $id_product_batch, $codemovement);
230  }
231  if ($idstockmove < 0) {
232  $error++;
233  setEventMessages($stockmove->error, $stockmove->errors, 'errors');
234  }
235  }
236 
237  if (!$error) {
238  // Record consumption
239  $moline = new MoLine($db);
240  $moline->fk_mo = $object->id;
241  $moline->position = $pos;
242  $moline->fk_product = $line->fk_product;
243  $moline->fk_warehouse = GETPOST('idwarehouse-'.$line->id.'-'.$i);
244  $moline->qty = $qtytoprocess;
245  $moline->batch = GETPOST('batch-'.$line->id.'-'.$i);
246  $moline->role = 'consumed';
247  $moline->fk_mrp_production = $line->id;
248  $moline->fk_stock_movement = $idstockmove == 0 ? null : $idstockmove;
249  $moline->fk_user_creat = $user->id;
250 
251  $resultmoline = $moline->create($user);
252  if ($resultmoline <= 0) {
253  $error++;
254  setEventMessages($moline->error, $moline->errors, 'errors');
255  }
256 
257  $pos++;
258  }
259  }
260 
261  $i++;
262  }
263  }
264  }
265 
266  // Process line to produce
267  $pos = 0;
268 
269  foreach ($object->lines as $line) {
270  if ($line->role == 'toproduce') {
271  $tmpproduct = new Product($db);
272  $tmpproduct->fetch($line->fk_product);
273 
274  $i = 1;
275  while (GETPOSTISSET('qtytoproduce-'.$line->id.'-'.$i)) {
276  $qtytoprocess = price2num(GETPOST('qtytoproduce-'.$line->id.'-'.$i));
277  $pricetoprocess = GETPOST('pricetoproduce-'.$line->id.'-'.$i) ? price2num(GETPOST('pricetoproduce-'.$line->id.'-'.$i)) : 0;
278 
279  if ($qtytoprocess != 0) {
280  // Check warehouse is set if we should have to
281  if (GETPOSTISSET('idwarehousetoproduce-'.$line->id.'-'.$i)) { // If there is a warehouse to set
282  if (!(GETPOST('idwarehousetoproduce-'.$line->id.'-'.$i) > 0)) { // If there is no warehouse set.
283  $langs->load("errors");
284  setEventMessages($langs->trans("ErrorFieldRequiredForProduct", $langs->transnoentitiesnoconv("Warehouse"), $tmpproduct->ref), null, 'errors');
285  $error++;
286  }
287  if (isModEnabled('productbatch') && $tmpproduct->status_batch && (!GETPOST('batchtoproduce-'.$line->id.'-'.$i))) {
288  $langs->load("errors");
289  setEventMessages($langs->trans("ErrorFieldRequiredForProduct", $langs->transnoentitiesnoconv("Batch"), $tmpproduct->ref), null, 'errors');
290  $error++;
291  }
292  }
293 
294  $idstockmove = 0;
295  if (!$error && GETPOST('idwarehousetoproduce-'.$line->id.'-'.$i) > 0) {
296  // Record stock movement
297  $id_product_batch = 0;
298  $stockmove->origin_type = $object->element;
299  $stockmove->origin_id = $object->id;
300 
301  $idstockmove = $stockmove->reception($user, $line->fk_product, GETPOST('idwarehousetoproduce-'.$line->id.'-'.$i), $qtytoprocess, $pricetoprocess, $labelmovement, '', '', GETPOST('batchtoproduce-'.$line->id.'-'.$i), dol_now(), $id_product_batch, $codemovement);
302  if ($idstockmove < 0) {
303  $error++;
304  setEventMessages($stockmove->error, $stockmove->errors, 'errors');
305  }
306  }
307 
308  if (!$error) {
309  // Record production
310  $moline = new MoLine($db);
311  $moline->fk_mo = $object->id;
312  $moline->position = $pos;
313  $moline->fk_product = $line->fk_product;
314  $moline->fk_warehouse = GETPOST('idwarehousetoproduce-'.$line->id.'-'.$i);
315  $moline->qty = $qtytoprocess;
316  $moline->batch = GETPOST('batchtoproduce-'.$line->id.'-'.$i);
317  $moline->role = 'produced';
318  $moline->fk_mrp_production = $line->id;
319  $moline->fk_stock_movement = $idstockmove;
320  $moline->fk_user_creat = $user->id;
321 
322  $resultmoline = $moline->create($user);
323  if ($resultmoline <= 0) {
324  $error++;
325  setEventMessages($moline->error, $moline->errors, 'errors');
326  }
327 
328  $pos++;
329  }
330  }
331 
332  $i++;
333  }
334  }
335  }
336 
337  if (!$error) {
338  $consumptioncomplete = true;
339  $productioncomplete = true;
340 
341  if (GETPOST('autoclose', 'int')) {
342  foreach ($object->lines as $line) {
343  if ($line->role == 'toconsume') {
344  $arrayoflines = $object->fetchLinesLinked('consumed', $line->id);
345  $alreadyconsumed = 0;
346  foreach ($arrayoflines as $line2) {
347  $alreadyconsumed += $line2['qty'];
348  }
349 
350  if ($alreadyconsumed < $line->qty) {
351  $consumptioncomplete = false;
352  }
353  }
354  if ($line->role == 'toproduce') {
355  $arrayoflines = $object->fetchLinesLinked('produced', $line->id);
356  $alreadyproduced = 0;
357  foreach ($arrayoflines as $line2) {
358  $alreadyproduced += $line2['qty'];
359  }
360 
361  if ($alreadyproduced < $line->qty) {
362  $productioncomplete = false;
363  }
364  }
365  }
366  } else {
367  $consumptioncomplete = false;
368  $productioncomplete = false;
369  }
370 
371  // Update status of MO
372  dol_syslog("consumptioncomplete = ".$consumptioncomplete." productioncomplete = ".$productioncomplete);
373  //var_dump("consumptioncomplete = ".$consumptioncomplete." productioncomplete = ".$productioncomplete);
374  if ($consumptioncomplete && $productioncomplete) {
375  $result = $object->setStatut($object::STATUS_PRODUCED, 0, '', 'MRP_MO_PRODUCED');
376  } else {
377  $result = $object->setStatut($object::STATUS_INPROGRESS, 0, '', 'MRP_MO_PRODUCED');
378  }
379  if ($result <= 0) {
380  $error++;
381  setEventMessages($object->error, $object->errors, 'errors');
382  }
383  }
384 
385  if ($error) {
386  $action = str_replace('confirm_', '', $action);
387  $db->rollback();
388  } else {
389  $db->commit();
390 
391  // Redirect to avoid to action done a second time if we make a back from browser
392  header("Location: ".$_SERVER["PHP_SELF"].'?id='.$object->id);
393  exit;
394  }
395  }
396 
397  // Action close produced
398  if ($action == 'confirm_produced' && $confirm == 'yes' && $permissiontoadd) {
399  $result = $object->setStatut($object::STATUS_PRODUCED, 0, '', 'MRP_MO_PRODUCED');
400  if ($result >= 0) {
401  // Define output language
402  if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE)) {
403  $outputlangs = $langs;
404  $newlang = '';
405  if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && GETPOST('lang_id', 'aZ09')) {
406  $newlang = GETPOST('lang_id', 'aZ09');
407  }
408  if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
409  $newlang = $object->thirdparty->default_lang;
410  }
411  if (!empty($newlang)) {
412  $outputlangs = new Translate("", $conf);
413  $outputlangs->setDefaultLang($newlang);
414  }
415  $model = $object->model_pdf;
416  $ret = $object->fetch($id); // Reload to get new records
417 
418  $object->generateDocument($model, $outputlangs, 0, 0, 0);
419  }
420  } else {
421  setEventMessages($object->error, $object->errors, 'errors');
422  }
423  }
424 }
425 
426 
427 
428 /*
429  * View
430  */
431 
432 $form = new Form($db);
433 $formproject = new FormProjets($db);
434 $formproduct = new FormProduct($db);
435 $tmpwarehouse = new Entrepot($db);
436 $tmpbatch = new Productlot($db);
437 $tmpstockmovement = new MouvementStock($db);
438 
439 $help_url = 'EN:Module_Manufacturing_Orders|FR:Module_Ordres_de_Fabrication';
440 llxHeader('', $langs->trans('Mo'), $help_url, '', 0, 0, array('/mrp/js/lib_dispatch.js.php'));
441 
442 $newToken = newToken();
443 
444 // Part to show record
445 if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'create'))) {
446  $res = $object->fetch_thirdparty();
447  $res = $object->fetch_optionals();
448 
449  $head = moPrepareHead($object);
450 
451  print dol_get_fiche_head($head, 'production', $langs->trans("ManufacturingOrder"), -1, $object->picto);
452 
453  $formconfirm = '';
454 
455  // Confirmation to delete
456  if ($action == 'delete') {
457  $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('DeleteMo'), $langs->trans('ConfirmDeleteMo'), 'confirm_delete', '', 0, 1);
458  }
459  // Confirmation to delete line
460  if ($action == 'deleteline') {
461  $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);
462  }
463  // Clone confirmation
464  if ($action == 'clone') {
465  // Create an array for form
466  $formquestion = array();
467  $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('ToClone'), $langs->trans('ConfirmCloneMo', $object->ref), 'confirm_clone', $formquestion, 'yes', 1);
468  }
469 
470  // Confirmation of validation
471  if ($action == 'validate') {
472  // We check that object has a temporary ref
473  $ref = substr($object->ref, 1, 4);
474  if ($ref == 'PROV') {
475  $object->fetch_product();
476  $numref = $object->getNextNumRef($object->fk_product);
477  } else {
478  $numref = $object->ref;
479  }
480 
481  $text = $langs->trans('ConfirmValidateMo', $numref);
482  /*if (isModEnabled('notification'))
483  {
484  require_once DOL_DOCUMENT_ROOT . '/core/class/notify.class.php';
485  $notify = new Notify($db);
486  $text .= '<br>';
487  $text .= $notify->confirmMessage('BOM_VALIDATE', $object->socid, $object);
488  }*/
489 
490  $formquestion = array();
491  if (isModEnabled('mrp')) {
492  $langs->load("mrp");
493  require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php';
494  $formproduct = new FormProduct($db);
495  $forcecombo = 0;
496  if ($conf->browser->name == 'ie') {
497  $forcecombo = 1; // There is a bug in IE10 that make combo inside popup crazy
498  }
499  $formquestion = array(
500  // 'text' => $langs->trans("ConfirmClone"),
501  // array('type' => 'checkbox', 'name' => 'clone_content', 'label' => $langs->trans("CloneMainAttributes"), 'value' => 1),
502  // array('type' => 'checkbox', 'name' => 'update_prices', 'label' => $langs->trans("PuttingPricesUpToDate"), 'value' => 1),
503  );
504  }
505 
506  $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('Validate'), $text, 'confirm_validate', $formquestion, 0, 1, 220);
507  }
508 
509  // Call Hook formConfirm
510  $parameters = array('formConfirm' => $formconfirm, 'lineid' => $lineid);
511  $reshook = $hookmanager->executeHooks('formConfirm', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
512  if (empty($reshook)) {
513  $formconfirm .= $hookmanager->resPrint;
514  } elseif ($reshook > 0) {
515  $formconfirm = $hookmanager->resPrint;
516  }
517 
518  // Print form confirm
519  print $formconfirm;
520 
521 
522  // MO file
523  // ------------------------------------------------------------
524  $linkback = '<a href="'.DOL_URL_ROOT.'/mrp/mo_list.php?restore_lastsearch_values=1'.(!empty($socid) ? '&socid='.$socid : '').'">'.$langs->trans("BackToList").'</a>';
525 
526  $morehtmlref = '<div class="refidno">';
527  /*
528  // Ref bis
529  $morehtmlref.=$form->editfieldkey("RefBis", 'ref_client', $object->ref_client, $object, $user->rights->mrp->creer, 'string', '', 0, 1);
530  $morehtmlref.=$form->editfieldval("RefBis", 'ref_client', $object->ref_client, $object, $user->rights->mrp->creer, 'string', '', null, null, '', 1);*/
531  // Thirdparty
532  if (is_object($object->thirdparty)) {
533  $morehtmlref .= $object->thirdparty->getNomUrl(1, 'customer');
534  if (empty($conf->global->MAIN_DISABLE_OTHER_LINK) && $object->thirdparty->id > 0) {
535  $morehtmlref .= ' (<a href="'.DOL_URL_ROOT.'/commande/list.php?socid='.$object->thirdparty->id.'&search_societe='.urlencode($object->thirdparty->name).'">'.$langs->trans("OtherOrders").'</a>)';
536  }
537  }
538  // Project
539  if (isModEnabled('project')) {
540  $langs->load("projects");
541  if (is_object($object->thirdparty)) {
542  $morehtmlref .= '<br>';
543  }
544  if ($permissiontoadd) {
545  $morehtmlref .= img_picto($langs->trans("Project"), 'project', 'class="pictofixedwidth"');
546  if ($action != 'classify') {
547  $morehtmlref .= '<a class="editfielda" href="'.$_SERVER['PHP_SELF'].'?action=classify&token='.newToken().'&id='.$object->id.'">'.img_edit($langs->transnoentitiesnoconv('SetProject')).'</a> ';
548  }
549  $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'].'?id='.$object->id, $object->socid, $object->fk_project, ($action == 'classify' ? 'projectid' : 'none'), 0, 0, 0, 1, '', 'maxwidth300');
550  } else {
551  if (!empty($object->fk_project)) {
552  $proj = new Project($db);
553  $proj->fetch($object->fk_project);
554  $morehtmlref .= $proj->getNomUrl(1);
555  if ($proj->title) {
556  $morehtmlref .= '<span class="opacitymedium"> - '.dol_escape_htmltag($proj->title).'</span>';
557  }
558  }
559  }
560  }
561  $morehtmlref .= '</div>';
562 
563 
564  dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref);
565 
566 
567  print '<div class="fichecenter">';
568  print '<div class="fichehalfleft">';
569  print '<div class="underbanner clearboth"></div>';
570  print '<table class="border centpercent tableforfield">'."\n";
571 
572  // Common attributes
573  $keyforbreak = 'fk_warehouse';
574  unset($object->fields['fk_project']);
575  unset($object->fields['fk_soc']);
576  include DOL_DOCUMENT_ROOT.'/core/tpl/commonfields_view.tpl.php';
577 
578  // Other attributes
579  include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_view.tpl.php';
580 
581  print '</table>';
582  print '</div>';
583  print '</div>';
584 
585  print '<div class="clearboth"></div>';
586 
587  print dol_get_fiche_end();
588 
589 
590  if (!in_array($action, array('consumeorproduce', 'consumeandproduceall'))) {
591  print '<div class="tabsAction">';
592 
593  $parameters = array();
594  // Note that $action and $object may be modified by hook
595  $reshook = $hookmanager->executeHooks('addMoreActionsButtons', $parameters, $object, $action);
596  if (empty($reshook)) {
597  // Validate
598  if ($object->status == $object::STATUS_DRAFT) {
599  if ($permissiontoadd) {
600  if (empty($object->table_element_line) || (is_array($object->lines) && count($object->lines) > 0)) {
601  print '<a class="butAction" href="'.$_SERVER['PHP_SELF'].'?id='.$object->id.'&action=validate&token='.$newToken.'">'.$langs->trans("Validate").'</a>';
602  } else {
603  $langs->load("errors");
604  print '<a class="butActionRefused" href="" title="'.$langs->trans("ErrorAddAtLeastOneLineFirst").'">'.$langs->trans("Validate").'</a>';
605  }
606  }
607  }
608 
609  // Consume or produce
610  if ($object->status == Mo::STATUS_VALIDATED || $object->status == Mo::STATUS_INPROGRESS) {
611  if ($permissiontoproduce) {
612  print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=consumeorproduce&token='.$newToken.'">'.$langs->trans('ConsumeOrProduce').'</a>';
613  } else {
614  print '<a class="butActionRefused classfortooltip" href="#" title="'.$langs->trans("NotEnoughPermissions").'">'.$langs->trans('ConsumeOrProduce').'</a>';
615  }
616  } elseif ($object->status == Mo::STATUS_DRAFT) {
617  print '<a class="butActionRefused classfortooltip" href="#" title="'.$langs->trans("ValidateBefore").'">'.$langs->trans('ConsumeOrProduce').'</a>';
618  }
619 
620  // ConsumeAndProduceAll
621  if ($object->status == Mo::STATUS_VALIDATED || $object->status == Mo::STATUS_INPROGRESS) {
622  if ($permissiontoproduce) {
623  print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=consumeandproduceall&token='.$newToken.'">'.$langs->trans('ConsumeAndProduceAll').'</a>';
624  } else {
625  print '<a class="butActionRefused classfortooltip" href="#" title="'.$langs->trans("NotEnoughPermissions").'">'.$langs->trans('ConsumeAndProduceAll').'</a>';
626  }
627  } elseif ($object->status == Mo::STATUS_DRAFT) {
628  print '<a class="butActionRefused classfortooltip" href="#" title="'.$langs->trans("ValidateBefore").'">'.$langs->trans('ConsumeAndProduceAll').'</a>';
629  }
630 
631  // Cancel - Reopen
632  if ($permissiontoadd) {
633  if ($object->status == $object::STATUS_VALIDATED || $object->status == $object::STATUS_INPROGRESS) {
634  $arrayproduced = $object->fetchLinesLinked('produced', 0);
635  $nbProduced = 0;
636  foreach ($arrayproduced as $lineproduced) {
637  $nbProduced += $lineproduced['qty'];
638  }
639  if ($nbProduced > 0) { // If production has started, we can close it
640  print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=confirm_produced&confirm=yes&token='.$newToken.'">'.$langs->trans("Close").'</a>'."\n";
641  } else {
642  print '<a class="butActionRefused" href="#" title="'.$langs->trans("GoOnTabProductionToProduceFirst", $langs->transnoentitiesnoconv("Production")).'">'.$langs->trans("Close").'</a>'."\n";
643  }
644 
645  print '<a class="butActionDelete" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=confirm_close&confirm=yes&token='.$newToken.'">'.$langs->trans("Cancel").'</a>'."\n";
646  }
647 
648  if ($object->status == $object::STATUS_CANCELED) {
649  print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=confirm_reopen&confirm=yes&token='.$newToken.'">'.$langs->trans("Re-Open").'</a>'."\n";
650  }
651 
652  if ($object->status == $object::STATUS_PRODUCED) {
653  if ($permissiontoproduce) {
654  print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=confirm_reopen&token='.$newToken.'">'.$langs->trans('ReOpen').'</a>';
655  } else {
656  print '<a class="butActionRefused classfortooltip" href="#" title="'.$langs->trans("NotEnoughPermissions").'">'.$langs->trans('ReOpen').'</a>';
657  }
658  }
659  }
660  }
661 
662  print '</div>';
663  }
664 
665  if (in_array($action, array('consumeorproduce', 'consumeandproduceall', 'addconsumeline', 'addproduceline'))) {
666  print '<form method="POST" action="'.$_SERVER["PHP_SELF"].'">';
667  print '<input type="hidden" name="token" value="'.newToken().'">';
668  print '<input type="hidden" name="action" value="confirm_'.$action.'">';
669  print '<input type="hidden" name="backtopage" value="'.$backtopage.'">';
670  print '<input type="hidden" name="id" value="'.$id.'">';
671  // Note: closing form is add end of page
672 
673  if (in_array($action, array('consumeorproduce', 'consumeandproduceall'))) {
674  $defaultstockmovementlabel = GETPOST('inventorylabel', 'alphanohtml') ? GETPOST('inventorylabel', 'alphanohtml') : $langs->trans("ProductionForRef", $object->ref);
675  $defaultstockmovementcode = GETPOST('inventorycode', 'alphanohtml') ? GETPOST('inventorycode', 'alphanohtml') : dol_print_date(dol_now(), 'dayhourlog');
676 
677  print '<div class="center'.(in_array($action, array('consumeorproduce', 'consumeandproduceall')) ? ' formconsumeproduce' : '').'">';
678  print '<div class="opacitymedium hideonsmartphone paddingbottom">'.$langs->trans("ConfirmProductionDesc", $langs->transnoentitiesnoconv("Confirm")).'<br></div>';
679  print '<span class="fieldrequired">'.$langs->trans("InventoryCode").':</span> <input type="text" class="minwidth200 maxwidth250" name="inventorycode" value="'.$defaultstockmovementcode.'"> &nbsp; ';
680  print '<span class="clearbothonsmartphone"></span>';
681  print $langs->trans("MovementLabel").': <input type="text" class="minwidth300" name="inventorylabel" value="'.$defaultstockmovementlabel.'"><br><br>';
682  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>';
683  print '<input type="submit" class="button" value="'.$langs->trans("Confirm").'" name="confirm">';
684  print ' &nbsp; ';
685  print '<input class="button button-cancel" type="submit" value="'.$langs->trans("Cancel").'" name="cancel">';
686  print '<br><br>';
687  print '</div>';
688 
689  print '<br>';
690  }
691  }
692 
693 
694  /*
695  * Lines
696  */
697  $collapse = 1;
698 
699  if (!empty($object->table_element_line)) {
700  // Show object lines
701  $object->fetchLines();
702 
703  $bomcost = 0;
704  if ($object->fk_bom > 0) {
705  $bom = new Bom($db);
706  $res = $bom->fetch($object->fk_bom);
707  if ($res > 0) {
708  $bom->calculateCosts();
709  $bomcost = $bom->unit_cost;
710  }
711  }
712 
713  // Lines to consume
714 
715  print '<div class="fichecenter">';
716  print '<div class="fichehalfleft">';
717  print '<div class="clearboth"></div>';
718 
719  $url = $_SERVER["PHP_SELF"].'?id='.$object->id.'&action=addconsumeline&token='.newToken();
720  $permissiontoaddaconsumeline = $object->status != $object::STATUS_PRODUCED && $object->status != $object::STATUS_CANCELED;
721  $parameters = array('morecss'=>'reposition');
722 
723  $newcardbutton = '';
724  if ($action != 'consumeorproduce' && $action != 'consumeandproduceall') {
725  $newcardbutton = dolGetButtonTitle($langs->trans('AddNewConsumeLines'), '', 'fa fa-plus-circle size15x', $url, '', $permissiontoaddaconsumeline, $parameters);
726  }
727 
728  print load_fiche_titre($langs->trans('Consumption'), $newcardbutton, '', 0, '', '', '');
729 
730  print '<div class="div-table-responsive-no-min">';
731  print '<table class="noborder noshadow centpercent nobottom">';
732 
733  print '<tr class="liste_titre">';
734  print '<td>'.$langs->trans("Product").'</td>';
735  // Qty
736  print '<td class="right">'.$langs->trans("Qty").'</td>';
737  // Cost price
738  if ($permissiontoupdatecost && !empty($conf->global->MRP_SHOW_COST_FOR_CONSUMPTION)) {
739  print '<td class="right">'.$langs->trans("UnitCost").'</td>';
740  }
741  // Qty already consumed
742  print '<td class="right">'.$langs->trans("QtyAlreadyConsumed").'</td>';
743  // Warehouse
744  print '<td>';
745  if ($collapse || in_array($action, array('consumeorproduce', 'consumeandproduceall'))) {
746  print $langs->trans("Warehouse");
747 
748  // Select warehouse to force it everywhere
749  if (in_array($action, array('consumeorproduce', 'consumeandproduceall'))) {
750  $listwarehouses = $tmpwarehouse->list_array(1);
751  if (count($listwarehouses) > 1) {
752  print '<br><span class="opacitymedium">' . $langs->trans("ForceTo") . '</span> ' . $form->selectarray('fk_default_warehouse', $listwarehouses, $fk_default_warehouse, 1, 0, 0, '', 0, 0, 0, '', 'minwidth100 maxwidth300', 1);
753  } elseif (count($listwarehouses) == 1) {
754  print '<br><span class="opacitymedium">' . $langs->trans("ForceTo") . '</span> ' . $form->selectarray('fk_default_warehouse', $listwarehouses, $fk_default_warehouse, 0, 0, 0, '', 0, 0, 0, '', 'minwidth100 maxwidth300', 1);
755  }
756  }
757  }
758  print '</td>';
759  if (isModEnabled('stock')) {
760  // Available
761  print '<td align="right">';
762  if ($collapse || in_array($action, array('consumeorproduce', 'consumeandproduceall'))) {
763  print $langs->trans("Stock");
764  }
765  print '</td>';
766  }
767  // Lot - serial
768  if (isModEnabled('productbatch')) {
769  print '<td>';
770  if ($collapse || in_array($action, array('consumeorproduce', 'consumeandproduceall'))) {
771  print $langs->trans("Batch");
772  }
773  print '</td>';
774  }
775  // Action
776  if ($permissiontodelete) {
777  print '<td></td>';
778  }
779 
780  // Split
781  print '<td></td>';
782 
783  // SplitAll
784  print '<td></td>';
785 
786  print '</tr>';
787 
788  if ($action == 'addconsumeline') {
789  print '<!-- Add line to consume -->'."\n";
790  print '<tr class="liste_titre">';
791  print '<td>';
792  print $form->select_produits('', 'productidtoadd', '', 0, 0, -1, 2, '', 1, array(), 0, '1', 0, 'maxwidth300');
793  print '</td>';
794  // Qty
795  print '<td class="right"><input type="text" name="qtytoadd" value="1" class="width50 right"></td>';
796  // Cost price
797  if ($permissiontoupdatecost && !empty($conf->global->MRP_SHOW_COST_FOR_CONSUMPTION)) {
798  print '<td></td>';
799  }
800  // Qty already consumed
801  print '<td colspan="2">';
802  // Warehouse
803  print '<input type="submit" class="button buttongen button-add" name="addconsumelinebutton" value="'.$langs->trans("Add").'">';
804  print '<input type="submit" class="button buttongen button-cancel" name="canceladdconsumelinebutton" value="'.$langs->trans("Cancel").'">';
805  print '</td>';
806  if (isModEnabled('stock')) {
807  print '<td></td>';
808  }
809  // Lot - serial
810  if (isModEnabled('productbatch')) {
811  print '<td></td>';
812  }
813  // Action
814  if ($permissiontodelete) {
815  print '<td></td>';
816  }
817  // Split
818  print '<td></td>';
819  // SplitAll
820  print '<td></td>';
821  print '</tr>';
822  }
823 
824  // Lines to consume
825 
826  $bomcostupdated = 0; // We will recalculate the unitary cost to produce a product using the real "products to consume into MO"
827 
828  if (!empty($object->lines)) {
829  $nblinetoconsume = 0;
830  foreach ($object->lines as $line) {
831  if ($line->role == 'toconsume') {
832  $nblinetoconsume++;
833  }
834  }
835 
836  $nblinetoconsumecursor = 0;
837  foreach ($object->lines as $line) {
838  if ($line->role == 'toconsume') {
839  $nblinetoconsumecursor++;
840 
841  $tmpproduct = new Product($db);
842  $tmpproduct->fetch($line->fk_product);
843  $linecost = price2num($tmpproduct->pmp, 'MT');
844 
845  if ($object->qty > 0) {
846  // add free consume line cost to $bomcostupdated
847  $costprice = price2num((!empty($tmpproduct->cost_price)) ? $tmpproduct->cost_price : $tmpproduct->pmp);
848  if (empty($costprice)) {
849  require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.product.class.php';
850  $productFournisseur = new ProductFournisseur($db);
851  if ($productFournisseur->find_min_price_product_fournisseur($line->fk_product) > 0) {
852  $costprice = $productFournisseur->fourn_unitprice;
853  } else {
854  $costprice = 0;
855  }
856  }
857  $linecost = price2num(($line->qty * $costprice) / $object->qty, 'MT'); // price for line for all quantities
858  $bomcostupdated += price2num(($line->qty * $costprice) / $object->qty, 'MU'); // same but with full accuracy
859  }
860 
861  $bomcostupdated = price2num($bomcostupdated, 'MU');
862  $arrayoflines = $object->fetchLinesLinked('consumed', $line->id);
863  $alreadyconsumed = 0;
864  foreach ($arrayoflines as $line2) {
865  $alreadyconsumed += $line2['qty'];
866  }
867 
868  $suffix = '_'.$line->id;
869  print '<!-- Line to dispatch '.$suffix.' -->'."\n";
870  // hidden fields for js function
871  print '<input id="qty_ordered'.$suffix.'" type="hidden" value="'.$line->qty.'">';
872  print '<input id="qty_dispatched'.$suffix.'" type="hidden" value="'.$alreadyconsumed.'">';
873 
874  print '<tr data-line-id="'.$line->id.'">';
875  // Product
876  print '<td>'.$tmpproduct->getNomUrl(1);
877  print '<br><span class="opacitymedium small">'.$tmpproduct->label.'</span>';
878  print '</td>';
879  // Qty
880  print '<td class="right nowraponall">';
881  $help = ''; $picto = 'help';
882  if ($line->qty_frozen) {
883  $help = ($help ? '<br>' : '').'<strong>'.$langs->trans("QuantityFrozen").'</strong>: '.yn(1).' ('.$langs->trans("QuantityConsumedInvariable").')';
884  print $form->textwithpicto('', $help, -1, 'lock').' ';
885  }
886  if ($line->disable_stock_change) {
887  $help = ($help ? '<br>' : '').'<strong>'.$langs->trans("DisableStockChange").'</strong>: '.yn(1).' ('.(($tmpproduct->type == Product::TYPE_SERVICE && empty($conf->global->STOCK_SUPPORTS_SERVICES)) ? $langs->trans("NoStockChangeOnServices") : $langs->trans("DisableStockChangeHelp")).')';
888  print $form->textwithpicto('', $help, -1, 'help').' ';
889  }
890  print price2num($line->qty, 'MS');
891  print '</td>';
892  // Cost price
893  if ($permissiontoupdatecost && !empty($conf->global->MRP_SHOW_COST_FOR_CONSUMPTION)) {
894  print '<td class="right nowraponall">';
895  print price($linecost);
896  print '</td>';
897  }
898  // Already consumed
899  print '<td class="right">';
900  if ($alreadyconsumed) {
901  print '<script>';
902  print 'jQuery(document).ready(function() {
903  jQuery("#expandtoproduce'.$line->id.'").click(function() {
904  console.log("Expand mrp_production line '.$line->id.'");
905  jQuery(".expanddetail'.$line->id.'").toggle();';
906  if ($nblinetoconsume == $nblinetoconsumecursor) { // If it is the last line
907  print 'if (jQuery("#tablelines").hasClass("nobottom")) { jQuery("#tablelines").removeClass("nobottom"); } else { jQuery("#tablelines").addClass("nobottom"); }';
908  }
909  print '
910  });
911  });';
912  print '</script>';
913  if (empty($conf->use_javascript_ajax)) {
914  print '<a href="'.$_SERVER["PHP_SELF"].'?collapse='.$collapse.','.$line->id.'">';
915  }
916  print img_picto($langs->trans("ShowDetails"), "chevron-down", 'id="expandtoproduce'.$line->id.'"');
917  if (empty($conf->use_javascript_ajax)) {
918  print '</a>';
919  }
920  } else {
921  if ($nblinetoconsume == $nblinetoconsumecursor) { // If it is the last line
922  print '<script>jQuery("#tablelines").removeClass("nobottom");</script>';
923  }
924  }
925  print ' '.price2num($alreadyconsumed, 'MS');
926  print '</td>';
927  // Warehouse
928  print '<td>';
929  print '</td>';
930  // Stock
931  if (isModEnabled('stock')) {
932  print '<td class="nowraponall right">';
933  if (empty($conf->global->STOCK_SUPPORTS_SERVICES) && $tmpproduct->type != PRODUCT::TYPE_SERVICE) {
934  if (!$line->disable_stock_change && $tmpproduct->stock_reel < ($line->qty - $alreadyconsumed)) {
935  print img_warning($langs->trans('StockTooLow')) . ' ';
936  }
937  print price2num($tmpproduct->stock_reel, 'MS'); // Available
938  }
939  print '</td>';
940  }
941  // Lot
942  if (isModEnabled('productbatch')) {
943  print '<td></td>';
944  }
945 
946  // Split
947  print '<td></td>';
948 
949  // Split All
950  print '<td></td>';
951 
952  // Action delete line
953  if ($permissiontodelete) {
954  $href = $_SERVER["PHP_SELF"].'?id='.((int) $object->id).'&action=deleteline&token='.newToken().'&lineid='.((int) $line->id);
955  print '<td class="center">';
956  print '<a class="reposition" href="'.$href.'">';
957  print img_picto($langs->trans('TooltipDeleteAndRevertStockMovement'), 'delete');
958  print '</a>';
959  print '</td>';
960  }
961 
962  print '</tr>';
963 
964  // Show detailed of already consumed with js code to collapse
965  foreach ($arrayoflines as $line2) {
966  print '<tr class="expanddetail'.$line->id.' hideobject opacitylow">';
967 
968  // Date
969  print '<td>';
970  $tmpstockmovement->id = $line2['fk_stock_movement'];
971  print '<a href="'.DOL_URL_ROOT.'/product/stock/movement_list.php?search_ref='.$tmpstockmovement->id.'">'.img_picto($langs->trans("StockMovement"), 'movement', 'class="paddingright"').'</a>';
972  print dol_print_date($line2['date'], 'dayhour', 'tzuserrel');
973  print '</td>';
974 
975  // Already consumed
976  print '<td></td>';
977 
978  // Qty
979  print '<td class="right">'.$line2['qty'].'</td>';
980 
981  // Cost price
982  if ($permissiontoupdatecost && !empty($conf->global->MRP_SHOW_COST_FOR_CONSUMPTION)) {
983  print '<td></td>';
984  }
985 
986  // Warehouse
987  print '<td class="tdoverflowmax150">';
988  if ($line2['fk_warehouse'] > 0) {
989  $result = $tmpwarehouse->fetch($line2['fk_warehouse']);
990  if ($result > 0) {
991  print $tmpwarehouse->getNomUrl(1);
992  }
993  }
994  print '</td>';
995 
996  // Stock
997  if (isModEnabled('stock')) {
998  print '<td></td>';
999  }
1000 
1001  // Lot Batch
1002  if (isModEnabled('productbatch')) {
1003  print '<td>';
1004  if ($line2['batch'] != '') {
1005  $tmpbatch->fetch(0, $line2['fk_product'], $line2['batch']);
1006  print $tmpbatch->getNomUrl(1);
1007  }
1008  print '</td>';
1009  }
1010 
1011  // Split
1012  print '<td></td>';
1013 
1014  // Split All
1015  print '<td></td>';
1016 
1017  // Action delete line
1018  if ($permissiontodelete) {
1019  $href = $_SERVER["PHP_SELF"].'?id='.((int) $object->id).'&action=deleteline&token='.newToken().'&lineid='.((int) $line2['rowid']).'&fk_movement='.((int) $line2['fk_stock_movement']);
1020  print '<td class="center">';
1021  print '<a class="reposition" href="'.$href.'">';
1022  print img_picto($langs->trans('TooltipDeleteAndRevertStockMovement'), 'delete');
1023  print '</a>';
1024  print '</td>';
1025  }
1026 
1027  print '</tr>';
1028  }
1029 
1030  if (in_array($action, array('consumeorproduce', 'consumeandproduceall'))) {
1031  $i = 1;
1032  print '<!-- Enter line to consume -->'."\n";
1033  $maxQty = 1;
1034  print '<tr data-max-qty="'.$maxQty.'" name="batch_'.$line->id.'_'.$i.'">';
1035  // Ref
1036  print '<td><span class="opacitymedium">'.$langs->trans("ToConsume").'</span></td>';
1037  $preselected = (GETPOSTISSET('qty-'.$line->id.'-'.$i) ? GETPOST('qty-'.$line->id.'-'.$i) : max(0, $line->qty - $alreadyconsumed));
1038  if ($action == 'consumeorproduce' && !GETPOSTISSET('qty-'.$line->id.'-'.$i)) {
1039  $preselected = 0;
1040  }
1041 
1042  $disable = '';
1043  if (!empty($conf->global->MRP_NEVER_CONSUME_MORE_THAN_EXPECTED) && ($line->qty - $alreadyconsumed) <= 0) {
1044  $disable = 'disabled';
1045  }
1046 
1047  // input hidden with fk_product of line
1048  print '<input type="hidden" name="product-'.$line->id.'-'.$i.'" value="'.$line->fk_product.'">';
1049 
1050  // Qty
1051  print '<td class="right"><input type="text" class="width50 right" id="qtytoconsume-'.$line->id.'-'.$i.'" name="qty-'.$line->id.'-'.$i.'" value="'.$preselected.'" '.$disable.'></td>';
1052 
1053  // Cost
1054  if ($permissiontoupdatecost && !empty($conf->global->MRP_SHOW_COST_FOR_CONSUMPTION)) {
1055  print '<td></td>';
1056  }
1057 
1058  // Already consumed
1059  print '<td></td>';
1060 
1061  // Warehouse
1062  print '<td>';
1063  if ($tmpproduct->type == Product::TYPE_PRODUCT || !empty($conf->global->STOCK_SUPPORTS_SERVICES)) {
1064  if (empty($line->disable_stock_change)) {
1065  $preselected = (GETPOSTISSET('idwarehouse-'.$line->id.'-'.$i) ? GETPOST('idwarehouse-'.$line->id.'-'.$i) : ($tmpproduct->fk_default_warehouse > 0 ? $tmpproduct->fk_default_warehouse : 'ifone'));
1066  print $formproduct->selectWarehouses($preselected, 'idwarehouse-'.$line->id.'-'.$i, '', 1, 0, $line->fk_product, '', 1, 0, null, 'maxwidth200 csswarehouse_'.$line->id.'_'.$i);
1067  } else {
1068  print '<span class="opacitymedium">'.$langs->trans("DisableStockChange").'</span>';
1069  }
1070  } else {
1071  print '<span class="opacitymedium">'.$langs->trans("NoStockChangeOnServices").'</span>';
1072  }
1073  print '</td>';
1074 
1075  // Stock
1076  if (isModEnabled('stock')) {
1077  print '<td></td>';
1078  }
1079 
1080  // Lot / Batch
1081  if (isModEnabled('productbatch')) {
1082  print '<td class="nowraponall">';
1083  if ($tmpproduct->status_batch) {
1084  $preselected = (GETPOSTISSET('batch-'.$line->id.'-'.$i) ? GETPOST('batch-'.$line->id.'-'.$i) : '');
1085  print '<input type="text" class="width50" name="batch-'.$line->id.'-'.$i.'" value="'.$preselected.'" list="batch-'.$line->id.'-'.$i.'">';
1086  print $formproduct->selectLotDataList('batch-'.$line->id.'-'.$i, 0, $line->fk_product, '', '');
1087  }
1088  print '</td>';
1089  }
1090 
1091  // Split
1092  $type = 'batch';
1093  print '<td align="right" class="split">';
1094  print ' '.img_picto($langs->trans('AddStockLocationLine'), 'split.png', 'class="splitbutton" onClick="addDispatchLine('.((int) $line->id).', \''.dol_escape_js($type).'\', \'qtymissingconsume\')"');
1095  print '</td>';
1096 
1097  // Split All
1098  print '<td align="right" class="splitall">';
1099  if (($action == 'consumeorproduce' || $action == 'consumeandproduceall') && $tmpproduct->status_batch == 2) {
1100  print img_picto($langs->trans('SplitAllQuantity'), 'split.png', 'class="splitbutton splitallbutton field-error-icon" data-max-qty="1" onClick="addDispatchLine('.$line->id.', \'batch\', \'allmissingconsume\')"');
1101  }
1102  print '</td>';
1103 
1104  // Action delete line
1105  if ($permissiontodelete) {
1106  print '<td></td>';
1107  }
1108 
1109  print '</tr>';
1110  }
1111  }
1112  }
1113  }
1114 
1115  print '</table>';
1116  print '</div>';
1117 
1118  // default warehouse processing
1119  print '<script type="text/javascript">
1120  $(document).ready(function () {
1121  $("select[name=fk_default_warehouse]").change(function() {
1122  var fk_default_warehouse = $("option:selected", this).val();
1123  $("select[name^=idwarehouse-]").val(fk_default_warehouse).change();
1124  });
1125  });
1126  </script>';
1127 
1128 
1129  // Lines to produce
1130 
1131  print '</div>';
1132  print '<div class="fichehalfright">';
1133  print '<div class="clearboth"></div>';
1134 
1135  $nblinetoproduce = 0;
1136  foreach ($object->lines as $line) {
1137  if ($line->role == 'toproduce') {
1138  $nblinetoproduce++;
1139  }
1140  }
1141 
1142  $newcardbutton = '';
1143  $url = $_SERVER["PHP_SELF"].'?id='.$object->id.'&action=addproduceline&token='.newToken();
1144  $permissiontoaddaproductline = $object->status != $object::STATUS_PRODUCED && $object->status != $object::STATUS_CANCELED;
1145  $parameters = array('morecss'=>'reposition');
1146  if ($action != 'consumeorproduce' && $action != 'consumeandproduceall') {
1147  if ($nblinetoproduce == 0 || $object->mrptype == 1) {
1148  $newcardbutton = dolGetButtonTitle($langs->trans('AddNewProduceLines'), '', 'fa fa-plus-circle size15x', $url, '', $permissiontoaddaproductline, $parameters);
1149  }
1150  }
1151 
1152  print load_fiche_titre($langs->trans('Production'), $newcardbutton, '', 0, '', '');
1153 
1154  print '<div class="div-table-responsive-no-min">';
1155  print '<table id="tablelinestoproduce" class="noborder noshadow nobottom centpercent">';
1156 
1157  print '<tr class="liste_titre">';
1158  // Product
1159  print '<td>'.$langs->trans("Product").'</td>';
1160  // Qty
1161  print '<td class="right">'.$langs->trans("Qty").'</td>';
1162  // Cost price
1163  if ($permissiontoupdatecost) {
1164  if (empty($bomcostupdated)) {
1165  print '<td class="right">'.$form->textwithpicto($langs->trans("UnitCost"), $langs->trans("AmountUsedToUpdateWAP")).'</td>';
1166  } else {
1167  print '<td class="right">'.$form->textwithpicto($langs->trans("ManufacturingPrice"), $langs->trans("AmountUsedToUpdateWAP")).'</td>';
1168  }
1169  }
1170  // Already produced
1171  print '<td class="right">'.$langs->trans("QtyAlreadyProduced").'</td>';
1172  // Warehouse
1173  print '<td>';
1174  if ($collapse || in_array($action, array('consumeorproduce', 'consumeandproduceall'))) {
1175  print $langs->trans("Warehouse");
1176  }
1177  print '</td>';
1178 
1179  // Lot
1180  if (isModEnabled('productbatch')) {
1181  print '<td>';
1182  if ($collapse || in_array($action, array('consumeorproduce', 'consumeandproduceall'))) {
1183  print $langs->trans("Batch");
1184  }
1185  print '</td>';
1186 
1187  // Split
1188  print '<td></td>';
1189 
1190  // Split All
1191  print '<td></td>';
1192  }
1193 
1194  // Action delete
1195  if ($permissiontodelete) {
1196  print '<td></td>';
1197  }
1198 
1199  print '</tr>';
1200 
1201  if ($action == 'addproduceline') {
1202  print '<!-- Add line to produce -->'."\n";
1203  print '<tr class="liste_titre">';
1204 
1205  // Product
1206  print '<td>';
1207  print $form->select_produits('', 'productidtoadd', '', 0, 0, -1, 2, '', 1, array(), 0, '1', 0, 'maxwidth300');
1208  print '</td>';
1209  // Qty
1210  print '<td class="right"><input type="text" name="qtytoadd" value="1" class="width50 right"></td>';
1211  // Cost price
1212  if ($permissiontoupdatecost) {
1213  print '<td></td>';
1214  }
1215  // Action (cost price + already produced)
1216  print '<td colspan="2">';
1217  print '<input type="submit" class="button buttongen button-add" name="addproducelinebutton" value="'.$langs->trans("Add").'">';
1218  print '<input type="submit" class="button buttongen button-cancel" name="canceladdproducelinebutton" value="'.$langs->trans("Cancel").'">';
1219  print '</td>';
1220  // Lot - serial
1221  if (isModEnabled('productbatch')) {
1222  print '<td></td>';
1223 
1224  // Split
1225  print '<td></td>';
1226 
1227  // Split All
1228  print '<td></td>';
1229  }
1230  // Action delete
1231  if ($permissiontodelete) {
1232  print '<td></td>';
1233  }
1234  print '</tr>';
1235  }
1236 
1237  if (!empty($object->lines)) {
1238  $nblinetoproduce = 0;
1239  foreach ($object->lines as $line) {
1240  if ($line->role == 'toproduce') {
1241  $nblinetoproduce++;
1242  }
1243  }
1244 
1245  $nblinetoproducecursor = 0;
1246  foreach ($object->lines as $line) {
1247  if ($line->role == 'toproduce') {
1248  $i = 1;
1249 
1250  $nblinetoproducecursor++;
1251 
1252  $tmpproduct = new Product($db);
1253  $tmpproduct->fetch($line->fk_product);
1254 
1255  $arrayoflines = $object->fetchLinesLinked('produced', $line->id);
1256  $alreadyproduced = 0;
1257  foreach ($arrayoflines as $line2) {
1258  $alreadyproduced += $line2['qty'];
1259  }
1260 
1261  $suffix = '_'.$line->id;
1262  print '<!-- Line to dispatch '.$suffix.' -->'."\n";
1263  // hidden fields for js function
1264  print '<input id="qty_ordered'.$suffix.'" type="hidden" value="'.$line->qty.'">';
1265  print '<input id="qty_dispatched'.$suffix.'" type="hidden" value="'.$alreadyproduced.'">';
1266 
1267  print '<tr>';
1268  // Product
1269  print '<td>'.$tmpproduct->getNomUrl(1);
1270  print '<br><span class="opacitymedium small">'.$tmpproduct->label.'</span>';
1271  print '</td>';
1272  // Qty
1273  print '<td class="right">'.$line->qty.'</td>';
1274  // Cost price
1275  if ($permissiontoupdatecost) {
1276  // Defined $manufacturingcost
1277  $manufacturingcost = 0;
1278  $manufacturingcostsrc = '';
1279  if ($object->mrptype == 0) { // If MO is a "Manufacture" type (and not "Disassemble")
1280  $manufacturingcost = $bomcostupdated;
1281  $manufacturingcostsrc = $langs->trans("CalculatedFromProductsToConsume");
1282  if (empty($manufacturingcost)) {
1283  $manufacturingcost = $bomcost;
1284  $manufacturingcostsrc = $langs->trans("ValueFromBom");
1285  }
1286  if (empty($manufacturingcost)) {
1287  $manufacturingcost = price2num($tmpproduct->cost_price, 'MU');
1288  $manufacturingcostsrc = $langs->trans("CostPrice");
1289  }
1290  if (empty($manufacturingcost)) {
1291  $manufacturingcost = price2num($tmpproduct->pmp, 'MU');
1292  $manufacturingcostsrc = $langs->trans("PMPValue");
1293  }
1294  }
1295 
1296  print '<td class="right nowraponall" title="'.dol_escape_htmltag($manufacturingcostsrc).'">';
1297  if ($manufacturingcost) {
1298  print price($manufacturingcost);
1299  }
1300  print '</td>';
1301  }
1302  // Already produced
1303  print '<td class="right nowraponall">';
1304  if ($alreadyproduced) {
1305  print '<script>';
1306  print 'jQuery(document).ready(function() {
1307  jQuery("#expandtoproduce'.$line->id.'").click(function() {
1308  console.log("Expand mrp_production line '.$line->id.'");
1309  jQuery(".expanddetailtoproduce'.$line->id.'").toggle();';
1310  if ($nblinetoproduce == $nblinetoproducecursor) {
1311  print 'if (jQuery("#tablelinestoproduce").hasClass("nobottom")) { jQuery("#tablelinestoproduce").removeClass("nobottom"); } else { jQuery("#tablelinestoproduce").addClass("nobottom"); }';
1312  }
1313  print '
1314  });
1315  });';
1316  print '</script>';
1317  if (empty($conf->use_javascript_ajax)) {
1318  print '<a href="'.$_SERVER["PHP_SELF"].'?collapse='.$collapse.','.$line->id.'">';
1319  }
1320  print img_picto($langs->trans("ShowDetails"), "chevron-down", 'id="expandtoproduce'.$line->id.'"');
1321  if (empty($conf->use_javascript_ajax)) {
1322  print '</a>';
1323  }
1324  }
1325  print ' '.$alreadyproduced;
1326  print '</td>';
1327  // Warehouse
1328  print '<td>';
1329  print '</td>';
1330  // Lot
1331  if (isModEnabled('productbatch')) {
1332  print '<td></td>';
1333 
1334  // Split
1335  print '<td></td>';
1336 
1337  // Split All
1338  print '<td></td>';
1339  }
1340  // Delete
1341  if ($permissiontodelete) {
1342  if ($line->origin_type == 'free') {
1343  $href = $_SERVER["PHP_SELF"];
1344  $href .= '?id='.$object->id;
1345  $href .= '&action=deleteline';
1346  $href .= '&lineid='.$line->id;
1347  print '<td class="center">';
1348  print '<a class="reposition" href="'.$href.'">';
1349  print img_picto($langs->trans('TooltipDeleteAndRevertStockMovement'), "delete");
1350  print '</a>';
1351  print '</td>';
1352  } else {
1353  print '<td></td>';
1354  }
1355  }
1356  print '</tr>';
1357 
1358  // Show detailed of already consumed with js code to collapse
1359  foreach ($arrayoflines as $line2) {
1360  print '<tr class="expanddetailtoproduce'.$line->id.' hideobject opacitylow">';
1361  // Product
1362  print '<td>';
1363  $tmpstockmovement->id = $line2['fk_stock_movement'];
1364  print '<a href="'.DOL_URL_ROOT.'/product/stock/movement_list.php?search_ref='.$tmpstockmovement->id.'">'.img_picto($langs->trans("StockMovement"), 'movement', 'class="paddingright"').'</a>';
1365  print dol_print_date($line2['date'], 'dayhour', 'tzuserrel');
1366  print '</td>';
1367  // Qty
1368  print '<td></td>';
1369  // Cost price
1370  if ($permissiontoupdatecost) {
1371  print '<td></td>';
1372  }
1373  // Already produced
1374  print '<td class="right">'.$line2['qty'].'</td>';
1375  // Warehouse
1376  print '<td class="tdoverflowmax150">';
1377  if ($line2['fk_warehouse'] > 0) {
1378  $result = $tmpwarehouse->fetch($line2['fk_warehouse']);
1379  if ($result > 0) {
1380  print $tmpwarehouse->getNomUrl(1);
1381  }
1382  }
1383  print '</td>';
1384  // Lot
1385  if (isModEnabled('productbatch')) {
1386  print '<td>';
1387  if ($line2['batch'] != '') {
1388  $tmpbatch->fetch(0, $line2['fk_product'], $line2['batch']);
1389  print $tmpbatch->getNomUrl(1);
1390  }
1391  print '</td>';
1392 
1393  // Split
1394  print '<td></td>';
1395 
1396  // Split All
1397  print '<td></td>';
1398  }
1399  // Action delete
1400  if ($permissiontodelete) {
1401  print '<td></td>';
1402  }
1403  print '</tr>';
1404  }
1405 
1406  if (in_array($action, array('consumeorproduce', 'consumeandproduceall'))) {
1407  print '<!-- Enter line to produce -->'."\n";
1408  $maxQty = 1;
1409  print '<tr data-max-qty="'.$maxQty.'" name="batch_'.$line->id.'_'.$i.'">';
1410  // Product
1411  print '<td><span class="opacitymedium">'.$langs->trans("ToProduce").'</span></td>';
1412  $preselected = (GETPOSTISSET('qtytoproduce-'.$line->id.'-'.$i) ? GETPOST('qtytoproduce-'.$line->id.'-'.$i) : max(0, $line->qty - $alreadyproduced));
1413  if ($action == 'consumeorproduce' && !GETPOSTISSET('qtytoproduce-'.$line->id.'-'.$i)) {
1414  $preselected = 0;
1415  }
1416  // Qty
1417  print '<td class="right"><input type="text" class="width50 right" id="qtytoproduce-'.$line->id.'-'.$i.'" name="qtytoproduce-'.$line->id.'-'.$i.'" value="'.$preselected.'"></td>';
1418  // Cost
1419  if ($permissiontoupdatecost) {
1420  // Defined $manufacturingcost
1421  $manufacturingcost = 0;
1422  $manufacturingcostsrc = '';
1423  if ($object->mrptype == 0) { // If MO is a "Manufacture" type (and not "Disassemble")
1424  $manufacturingcost = $bomcostupdated;
1425  $manufacturingcostsrc = $langs->trans("CalculatedFromProductsToConsume");
1426  if (empty($manufacturingcost)) {
1427  $manufacturingcost = $bomcost;
1428  $manufacturingcostsrc = $langs->trans("ValueFromBom");
1429  }
1430  if (empty($manufacturingcost)) {
1431  $manufacturingcost = price2num($tmpproduct->cost_price, 'MU');
1432  $manufacturingcostsrc = $langs->trans("CostPrice");
1433  }
1434  if (empty($manufacturingcost)) {
1435  $manufacturingcost = price2num($tmpproduct->pmp, 'MU');
1436  $manufacturingcostsrc = $langs->trans("PMPValue");
1437  }
1438  }
1439 
1440  if ($tmpproduct->type == Product::TYPE_PRODUCT || !empty($conf->global->STOCK_SUPPORTS_SERVICES)) {
1441  $preselected = (GETPOSTISSET('pricetoproduce-'.$line->id.'-'.$i) ? GETPOST('pricetoproduce-'.$line->id.'-'.$i) : ($manufacturingcost ? price($manufacturingcost) : ''));
1442  print '<td class="right"><input type="text" class="width75 right" name="pricetoproduce-'.$line->id.'-'.$i.'" value="'.$preselected.'"></td>';
1443  } else {
1444  print '<td><input type="hidden" class="width50 right" name="pricetoproduce-'.$line->id.'-'.$i.'" value="'.($manufacturingcost ? $manufacturingcost : '').'"></td>';
1445  }
1446  }
1447  // Already produced
1448  print '<td></td>';
1449  // Warehouse
1450  print '<td>';
1451  if ($tmpproduct->type == Product::TYPE_PRODUCT || !empty($conf->global->STOCK_SUPPORTS_SERVICES)) {
1452  $preselected = (GETPOSTISSET('idwarehousetoproduce-'.$line->id.'-'.$i) ? GETPOST('idwarehousetoproduce-'.$line->id.'-'.$i) : ($object->fk_warehouse > 0 ? $object->fk_warehouse : 'ifone'));
1453  print $formproduct->selectWarehouses($preselected, 'idwarehousetoproduce-'.$line->id.'-'.$i, '', 1, 0, $line->fk_product, '', 1, 0, null, 'maxwidth200 csswarehouse_'.$line->id.'_'.$i);
1454  } else {
1455  print '<span class="opacitymedium">'.$langs->trans("NoStockChangeOnServices").'</span>';
1456  }
1457  print '</td>';
1458  // Lot
1459  if (isModEnabled('productbatch')) {
1460  print '<td>';
1461  if ($tmpproduct->status_batch) {
1462  $preselected = (GETPOSTISSET('batchtoproduce-'.$line->id.'-'.$i) ? GETPOST('batchtoproduce-'.$line->id.'-'.$i) : '');
1463  print '<input type="text" class="width50" name="batchtoproduce-'.$line->id.'-'.$i.'" value="'.$preselected.'">';
1464  }
1465  print '</td>';
1466  // Batch number in same column than the stock movement picto
1467  if ($tmpproduct->status_batch) {
1468  $type = 'batch';
1469  print '<td align="right" class="split">';
1470  print img_picto($langs->trans('AddStockLocationLine'), 'split.png', 'class="splitbutton" onClick="addDispatchLine('.$line->id.', \''.$type.'\', \'qtymissing\')"');
1471  print '</td>';
1472 
1473  print '<td align="right" class="splitall">';
1474  if (($action == 'consumeorproduce' || $action == 'consumeandproduceall') && $tmpproduct->status_batch == 2) print img_picto($langs->trans('SplitAllQuantity'), 'split.png', 'class="splitbutton splitallbutton field-error-icon" onClick="addDispatchLine('.$line->id.', \'batch\', \'alltoproduce\')"'); //
1475  print '</td>';
1476  } else {
1477  print '<td></td>';
1478 
1479  print '<td></td>';
1480  }
1481  }
1482 
1483  // Action delete
1484  print '<td></td>';
1485 
1486  print '</tr>';
1487  }
1488  }
1489  }
1490  }
1491 
1492  print '</table>';
1493  print '</div>';
1494 
1495  print '</div>';
1496  print '</div>';
1497  }
1498 
1499  if (in_array($action, array('consumeorproduce', 'consumeandproduceall', 'addconsumeline'))) {
1500  print "</form>\n";
1501  }
1502 }
1503 
1504 // End of page
1505 llxFooter();
1506 $db->close();
if(GETPOST('button_removefilter_x', 'alpha')||GETPOST('button_removefilter.x', 'alpha')||GETPOST('button_removefilter', 'alpha')) if(GETPOST('button_search_x', 'alpha')||GETPOST('button_search.x', 'alpha')||GETPOST('button_search', 'alpha')) if($action=="save" &&empty($cancel)) $help_url
View.
Definition: agenda.php:118
if(!defined('NOREQUIRESOC')) if(!defined('NOREQUIRETRAN')) if(!defined('NOTOKENRENEWAL')) if(!defined('NOREQUIREMENU')) if(!defined('NOREQUIREHTML')) if(!defined('NOREQUIREAJAX')) llxHeader()
Empty header.
Definition: wrapper.php:56
llxFooter()
Empty footer.
Definition: wrapper.php:70
$object ref
Definition: info.php:78
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:36
Class MoLine.
Definition: mo.class.php:1609
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.
if($cancel &&! $id) if($action=='add' &&! $cancel) if($action=='delete') if($id) $form
Actions.
Definition: card.php:143
dol_banner_tab($object, $paramid, $morehtml='', $shownav=1, $fieldid='rowid', $fieldref='ref', $morehtmlref='', $moreparam='', $nodbprefix=0, $morehtmlleft='', $morehtmlstatus='', $onlybanner=0, $morehtmlright='')
Show tab footer of a card.
load_fiche_titre($titre, $morehtmlright='', $picto='generic', $pictoisfullpath=0, $id='', $morecssontable='', $morehtmlcenter='')
Load a title with picto.
dol_get_fiche_head($links=array(), $active='', $title='', $notab=0, $picto='', $pictoisfullpath=0, $morehtmlright='', $morecss='', $limittoshow=0, $moretabssuffix='')
Show tabs of a record.
img_warning($titlealt='default', $moreatt='', $morecss='pictowarning')
Show warning logo.
yn($yesno, $case=1, $color=0)
Return yes or no in current language.
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.
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='')
Set event messages in dol_events session object.
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_print_date($time, $format='', $tzoutput='auto', $outputlangs='', $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
if(!function_exists('dol_getprefix')) dol_include_once($relpath, $classname='')
Make an include_once using default root and alternate root if it fails.
dol_now($mode='auto')
Return date for now.
getDolGlobalInt($key, $default=0)
Return dolibarr global constant int value.
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2)
Show picto whatever it's its name (generic function)
dol_escape_js($stringtoescape, $mode=0, $noescapebackslashn=0)
Returns text escaped for inclusion into javascript code.
newToken()
Return the value of token currently saved into session with name 'newtoken'.
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.
GETPOSTISSET($paramname)
Return true if we are in a context of submitting the parameter $paramname from a POST of a form.
isModEnabled($module)
Is Dolibarr module enabled.
img_edit($titlealt='default', $float=0, $other='')
Show logo editer/modifier fiche.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
$formconfirm
if ($action == 'delbookkeepingyear') {
moPrepareHead($object)
Prepare array of tabs for Mo.
Definition: mrp_mo.lib.php:30
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.