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