dolibarr 21.0.3
dispatch.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2004-2006 Rodolphe Quiedeville <rodolphe@quiedeville.org>
3 * Copyright (C) 2004-2023 Laurent Destailleur <eldy@users.sourceforge.net>
4 * Copyright (C) 2005 Eric Seigne <eric.seigne@ryxeo.com>
5 * Copyright (C) 2005-2009 Regis Houssin <regis.houssin@inodbox.com>
6 * Copyright (C) 2010-2021 Juanjo Menent <jmenent@2byte.es>
7 * Copyright (C) 2014 Cedric Gross <c.gross@kreiz-it.fr>
8 * Copyright (C) 2016 Florian Henry <florian.henry@atm-consulting.fr>
9 * Copyright (C) 2017-2022 Ferran Marcet <fmarcet@2byte.es>
10 * Copyright (C) 2018-2024 Frédéric France <frederic.france@free.fr>
11 * Copyright (C) 2019-2020 Christophe Battarel <christophe@altairis.fr>
12 * Copyright (C) 2024 MDW <mdeweerd@users.noreply.github.com>
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 3 of the License, or
17 * (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program. If not, see <https://www.gnu.org/licenses/>.
26 */
27
34// Load Dolibarr environment
35require '../../main.inc.php';
36require_once DOL_DOCUMENT_ROOT.'/core/modules/supplier_order/modules_commandefournisseur.php';
37require_once DOL_DOCUMENT_ROOT.'/product/stock/class/entrepot.class.php';
38require_once DOL_DOCUMENT_ROOT.'/core/lib/fourn.lib.php';
39require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.commande.class.php';
40require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.commande.dispatch.class.php';
41require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php';
42require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
43require_once DOL_DOCUMENT_ROOT.'/product/stock/class/productlot.class.php';
44
45if (isModEnabled('project')) {
46 require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
47}
48
57// Load translation files required by the page
58$langs->loadLangs(array("bills", "orders", "sendings", "companies", "deliveries", "products", "stocks", "receptions"));
59
60if (isModEnabled('productbatch')) {
61 $langs->load('productbatch');
62}
63
64// Security check
65$id = GETPOSTINT("id");
66$ref = GETPOST('ref');
67$lineid = GETPOSTINT('lineid');
68$action = GETPOST('action', 'aZ09');
69$fk_default_warehouse = GETPOSTINT('fk_default_warehouse');
70$cancel = GETPOST('cancel', 'alpha');
71$confirm = GETPOST('confirm', 'alpha');
72
73if ($user->socid) {
74 $socid = $user->socid;
75}
76
77$hookmanager->initHooks(array('ordersupplierdispatch'));
78
79// Recuperation de l'id de projet
80$projectid = 0;
81if (GETPOSTISSET("projectid")) {
82 $projectid = GETPOSTINT("projectid");
83}
84
86
87if ($id > 0 || !empty($ref)) {
88 $result = $object->fetch($id, $ref);
89 if ($result < 0) {
90 setEventMessages($object->error, $object->errors, 'errors');
91 }
92 $result = $object->fetch_thirdparty();
93 if ($result < 0) {
94 setEventMessages($object->error, $object->errors, 'errors');
95 }
96}
97
98if (empty($conf->reception->enabled)) {
99 $permissiontoreceive = $user->hasRight("fournisseur", "commande", "receptionner");
100 $permissiontocontrol = ((!getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && $user->hasRight("fournisseur", "commande", "receptionner")) || (getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && $user->hasRight("fournisseur", "commande_advance", "check")));
101} else {
102 $permissiontoreceive = $user->hasRight("reception", "creer");
103 $permissiontocontrol = ((!getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && $user->hasRight("reception", "creer")) || (getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && $user->hasRight("reception", "reception_advance", "validate")));
104}
105
106// $id is id of a purchase order.
107$result = restrictedArea($user, 'fournisseur', $object, 'commande_fournisseur', 'commande');
108
109if (!isModEnabled('stock')) {
111}
112
113$usercancreate = ($user->hasRight("fournisseur", "commande", "creer") || $user->hasRight("supplier_order", "creer"));
114$permissiontoadd = $usercancreate; // Used by the include of actions_addupdatedelete.inc.php
115
116
117/*
118 * Actions
119 */
120
121$error = 0;
122$errors = [];
123$parameters = array();
124$reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
125if ($reshook < 0) {
126 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
127}
128
129if ($action == 'checkdispatchline' && $permissiontocontrol) {
130 $supplierorderdispatch = new CommandeFournisseurDispatch($db);
131
132 $db->begin();
133
134 $result = $supplierorderdispatch->fetch($lineid);
135 if (!$result) {
136 $error++;
137 setEventMessages($supplierorderdispatch->error, $supplierorderdispatch->errors, 'errors');
138 $action = '';
139 }
140
141 if (!$error) {
142 $result = $supplierorderdispatch->setStatut(1);
143 if ($result < 0) {
144 setEventMessages($supplierorderdispatch->error, $supplierorderdispatch->errors, 'errors');
145 $error++;
146 $action = '';
147 }
148 }
149
150 if (!$error) {
151 $result = $object->calcAndSetStatusDispatch($user);
152 if ($result < 0) {
153 setEventMessages($object->error, $object->errors, 'errors');
154 $error++;
155 $action = '';
156 }
157 }
158 if (!$error) {
159 $db->commit();
160 } else {
161 $db->rollback();
162 }
163}
164
165if ($action == 'uncheckdispatchline' && $permissiontocontrol) {
166 $supplierorderdispatch = new CommandeFournisseurDispatch($db);
167
168 $db->begin();
169
170 $result = $supplierorderdispatch->fetch($lineid);
171 if (!$result) {
172 $error++;
173 setEventMessages($supplierorderdispatch->error, $supplierorderdispatch->errors, 'errors');
174 $action = '';
175 }
176
177 if (!$error) {
178 $result = $supplierorderdispatch->setStatut(0);
179 if ($result < 0) {
180 setEventMessages($supplierorderdispatch->error, $supplierorderdispatch->errors, 'errors');
181 $error++;
182 $action = '';
183 }
184 }
185 if (!$error) {
186 $result = $object->calcAndSetStatusDispatch($user);
187 if ($result < 0) {
188 setEventMessages($object->error, $object->errors, 'errors');
189 $error++;
190 $action = '';
191 }
192 }
193 if (!$error) {
194 $db->commit();
195 } else {
196 $db->rollback();
197 }
198}
199
200if ($action == 'denydispatchline' && $permissiontocontrol) {
201 $supplierorderdispatch = new CommandeFournisseurDispatch($db);
202
203 $db->begin();
204
205 $result = $supplierorderdispatch->fetch($lineid);
206 if (!$result) {
207 $error++;
208 setEventMessages($supplierorderdispatch->error, $supplierorderdispatch->errors, 'errors');
209 $action = '';
210 }
211
212 if (!$error) {
213 $result = $supplierorderdispatch->setStatut(2);
214 if ($result < 0) {
215 setEventMessages($supplierorderdispatch->error, $supplierorderdispatch->errors, 'errors');
216 $error++;
217 $action = '';
218 }
219 }
220 if (!$error) {
221 $result = $object->calcAndSetStatusDispatch($user);
222 if ($result < 0) {
223 setEventMessages($object->error, $object->errors, 'errors');
224 $error++;
225 $action = '';
226 }
227 }
228 if (!$error) {
229 $db->commit();
230 } else {
231 $db->rollback();
232 }
233}
234
235$saveprice = "savepriceIsNotSet";
236if ($action == 'dispatch' && $permissiontoreceive) {
237 $notrigger = 0;
238
239 $db->begin();
240
241 $pos = 0;
242 foreach ($_POST as $key => $value) {
243 // without batch module enabled
244 $reg = array();
245 if (preg_match('/^product_([0-9]+)_([0-9]+)$/i', $key, $reg)) {
246 $pos++;
247
248 // $numline=$reg[2] + 1; // line of product
249 $numline = $pos;
250 $prod = "product_".$reg[1].'_'.$reg[2];
251 $qty = "qty_".$reg[1].'_'.$reg[2];
252 $ent = "entrepot_".$reg[1].'_'.$reg[2];
253 if (empty(GETPOST($ent))) {
254 $ent = $fk_default_warehouse;
255 }
256 $pu = "pu_".$reg[1].'_'.$reg[2]; // This is unit price including discount
257 $fk_commandefourndet = "fk_commandefourndet_".$reg[1].'_'.$reg[2];
258
259 if (getDolGlobalString('SUPPLIER_ORDER_CAN_UPDATE_BUYINGPRICE_DURING_RECEIPT')) {
260 if (!isModEnabled("multicurrency") && empty($conf->dynamicprices->enabled)) {
261 $dto = GETPOSTINT("dto_".$reg[1].'_'.$reg[2]);
262 if (!empty($dto)) {
263 $unit_price = price2num((float) GETPOST("pu_".$reg[1]) * (100 - $dto) / 100, 'MU');
264 }
265 $saveprice = "saveprice_".$reg[1].'_'.$reg[2];
266 }
267 }
268
269 // We ask to move a qty
270 $qtytomove = GETPOSTFLOAT($qty);
271 $puformove = GETPOSTFLOAT($pu);
272 if ($qtytomove != 0) {
273 if (!(GETPOSTINT($ent) > 0)) {
274 dol_syslog('No dispatch for line '.$key.' as no warehouse was chosen.');
275 $text = $langs->transnoentities('Warehouse').', '.$langs->transnoentities('Line').' '.($numline);
276 setEventMessages($langs->trans('ErrorFieldRequired', $text), null, 'errors');
277 $error++;
278 }
279
280 if (!$error) {
281 $result = $object->dispatchProduct($user, GETPOSTINT($prod), $qtytomove, GETPOSTINT($ent), $puformove, GETPOST('comment'), '', '', '', GETPOSTINT($fk_commandefourndet), $notrigger);
282 if ($result < 0) {
283 setEventMessages($object->error, $object->errors, 'errors');
284 $error++;
285 }
286
287 if (!$error && getDolGlobalString('SUPPLIER_ORDER_CAN_UPDATE_BUYINGPRICE_DURING_RECEIPT')) {
288 if (!isModEnabled("multicurrency") && empty($conf->dynamicprices->enabled)) {
289 $dto = price2num(GETPOSTINT("dto_".$reg[1].'_'.$reg[2]), '');
290 if (empty($dto)) {
291 $dto = 0;
292 }
293
294 //update supplier price
295 if (GETPOSTISSET($saveprice)) {
296 // TODO Use class
297 $sql = "UPDATE ".MAIN_DB_PREFIX."product_fournisseur_price";
298 $sql .= " SET unitprice='".price2num(GETPOST($pu), 'MU')."'";
299 $sql .= ", price=".price2num(GETPOST($pu), 'MU')."*quantity";
300 $sql .= ", remise_percent = ".((float) $dto);
301 $sql .= " WHERE fk_soc=".((int) $object->socid);
302 $sql .= " AND fk_product=".(GETPOSTINT($prod));
303
304 $resql = $db->query($sql);
305 }
306 }
307 }
308 }
309 }
310 }
311 // with batch module enabled
312 if (preg_match('/^product_batch_([0-9]+)_([0-9]+)$/i', $key, $reg)) {
313 $pos++;
314
315 // eat-by date dispatch
316 // $numline=$reg[2] + 1; // line of product
317 $numline = $pos;
318 $prod = 'product_batch_'.$reg[1].'_'.$reg[2];
319 $qty = 'qty_'.$reg[1].'_'.$reg[2];
320 $ent = 'entrepot_'.$reg[1].'_'.$reg[2];
321 $pu = 'pu_'.$reg[1].'_'.$reg[2];
322 $fk_commandefourndet = 'fk_commandefourndet_'.$reg[1].'_'.$reg[2];
323 $lot = 'lot_number_'.$reg[1].'_'.$reg[2];
324 $dDLUO = dol_mktime(12, 0, 0, GETPOSTINT('dluo_'.$reg[1].'_'.$reg[2].'month'), GETPOSTINT('dluo_'.$reg[1].'_'.$reg[2].'day'), GETPOSTINT('dluo_'.$reg[1].'_'.$reg[2].'year'));
325 $dDLC = dol_mktime(12, 0, 0, GETPOSTINT('dlc_'.$reg[1].'_'.$reg[2].'month'), GETPOSTINT('dlc_'.$reg[1].'_'.$reg[2].'day'), GETPOSTINT('dlc_'.$reg[1].'_'.$reg[2].'year'));
326
327 $fk_commandefourndet = 'fk_commandefourndet_'.$reg[1].'_'.$reg[2];
328
329 if (getDolGlobalString('SUPPLIER_ORDER_CAN_UPDATE_BUYINGPRICE_DURING_RECEIPT')) {
330 if (!isModEnabled("multicurrency") && empty($conf->dynamicprices->enabled)) {
331 $dto = GETPOSTINT("dto_".$reg[1].'_'.$reg[2]);
332 if (!empty($dto)) {
333 $unit_price = price2num((float) GETPOST("pu_".$reg[1]) * (100 - $dto) / 100, 'MU');
334 }
335 $saveprice = "saveprice_".$reg[1].'_'.$reg[2];
336 }
337 }
338
339 // We ask to move a qty
340 $qtytomove = GETPOSTFLOAT($qty);
341 $puformove = GETPOSTFLOAT($pu);
342 if ($qtytomove > 0) {
343 $productId = GETPOSTINT($prod);
344
345 if (!(GETPOSTINT($ent) > 0)) {
346 dol_syslog('No dispatch for line '.$key.' as no warehouse was chosen.');
347 $text = $langs->transnoentities('Warehouse').', '.$langs->transnoentities('Line').' '.($numline).'-'.((int) $reg[1] + 1);
348 setEventMessages($langs->trans('ErrorFieldRequired', $text), null, 'errors');
349 $error++;
350 }
351
352 // check sell-by / eat-by date is mandatory
353 /* Not required. Mandatory is checked when we insert the lot. Once lot has been recorded and is known, user can just enter the lot/serial
354 $errorMsgArr = Productlot::checkSellOrEatByMandatoryFromProductIdAndDates($productId, $dDLC, $dDLUO);
355 if (!(GETPOST($lot, 'alpha')) || !empty($errorMsgArr)) {
356 dol_syslog('No dispatch for line '.$key.' as serial/eat-by/sellby date are not set');
357 $text = $langs->transnoentities('atleast1batchfield').', '.$langs->transnoentities('Line').' '.($numline).'-'.($reg[1] + 1);
358 setEventMessages($langs->trans('ErrorFieldRequired', $text), null, 'errors');
359 $error++;
360 }*/
361 if (!GETPOST($lot, 'alpha') && !$dDLUO && !$dDLC) {
362 dol_syslog('No dispatch for line '.$key.' as serial/eat-by/sellby date are not set');
363 $text = $langs->transnoentities('atleast1batchfield').', '.$langs->transnoentities('Line').' '.($numline).'-'.((int) $reg[1] + 1);
364 setEventMessages($langs->trans('ErrorFieldRequired', $text), null, 'errors');
365 $error++;
366 }
367
368 if (!$error) {
369 $result = $object->dispatchProduct($user, $productId, $qtytomove, GETPOSTINT($ent), $puformove, GETPOST('comment'), $dDLUO, $dDLC, GETPOST($lot, 'alpha'), GETPOSTINT($fk_commandefourndet), $notrigger);
370 if ($result < 0) {
371 setEventMessages($object->error, $object->errors, 'errors');
372 $error++;
373 }
374
375 if (!$error && getDolGlobalString('SUPPLIER_ORDER_CAN_UPDATE_BUYINGPRICE_DURING_RECEIPT')) {
376 if (!isModEnabled("multicurrency") && empty($conf->dynamicprices->enabled)) {
377 $dto = GETPOSTINT("dto_".$reg[1].'_'.$reg[2]);
378 //update supplier price
379 if (GETPOSTISSET($saveprice)) {
380 // TODO Use class
381 $sql = "UPDATE ".MAIN_DB_PREFIX."product_fournisseur_price";
382 $sql .= " SET unitprice = ".price2num(GETPOST($pu), 'MU', 2);
383 $sql .= ", price = ".price2num(GETPOST($pu), 'MU', 2)." * quantity";
384 $sql .= ", remise_percent = ".price2num((empty($dto) ? 0 : $dto), 3, 2)."'";
385 $sql .= " WHERE fk_soc = ".((int) $object->socid);
386 $sql .= " AND fk_product=".((int) $productId);
387
388 $resql = $db->query($sql);
389 }
390 }
391 }
392 }
393 }
394 }
395 }
396
397 if (!$error) {
398 $result = $object->calcAndSetStatusDispatch($user, GETPOST('closeopenorder') ? 1 : 0, GETPOST('comment'));
399 if ($result < 0) {
400 setEventMessages($object->error, $object->errors, 'errors');
401 $error++;
402 }
403 }
404
405 if ($result >= 0 && !$error) {
406 $db->commit();
407
408 setEventMessages($langs->trans("ReceptionsRecorded"), null, 'mesgs');
409
410 header("Location: dispatch.php?id=".$id);
411 exit();
412 } else {
413 $db->rollback();
414 }
415}
416
417$batch = '';
418$eatby = null;
419$sellby = 0;
420$qty = 0;
421$price = '0';
422$entrepot = 0;
423
424// Remove a dispatched line
425if ($action == 'confirm_deleteline' && $confirm == 'yes' && $permissiontoreceive) {
426 $db->begin();
427
428 $supplierorderdispatch = new CommandeFournisseurDispatch($db);
429 $result = $supplierorderdispatch->fetch($lineid);
430 if ($result > 0) {
431 $qty = $supplierorderdispatch->qty;
432 $entrepot = $supplierorderdispatch->fk_entrepot;
433 $product = $supplierorderdispatch->fk_product;
434 $price = price2num(GETPOST('price', 'alpha'), 'MU');
435 $comment = $supplierorderdispatch->comment;
436 $eatby = $supplierorderdispatch->eatby;
437 $sellby = $supplierorderdispatch->sellby;
438 $batch = $supplierorderdispatch->batch;
439
440 $result = $supplierorderdispatch->delete($user);
441 }
442 if ($result < 0) {
443 $errors = $object->errors;
444 $error++;
445 } else {
446 // If module stock is enabled and the stock increase is done on purchase order dispatching
447 if ($entrepot > 0 && isModEnabled('stock') && getDolGlobalString('STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER') && empty($supplierorderdispatch->fk_reception)) {
448 $mouv = new MouvementStock($db);
449 if ($product > 0) {
450 $mouv->origin = &$object;
451 $mouv->setOrigin($object->element, $object->id);
452 $result = $mouv->livraison($user, $product, $entrepot, $qty, $price, $comment, '', $eatby, $sellby, $batch);
453 if ($result < 0) {
454 $errors = $mouv->errors;
455 $error++;
456 }
457 }
458 }
459 }
460 if ($error > 0) {
461 $db->rollback();
462 setEventMessages(null, $errors, 'errors');
463 } else {
464 $db->commit();
465 }
466}
467
468// Update a dispatched line
469if ($action == 'updateline' && $permissiontoreceive && empty($cancel)) {
470 $db->begin();
471
472 $supplierorderdispatch = new CommandeFournisseurDispatch($db);
473 $result = $supplierorderdispatch->fetch($lineid);
474 if ($result > 0) {
475 $qty = $supplierorderdispatch->qty;
476 $entrepot = $supplierorderdispatch->fk_entrepot;
477 $product = $supplierorderdispatch->fk_product;
478 $price = GETPOSTFLOAT('price');
479 $comment = $supplierorderdispatch->comment;
480 $eatby = $supplierorderdispatch->eatby;
481 $sellby = $supplierorderdispatch->sellby;
482 $batch = $supplierorderdispatch->batch;
483
484 $supplierorderdispatch->qty = GETPOSTFLOAT('qty', 'MS');
485 $supplierorderdispatch->fk_entrepot = GETPOSTINT('fk_entrepot');
486 $result = $supplierorderdispatch->update($user);
487 }
488 if ($result < 0) {
489 $error++;
490 $errors = $supplierorderdispatch->errors;
491 } else {
492 // If module stock is enabled and the stock increase is done on purchase order dispatching
493 if ($entrepot > 0 && isModEnabled('stock') && getDolGlobalString('STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER')) {
494 $mouv = new MouvementStock($db);
495 if ($product > 0) {
496 $mouv->origin = &$object;
497 $mouv->setOrigin($object->element, $object->id);
498 $result = $mouv->livraison($user, $product, $entrepot, $qty, $price, $comment, '', $eatby, $sellby, $batch);
499 if ($result < 0) {
500 $errors = $mouv->errors;
501 $error++;
502 } else {
503 $mouv->origin = &$object;
504 $result = $mouv->reception($user, $product, $supplierorderdispatch->fk_entrepot, $supplierorderdispatch->qty, $price, $comment, $eatby, $sellby, $batch);
505 if ($result < 0) {
506 $errors = $mouv->errors;
507 $error++;
508 }
509 }
510 }
511 }
512 }
513 if ($error > 0) {
514 $db->rollback();
515 setEventMessages($langs->trans("Error"), $errors, 'errors');
516 } else {
517 $db->commit();
518 }
519}
520
521
522/*
523 * View
524 */
525
526$now = dol_now();
527
528$form = new Form($db);
529$formproduct = new FormProduct($db);
530$warehouse_static = new Entrepot($db);
531$supplierorderdispatch = new CommandeFournisseurDispatch($db);
532
533$title = $object->ref." - ".$langs->trans('OrderDispatch');
534$help_url = 'EN:Module_Suppliers_Orders|FR:CommandeFournisseur|ES:Módulo_Pedidos_a_proveedores';
535$morejs = array('/fourn/js/lib_dispatch.js.php');
536
537llxHeader('', $title, $help_url, '', 0, 0, $morejs, '', '', 'mod-supplier-order page-card_dispatch');
538
539if ($id > 0 || !empty($ref)) {
540 $soc = new Societe($db);
541 $soc->fetch($object->socid);
542
543 $author = new User($db);
544 $author->fetch($object->user_author_id);
545
546 $head = ordersupplier_prepare_head($object);
547
548 $title = $langs->trans("SupplierOrder");
549 print dol_get_fiche_head($head, 'dispatch', $title, -1, 'order');
550
551 $formconfirm = '';
552
553 // Confirmation to delete line
554 if ($action == 'ask_deleteline') {
555 $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id.'&lineid='.$lineid, $langs->trans('DeleteLine'), $langs->trans('ConfirmDeleteLine'), 'confirm_deleteline', '', 0, 1);
556 }
557
558 // Call Hook formConfirm
559 $parameters = array('lineid' => $lineid);
560 // Note that $action and $object may be modified by hook
561 $reshook = $hookmanager->executeHooks('formConfirm', $parameters, $object, $action);
562 if (empty($reshook)) {
563 $formconfirm .= $hookmanager->resPrint;
564 } elseif ($reshook > 0) {
565 $formconfirm = $hookmanager->resPrint;
566 }
567
568 // Print form confirm
569 print $formconfirm;
570
571 // Supplier order card
572
573 $linkback = '<a href="'.DOL_URL_ROOT.'/fourn/commande/list.php'.(!empty($socid) ? '?socid='.$socid : '').'">'.$langs->trans("BackToList").'</a>';
574
575 $morehtmlref = '<div class="refidno">';
576 // Ref supplier
577 $morehtmlref .= $form->editfieldkey("RefSupplier", 'ref_supplier', $object->ref_supplier, $object, 0, 'string', '', 0, 1);
578 $morehtmlref .= $form->editfieldval("RefSupplier", 'ref_supplier', $object->ref_supplier, $object, 0, 'string', '', null, null, '', 1);
579 // Thirdparty
580 $morehtmlref .= '<br>'.$object->thirdparty->getNomUrl(1);
581 // Project
582 if (isModEnabled('project')) {
583 $langs->load("projects");
584 $morehtmlref .= '<br>';
585 if (0) {
586 $caneditproject = false; // For static analysis
587 $morehtmlref .= img_picto($langs->trans("Project"), 'project', 'class="pictofixedwidth"');
588 if ($action != 'classify' && $caneditproject) {
589 $morehtmlref .= '<a class="editfielda" href="'.$_SERVER['PHP_SELF'].'?action=classify&token='.newToken().'&id='.$object->id.'">'.img_edit($langs->transnoentitiesnoconv('SetProject')).'</a> ';
590 }
591 $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'].'?id='.$object->id, (!getDolGlobalString('PROJECT_CAN_ALWAYS_LINK_TO_ALL_SUPPLIERS') ? $object->socid : -1), $object->fk_project, ($action == 'classify' ? 'projectid' : 'none'), 0, 0, 0, 1, '', 'maxwidth300');
592 } else {
593 if (!empty($object->fk_project)) {
594 $proj = new Project($db);
595 $proj->fetch($object->fk_project);
596 $morehtmlref .= $proj->getNomUrl(1);
597 if ($proj->title) {
598 $morehtmlref .= '<span class="opacitymedium"> - '.dol_escape_htmltag($proj->title).'</span>';
599 }
600 }
601 }
602 }
603 $morehtmlref .= '</div>';
604
605
606 dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref);
607
608
609 print '<div class="fichecenter">';
610 print '<div class="underbanner clearboth"></div>';
611
612 print '<table class="border tableforfield" width="100%">';
613
614 // Date
615 if ($object->methode_commande_id > 0) {
616 print '<tr><td class="titlefield">'.$langs->trans("Date").'</td><td>';
617 if ($object->date_commande) {
618 print dol_print_date($object->date_commande, "dayhour")."\n";
619 }
620 print "</td></tr>";
621
622 if ($object->methode_commande) {
623 print '<tr><td>'.$langs->trans("Method").'</td><td>'.$object->getInputMethod().'</td></tr>';
624 }
625 }
626
627 // Author
628 print '<tr><td class="titlefield">'.$langs->trans("AuthorRequest").'</td>';
629 print '<td>'.$author->getNomUrl(1, '', 0, 0, 0).'</td>';
630 print '</tr>';
631
632 $parameters = array();
633 $reshook = $hookmanager->executeHooks('formObjectOptions', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
634
635 print "</table>";
636
637 print '</div>';
638
639 // if ($mesg) print $mesg;
640 print '<br>';
641
642 $disabled = 0; // This is used to disable or not the bulk selection of target warehouse. No reason to have it disabled so forced to 0.
643
644 // Line of orders
646 print '<br><span class="opacitymedium">'.$langs->trans("OrderStatusNotReadyToDispatch").'</span>';
647 }
648
649
650 print '<br>';
651
652 $listwarehouses = array();
653
657 require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php';
658 $formproduct = new FormProduct($db);
659 $formproduct->loadWarehouses();
660 $entrepot = new Entrepot($db);
661 $listwarehouses = $entrepot->list_array(1);
662
663
664 if (empty($conf->reception->enabled)) {
665 print '<form method="POST" action="dispatch.php?id='.$object->id.'">';
666 } else {
667 print '<form method="post" action="'.dol_buildpath('/reception/card.php', 1).'?originid='.$object->id.'&origin=supplierorder">';
668 }
669
670 print '<input type="hidden" name="token" value="'.newToken().'">';
671 if (empty($conf->reception->enabled)) {
672 print '<input type="hidden" name="action" value="dispatch">';
673 } else {
674 print '<input type="hidden" name="action" value="create">';
675 }
676
677 print '<div class="div-table-responsive-no-min">';
678 print '<table class="noborder centpercent">';
679
680 // Set $products_dispatched with qty dispatched for each product id
681 $products_dispatched = array();
682 $sql = "SELECT l.rowid, cfd.fk_product, sum(cfd.qty) as qty";
683 $sql .= " FROM ".MAIN_DB_PREFIX."receptiondet_batch as cfd";
684 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."commande_fournisseurdet as l on l.rowid = cfd.fk_elementdet";
685 $sql .= " WHERE cfd.fk_element = ".((int) $object->id);
686 $sql .= " GROUP BY l.rowid, cfd.fk_product";
687
688 $resql = $db->query($sql);
689 if ($resql) {
690 $num = $db->num_rows($resql);
691 $i = 0;
692
693 if ($num) {
694 while ($i < $num) {
695 $objd = $db->fetch_object($resql);
696 $products_dispatched[$objd->rowid] = price2num($objd->qty, 'MS');
697 $i++;
698 }
699 }
700 $db->free($resql);
701 }
702
703 //$sql = "SELECT l.rowid, l.fk_product, l.subprice, l.remise_percent, l.ref AS sref, SUM(l.qty) as qty,";
704 $sql = "SELECT l.rowid, l.fk_product, l.subprice, l.remise_percent, l.ref AS sref, l.qty as qty,";
705 $sql .= " p.ref, p.label, p.tobatch, p.fk_default_warehouse";
706
707 // Enable hooks to alter the SQL query (SELECT)
708 $parameters = array();
709 $reshook = $hookmanager->executeHooks(
710 'printFieldListSelect',
711 $parameters,
712 $object,
713 $action
714 );
715 if ($reshook < 0) {
716 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
717 }
718 $sql .= $hookmanager->resPrint;
719
720 $sql .= " FROM ".MAIN_DB_PREFIX."commande_fournisseurdet as l";
721 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product as p ON l.fk_product=p.rowid";
722 $sql .= " WHERE l.fk_commande = ".((int) $object->id);
723 if (!getDolGlobalString('STOCK_SUPPORTS_SERVICES')) {
724 $sql .= " AND l.product_type = 0";
725 }
726
727 // Enable hooks to alter the SQL query (WHERE)
728 $parameters = array();
729 $reshook = $hookmanager->executeHooks(
730 'printFieldListWhere',
731 $parameters,
732 $object,
733 $action
734 );
735 if ($reshook < 0) {
736 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
737 }
738 $sql .= $hookmanager->resPrint;
739
740 //$sql .= " GROUP BY p.ref, p.label, p.tobatch, p.fk_default_warehouse, l.rowid, l.fk_product, l.subprice, l.remise_percent, l.ref"; // Calculation of amount dispatched is done per fk_product so we must group by fk_product
741 $sql .= " ORDER BY l.rang, p.ref, p.label";
742
743 // Nb of predefined product lines to dispatch (already done or not) if SUPPLIER_ORDER_DISABLE_STOCK_DISPATCH_WHEN_TOTAL_REACHED is off (default)
744 // or nb of line that remain to dispatch if SUPPLIER_ORDER_DISABLE_STOCK_DISPATCH_WHEN_TOTAL_REACHED is on.
745 $nbproduct = 0;
746
747 $resql = $db->query($sql);
748 if ($resql) {
749 $num = $db->num_rows($resql);
750 $i = 0;
751
752 if ($num) {
753 print '<tr class="liste_titre">';
754
755 print '<td>'.$langs->trans("Description").'</td>';
756 if (isModEnabled('productbatch')) {
757 print '<td class="dispatch_batch_number_title">'.$langs->trans("batch_number").'</td>';
758 if (!getDolGlobalString('PRODUCT_DISABLE_SELLBY')) {
759 print '<td class="dispatch_dlc_title">'.$langs->trans("SellByDate").'</td>';
760 }
761 if (!getDolGlobalString('PRODUCT_DISABLE_EATBY')) {
762 print '<td class="dispatch_dluo_title">'.$langs->trans("EatByDate").'</td>';
763 }
764 } else {
765 print '<td></td>';
766 print '<td></td>';
767 print '<td></td>';
768 }
769 print '<td class="right">'.$langs->trans("SupplierRef").'</td>';
770 print '<td class="right">'.$langs->trans("QtyOrdered").'</td>';
771 print '<td class="right">'.$langs->trans("QtyDispatchedShort").'</td>';
772 print ' <td class="right">'.$langs->trans("QtyToDispatchShort");
773 print '<br><a href="#" id="autoreset">'.img_picto($langs->trans("Reset"), 'eraser', 'class="pictofixedwidth opacitymedium"').$langs->trans("Reset").'</a></td>';
774 print '<td width="32"></td>';
775
776 if (getDolGlobalString('SUPPLIER_ORDER_CAN_UPDATE_BUYINGPRICE_DURING_RECEIPT')) {
777 if (!isModEnabled("multicurrency") && empty($conf->dynamicprices->enabled)) {
778 print '<td class="right">'.$langs->trans("Price").'</td>';
779 print '<td class="right">'.$langs->trans("ReductionShort").' (%)</td>';
780 print '<td class="right">'.$langs->trans("UpdatePrice").'</td>';
781 }
782 }
783
784 print '<td align="right">'.$langs->trans("Warehouse");
785
786 // Select warehouse to force it everywhere
787 if (count($listwarehouses) > 1) {
788 print '<br>'.$form->selectarray('fk_default_warehouse', $listwarehouses, $fk_default_warehouse, $langs->trans("ForceTo"), 0, 0, '', 0, 0, $disabled, '', 'minwidth100 maxwidth300', 1);
789 } elseif (count($listwarehouses) == 1) {
790 print '<br>'.$form->selectarray('fk_default_warehouse', $listwarehouses, $fk_default_warehouse, 0, 0, 0, '', 0, 0, $disabled, '', 'minwidth100 maxwidth300', 1);
791 }
792
793 print '</td>';
794
795 // Enable hooks to append additional columns
796 $parameters = array();
797 $reshook = $hookmanager->executeHooks(
798 'printFieldListTitle',
799 $parameters,
800 $object,
801 $action
802 );
803 if ($reshook < 0) {
804 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
805 }
806 print $hookmanager->resPrint;
807
808 print "</tr>\n";
809 }
810
811 $nbfreeproduct = 0; // Nb of lines of free products/services
812
813 $conf->cache['product'] = array();
814
815 // Loop on each source order line (may be more or less than current number of lines in llx_commande_fournisseurdet)
816 while ($i < $num) {
817 $objp = $db->fetch_object($resql);
818
819 // On n'affiche pas les produits libres
820 if (!$objp->fk_product > 0) {
821 $nbfreeproduct++;
822 } else {
823 $alreadydispatched = isset($products_dispatched[$objp->rowid]) ? $products_dispatched[$objp->rowid] : 0;
824 $remaintodispatch = price2num($objp->qty - ((float) $alreadydispatched), 5); // Calculation of dispatched
825 if ($remaintodispatch < 0 && !getDolGlobalString('SUPPLIER_ORDER_ALLOW_NEGATIVE_QTY_FOR_SUPPLIER_ORDER_RETURN')) {
826 $remaintodispatch = 0;
827 }
828
829 if ($remaintodispatch || !getDolGlobalString('SUPPLIER_ORDER_DISABLE_STOCK_DISPATCH_WHEN_TOTAL_REACHED')) {
830 $nbproduct++;
831
832 // To show detail cref and description value, we must make calculation by cref
833 // print ($objp->cref?' ('.$objp->cref.')':'');
834 // if ($objp->description) print '<br>'.nl2br($objp->description);
835 $suffix = '_0_'.$i;
836
837 print "\n";
838 print '<!-- Line to dispatch '.$suffix.' -->'."\n";
839 // hidden fields for js function
840 print '<input id="qty_ordered'.$suffix.'" type="hidden" value="'.$objp->qty.'">';
841 print '<input id="qty_dispatched'.$suffix.'" type="hidden" value="'.(float) $alreadydispatched.'">';
842 print '<tr class="oddeven">';
843
844 if (empty($conf->cache['product'][$objp->fk_product])) {
845 $tmpproduct = new Product($db);
846 $tmpproduct->fetch($objp->fk_product);
847 $conf->cache['product'][$objp->fk_product] = $tmpproduct;
848 } else {
849 $tmpproduct = $conf->cache['product'][$objp->fk_product];
850 }
851
852 $linktoprod = $tmpproduct->getNomUrl(1);
853 $linktoprod .= ' - '.$objp->label."\n";
854
855 if (isModEnabled('productbatch')) {
856 if ($objp->tobatch) {
857 // Product
858 print '<td>';
859 print $linktoprod;
860 print "</td>";
861 print '<td class="dispatch_batch_number"></td>';
862 if (!getDolGlobalString('PRODUCT_DISABLE_SELLBY')) {
863 print '<td class="dispatch_dlc"></td>';
864 }
865 if (!getDolGlobalString('PRODUCT_DISABLE_EATBY')) {
866 print '<td class="dispatch_dluo"></td>';
867 }
868 } else {
869 // Product
870 print '<td>';
871 print $linktoprod;
872 print "</td>";
873 print '<td class="dispatch_batch_number">';
874 print '<span class="opacitymedium small">'.$langs->trans("ProductDoesNotUseBatchSerial").'</small>';
875 print '</td>';
876 if (!getDolGlobalString('PRODUCT_DISABLE_SELLBY')) {
877 print '<td class="dispatch_dlc"></td>';
878 }
879 if (!getDolGlobalString('PRODUCT_DISABLE_EATBY')) {
880 print '<td class="dispatch_dluo"></td>';
881 }
882 }
883 } else {
884 print '<td colspan="4">';
885 print $linktoprod;
886 print "</td>";
887 }
888
889 // Define unit price for PMP calculation
890 $up_ht_disc = $objp->subprice;
891 if (!empty($objp->remise_percent) && !getDolGlobalString('STOCK_EXCLUDE_DISCOUNT_FOR_PMP')) {
892 $up_ht_disc = price2num($up_ht_disc * (100 - $objp->remise_percent) / 100, 'MU');
893 }
894
895 // Supplier ref
896 print '<td class="right">'.$objp->sref.'</td>';
897
898 // Qty ordered
899 print '<td class="right">'.$objp->qty.'</td>';
900
901 // Already dispatched
902 print '<td class="right">'.$alreadydispatched.'</td>';
903
904 if (isModEnabled('productbatch') && $objp->tobatch > 0) {
905 $type = 'batch';
906 print '<td class="right">';
907 print '</td>'; // Qty to dispatch
908 print '<td>';
909 //print img_picto($langs->trans('AddDispatchBatchLine'), 'split.png', 'class="splitbutton" onClick="addDispatchLine(' . $i . ',\'' . $type . '\')"');
910 print '</td>'; // Dispatch column
911 print '<td></td>'; // Warehouse column
912
913 // Enable hooks to append additional columns
914 $parameters = array(
915 // allows hook to distinguish between the rows with information and the rows with dispatch form input
916 'is_information_row' => true,
917 'i' => $i,
918 'suffix' => $suffix,
919 'objp' => $objp,
920 );
921 $reshook = $hookmanager->executeHooks(
922 'printFieldListValue',
923 $parameters,
924 $object,
925 $action
926 );
927 if ($reshook < 0) {
928 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
929 }
930 print $hookmanager->resPrint;
931
932 print '</tr>';
933
934 print '<tr class="oddeven" name="'.$type.$suffix.'">';
935 print '<td>';
936 print '<input name="fk_commandefourndet'.$suffix.'" type="hidden" value="'.$objp->rowid.'">';
937 print '<input name="product_batch'.$suffix.'" type="hidden" value="'.$objp->fk_product.'">';
938
939 print '<!-- This is a up (may include discount or not depending on STOCK_EXCLUDE_DISCOUNT_FOR_PMP. will be used for PMP calculation) -->';
940 if (getDolGlobalString('SUPPLIER_ORDER_EDIT_BUYINGPRICE_DURING_RECEIPT')) { // Not tested !
941 print $langs->trans("BuyingPrice").': <input class="maxwidth75" name="pu'.$suffix.'" type="text" value="'.price2num($up_ht_disc, 'MU').'">';
942 } else {
943 print '<input class="maxwidth75" name="pu'.$suffix.'" type="hidden" value="'.price2num($up_ht_disc, 'MU').'">';
944 }
945
946 print '</td>';
947
948 print '<td>';
949 print '<input type="text" class="inputlotnumber quatrevingtquinzepercent" id="lot_number'.$suffix.'" name="lot_number'.$suffix.'" value="'.GETPOST('lot_number'.$suffix).'">';
950 print '</td>';
951 if (!getDolGlobalString('PRODUCT_DISABLE_SELLBY')) {
952 print '<td class="nowraponall">';
953 $dlcdatesuffix = dol_mktime(0, 0, 0, GETPOST('dlc'.$suffix.'month'), GETPOST('dlc'.$suffix.'day'), GETPOST('dlc'.$suffix.'year'));
954 print $form->selectDate($dlcdatesuffix, 'dlc'.$suffix, 0, 0, 1, '');
955 print '</td>';
956 }
957 if (!getDolGlobalString('PRODUCT_DISABLE_EATBY')) {
958 print '<td class="nowraponall">';
959 $dluodatesuffix = dol_mktime(0, 0, 0, GETPOST('dluo'.$suffix.'month'), GETPOST('dluo'.$suffix.'day'), GETPOST('dluo'.$suffix.'year'));
960 print $form->selectDate($dluodatesuffix, 'dluo'.$suffix, 0, 0, 1, '');
961 print '</td>';
962 }
963 print '<td colspan="3">&nbsp;</td>'; // Supplier ref + Qty ordered + qty already dispatched
964 } else {
965 $type = 'dispatch';
966 $colspan = 7;
967 $colspan = (getDolGlobalString('PRODUCT_DISABLE_SELLBY')) ? --$colspan : $colspan;
968 $colspan = (getDolGlobalString('PRODUCT_DISABLE_EATBY')) ? --$colspan : $colspan;
969 print '<td class="right">';
970 print '</td>'; // Qty to dispatch
971 print '<td>';
972 //print img_picto($langs->trans('AddStockLocationLine'), 'split.png', 'class="splitbutton" onClick="addDispatchLine(' . $i . ',\'' . $type . '\')"');
973 print '</td>'; // Dispatch column
974 print '<td></td>'; // Warehouse column
975
976 // Enable hooks to append additional columns
977 $parameters = array(
978 // allows hook to distinguish between the rows with information and the rows with dispatch form input
979 'is_information_row' => true,
980 'i' => $i,
981 'suffix' => $suffix,
982 'objp' => $objp,
983 );
984 $reshook = $hookmanager->executeHooks(
985 'printFieldListValue',
986 $parameters,
987 $object,
988 $action
989 );
990 if ($reshook < 0) {
991 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
992 }
993 print $hookmanager->resPrint;
994
995 print '</tr>';
996
997 print '<tr class="oddeven" name="'.$type.$suffix.'">';
998 print '<td colspan="'.$colspan.'">';
999 print '<input name="fk_commandefourndet'.$suffix.'" type="hidden" value="'.$objp->rowid.'">';
1000 print '<input name="product'.$suffix.'" type="hidden" value="'.$objp->fk_product.'">';
1001
1002 print '<!-- This is a up (may include discount or not depending on STOCK_EXCLUDE_DISCOUNT_FOR_PMP. will be used for PMP calculation) -->';
1003 if (getDolGlobalString('SUPPLIER_ORDER_EDIT_BUYINGPRICE_DURING_RECEIPT')) { // Not tested !
1004 print $langs->trans("BuyingPrice").': <input class="maxwidth75" name="pu'.$suffix.'" type="text" value="'.price2num($up_ht_disc, 'MU').'">';
1005 } else {
1006 print '<input class="maxwidth75" name="pu'.$suffix.'" type="hidden" value="'.price2num($up_ht_disc, 'MU').'">';
1007 }
1008
1009 print '</td>';
1010 }
1011
1012 // Qty to dispatch
1013 print '<td class="right nowrap">';
1014 if ($remaintodispatch > 0) {
1015 $btnLabel = $langs->trans("Fill").' : '.$remaintodispatch;
1016 print '<button class="auto-fill-qty btn-low-emphasis --btn-icon" data-rowname="qty'.$suffix.'" data-value="'.$remaintodispatch.'" title="'.dol_escape_htmltag($btnLabel).'" aria-label="'.dol_escape_htmltag($btnLabel).'" >'.img_picto($btnLabel, 'fa-arrow-right', 'aria-hidden="true"', 0, 0, 1).'</button>';
1017 }
1018 print '<input id="qty'.$suffix.'" name="qty'.$suffix.'" type="number" step="any" class="width50 right qtydispatchinput" value="'.(GETPOSTISSET('qty'.$suffix) ? GETPOSTINT('qty'.$suffix) : (!getDolGlobalString('SUPPLIER_ORDER_DISPATCH_FORCE_QTY_INPUT_TO_ZERO') ? $remaintodispatch : 0)).'">';
1019 print '<button class="resetline btn-low-emphasis --btn-icon" id="reset'.$suffix.'" title="'.dol_escape_htmltag($langs->trans("Reset")).'" >'.img_picto($langs->trans("Reset"), 'eraser', 'aria-hidden="true"', 0, 0, 1).'</button>';
1020 print '</td>';
1021
1022 print '<td>';
1023 if (isModEnabled('productbatch') && $objp->tobatch > 0) {
1024 $type = 'batch';
1025 print img_picto($langs->trans('AddStockLocationLine'), 'split.png', 'class="splitbutton" onClick="addDispatchLine('.$i.', \''.$type.'\')"');
1026 } else {
1027 $type = 'dispatch';
1028 print img_picto($langs->trans('AddStockLocationLine'), 'split.png', 'class="splitbutton" onClick="addDispatchLine('.$i.', \''.$type.'\')"');
1029 }
1030 print '</td>';
1031
1032 if (getDolGlobalString('SUPPLIER_ORDER_CAN_UPDATE_BUYINGPRICE_DURING_RECEIPT')) {
1033 if (!isModEnabled("multicurrency") && empty($conf->dynamicprices->enabled)) {
1034 // Price
1035 print '<td class="right">';
1036 print '<input id="pu'.$suffix.'" name="pu'.$suffix.'" type="text" size="8" value="'.price((GETPOST('pu'.$suffix) != '' ? price2num(GETPOST('pu'.$suffix)) : $up_ht_disc)).'">';
1037 print '</td>';
1038
1039 // Discount
1040 print '<td class="right">';
1041 print '<input id="dto'.$suffix.'" name="dto'.$suffix.'" type="text" size="8" value="'.(GETPOST('dto'.$suffix) != '' ? GETPOST('dto'.$suffix) : '').'">';
1042 print '</td>';
1043
1044 // Save price
1045 print '<td class="center">';
1046 print '<input class="flat checkformerge" type="checkbox" name="saveprice'.$suffix.'" value="'.(GETPOST('saveprice'.$suffix) != '' ? GETPOST('saveprice'.$suffix) : '').'">';
1047 print '</td>';
1048 }
1049 }
1050
1051 // Warehouse
1052 print '<td class="right">';
1053 if (count($listwarehouses) > 1) {
1054 print $formproduct->selectWarehouses(GETPOST("entrepot".$suffix) ? GETPOST("entrepot".$suffix) : ($objp->fk_default_warehouse ? $objp->fk_default_warehouse : ''), "entrepot".$suffix, '', 1, 0, $objp->fk_product, '', 1, 0, array(), 'csswarehouse'.$suffix);
1055 } elseif (count($listwarehouses) == 1) {
1056 print $formproduct->selectWarehouses(GETPOST("entrepot".$suffix) ? GETPOST("entrepot".$suffix) : ($objp->fk_default_warehouse ? $objp->fk_default_warehouse : ''), "entrepot".$suffix, '', 0, 0, $objp->fk_product, '', 1, 0, array(), 'csswarehouse'.$suffix);
1057 } else {
1058 $langs->load("errors");
1059 print $langs->trans("ErrorNoWarehouseDefined");
1060 }
1061 print "</td>\n";
1062
1063 // Enable hooks to append additional columns
1064 $parameters = array(
1065 'is_information_row' => false, // this is a dispatch form row
1066 'i' => $i,
1067 'suffix' => $suffix,
1068 'objp' => $objp,
1069 );
1070 $reshook = $hookmanager->executeHooks(
1071 'printFieldListValue',
1072 $parameters,
1073 $object,
1074 $action
1075 );
1076 if ($reshook < 0) {
1077 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
1078 }
1079 print $hookmanager->resPrint;
1080
1081 print "</tr>\n";
1082 }
1083 }
1084 $i++;
1085 }
1086 $db->free($resql);
1087 } else {
1088 dol_print_error($db);
1089 }
1090
1091 print "</table>\n";
1092 print '</div>';
1093
1094 if ($nbproduct) {
1095 $checkboxlabel = $langs->trans("CloseReceivedSupplierOrdersAutomatically", $langs->transnoentitiesnoconv('StatusOrderReceivedAll'));
1096
1097 print '<div class="center">';
1098 $parameters = array();
1099 $reshook = $hookmanager->executeHooks('addMoreActionsButtons', $parameters, $object, $action); // Note that $action and $object may have been
1100 // modified by hook
1101 if (empty($reshook)) {
1102 if (empty($conf->reception->enabled)) {
1103 print $langs->trans("Comment").' : ';
1104 print '<input type="text" class="minwidth400" maxlength="128" name="comment" value="';
1105 print GETPOSTISSET("comment") ? GETPOST("comment") : $langs->trans("DispatchSupplierOrder", $object->ref);
1106 // print ' / '.$object->ref_supplier; // Not yet available
1107 print '" class="flat"><br>';
1108
1109 print '<input type="checkbox" checked="checked" name="closeopenorder"> '.$checkboxlabel;
1110 }
1111
1112 $dispatchBt = empty($conf->reception->enabled) ? $langs->trans("Receive") : $langs->trans("CreateReception");
1113
1114 print '<br>';
1115 print '<input type="hidden" name="backtopageforcancel" value="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'">';
1116 print '<input type="submit" class="button" name="dispatch" value="'.dol_escape_htmltag($dispatchBt).'"';
1117 $disabled = 0;
1118 if (!$permissiontoreceive) {
1119 $disabled = 1;
1120 }
1121 if (count($listwarehouses) <= 0) {
1122 $disabled = 1;
1123 }
1124 if ($disabled) {
1125 print ' disabled';
1126 }
1127
1128 print '>';
1129 }
1130 print '</div>';
1131 }
1132
1133 // Message if nothing to dispatch
1134 if (!$nbproduct) {
1135 print "<br>\n";
1136 if (!getDolGlobalString('SUPPLIER_ORDER_DISABLE_STOCK_DISPATCH_WHEN_TOTAL_REACHED')) {
1137 print '<div class="opacitymedium">'.$langs->trans("NoPredefinedProductToDispatch").'</div>'; // No predefined line at all
1138 } else {
1139 print '<div class="opacitymedium">'.$langs->trans("NoMorePredefinedProductToDispatch").'</div>'; // No predefined line that remain to be dispatched.
1140 }
1141 }
1142
1143 print '</form>';
1144 }
1145
1146 print dol_get_fiche_end();
1147
1148 // traitement entrepot par défaut
1149 print '<script type="text/javascript">
1150 $(document).ready(function () {
1151 $("select[name=fk_default_warehouse]").change(function() {
1152 var fk_default_warehouse = $("option:selected", this).val();
1153 $("select[name^=entrepot_]").val(fk_default_warehouse).change();
1154 });
1155
1156 $(".auto-fill-qty").on("click touchstart", function(e){
1157 e.preventDefault();
1158 $("input[name="+$(this).data("rowname")+"]").val($(this).data("value")).trigger("change");
1159 });
1160
1161 $("#autoreset").click(function() {
1162 $(".qtydispatchinput").each(function(){
1163 id = $(this).attr("id");
1164 idtab = id.split("_");
1165 if(idtab[1] == 0){
1166 console.log(idtab);
1167 $(this).val("");
1168 $("#qty_dispatched_0_"+idtab[2]).val("0");
1169 } else {
1170 obj = $(this).parent().parent();
1171 nameobj = obj.attr("name");
1172 nametab = nameobj.split("_");
1173 obj.remove();
1174 $("tr[name^=\'"+nametab[0]+"_\'][name$=\'_"+nametab[2]+"\']:last .splitbutton").show();
1175 }
1176 });
1177 });
1178
1179 $(".resetline").click(function(e){
1180 e.preventDefault();
1181 id = $(this).attr("id");
1182 id = id.split("reset_");
1183 console.log("Reset trigger for id = qty_"+id[1]);
1184 $("#qty_"+id[1]).val("");
1185 });
1186 });
1187 </script>';
1188
1189 // List of lines already dispatched
1190 $sql = "SELECT p.rowid as pid, p.ref, p.label,";
1191 $sql .= " e.rowid as warehouse_id, e.ref as entrepot,";
1192 $sql .= " cfd.rowid as dispatchlineid, cfd.fk_product, cfd.qty, cfd.eatby, cfd.sellby, cfd.batch, cfd.comment, cfd.status, cfd.datec";
1193 $sql .= " ,cd.rowid, cd.subprice";
1194 if (isModEnabled('reception')) {
1195 $sql .= ", cfd.fk_reception, r.date_delivery";
1196 }
1197 $sql .= " FROM ".MAIN_DB_PREFIX."product as p,";
1198 $sql .= " ".MAIN_DB_PREFIX."receptiondet_batch as cfd";
1199 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."commande_fournisseurdet as cd ON cd.rowid = cfd.fk_elementdet";
1200 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."entrepot as e ON cfd.fk_entrepot = e.rowid";
1201 if (isModEnabled('reception')) {
1202 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."reception as r ON cfd.fk_reception = r.rowid";
1203 }
1204 $sql .= " WHERE cfd.fk_element = ".((int) $object->id);
1205 $sql .= " AND cfd.fk_product = p.rowid";
1206 $sql .= " ORDER BY cfd.rowid ASC";
1207
1208 $resql = $db->query($sql);
1209 if ($resql) {
1210 $num = $db->num_rows($resql);
1211 $i = 0;
1212
1213 if ($num > 0) {
1214 print "<br>\n";
1215
1216 print load_fiche_titre($langs->trans("ReceivingForSameOrder"));
1217
1218 print '<div class="div-table-responsive">';
1219 print '<table id="dispatch_received_products" class="noborder centpercent">';
1220
1221 print '<tr class="liste_titre">';
1222 // Reception ref
1223 if (isModEnabled("reception")) {
1224 print '<td>'.$langs->trans("Reception").'</td>';
1225 }
1226 // Product
1227 print '<td>'.$langs->trans("Product").'</td>';
1228 print '<td class="center">'.$langs->trans("DateCreation").'</td>';
1229 print '<td class="center">'.$langs->trans("DateDeliveryPlanned").'</td>';
1230 if (isModEnabled('productbatch')) {
1231 print '<td class="dispatch_batch_number_title">'.$langs->trans("batch_number").'</td>';
1232 if (!getDolGlobalString('PRODUCT_DISABLE_SELLBY')) {
1233 print '<td class="dispatch_dlc_title">'.$langs->trans("SellByDate").'</td>';
1234 }
1235 if (!getDolGlobalString('PRODUCT_DISABLE_EATBY')) {
1236 print '<td class="dispatch_dluo_title">'.$langs->trans("EatByDate").'</td>';
1237 }
1238 }
1239 print '<td class="right">'.$langs->trans("QtyDispatched").'</td>';
1240 print '<td>'.$langs->trans("Warehouse").'</td>';
1241 print '<td>'.$langs->trans("Comment").'</td>';
1242
1243 // Status
1244 if (getDolGlobalString('SUPPLIER_ORDER_USE_DISPATCH_STATUS') && !isModEnabled("reception")) {
1245 print '<td class="center" colspan="2">'.$langs->trans("Status").'</td>';
1246 } elseif (isModEnabled("reception")) {
1247 print '<td class="center"></td>';
1248 }
1249
1250 print '<td class="center" colspan="2"></td>';
1251
1252 print "</tr>\n";
1253
1254
1255 while ($i < $num) {
1256 $objp = $db->fetch_object($resql);
1257
1258 if ($action == 'editline' && $lineid == $objp->dispatchlineid) {
1259 print '<form name="editdispatchedlines" id="editdispatchedlines" action="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'#line_'.GETPOSTINT('lineid').'" method="POST">
1260 <input type="hidden" name="token" value="'.newToken().'">
1261 <input type="hidden" name="action" value="updateline">
1262 <input type="hidden" name="mode" value="">
1263 <input type="hidden" name="lineid" value="'.$objp->dispatchlineid.'">';
1264 }
1265
1266 print '<tr class="oddeven" id="line_'.$objp->dispatchlineid.'" >';
1267
1268 // Reception ref
1269 $reception = null;
1270 if (isModEnabled("reception")) {
1271 print '<td class="nowraponall">';
1272 if (!empty($objp->fk_reception)) {
1273 $reception = new Reception($db);
1274 $reception->fetch($objp->fk_reception);
1275 print $reception->getNomUrl(1);
1276 }
1277
1278 print "</td>";
1279 }
1280
1281 // Product
1282 print '<td class="tdoverflowmax150">';
1283 if (empty($conf->cache['product'][$objp->fk_product])) {
1284 $tmpproduct = new Product($db);
1285 $tmpproduct->fetch($objp->fk_product);
1286 $conf->cache['product'][$objp->fk_product] = $tmpproduct;
1287 } else {
1288 $tmpproduct = $conf->cache['product'][$objp->fk_product];
1289 }
1290 print $tmpproduct->getNomUrl(1);
1291 print ' - '.$objp->label;
1292 print "</td>\n";
1293
1294 // Date creation
1295 print '<td class="center">'.dol_print_date($db->jdate($objp->datec), 'day').'</td>';
1296
1297 // Date delivery
1298 if (property_exists($objp, "date_delivery")) {
1299 print '<td class="center">' . dol_print_date($db->jdate($objp->date_delivery), 'day') . '</td>';
1300 } else {
1301 print '<td class="center"></td>';
1302 }
1303
1304 // Batch / Eat by / Sell by
1305 if (isModEnabled('productbatch')) {
1306 if ($objp->batch) {
1307 include_once DOL_DOCUMENT_ROOT.'/product/stock/class/productlot.class.php';
1308 $lot = new Productlot($db);
1309 $lot->fetch(0, $objp->pid, $objp->batch);
1310 print '<td class="dispatch_batch_number">'.$lot->getNomUrl(1).'</td>';
1311 if (!getDolGlobalString('PRODUCT_DISABLE_SELLBY')) {
1312 print '<td class="dispatch_dlc">'.dol_print_date($lot->sellby, 'day').'</td>';
1313 }
1314 if (!getDolGlobalString('PRODUCT_DISABLE_EATBY')) {
1315 print '<td class="dispatch_dluo">'.dol_print_date($lot->eatby, 'day').'</td>';
1316 }
1317 } else {
1318 print '<td class="dispatch_batch_number"></td>';
1319 if (!getDolGlobalString('PRODUCT_DISABLE_SELLBY')) {
1320 print '<td class="dispatch_dlc"></td>';
1321 }
1322 if (!getDolGlobalString('PRODUCT_DISABLE_EATBY')) {
1323 print '<td class="dispatch_dluo"></td>';
1324 }
1325 }
1326 }
1327
1328 // Qty
1329 print '<td class="right">';
1330 if ($action == 'editline' && $lineid == $objp->dispatchlineid) {
1331 print '<input style="width: 50px;" type="text" min="1" name="qty" value="'.$objp->qty.'" />';
1332 } else {
1333 print $objp->qty;
1334 }
1335 print '<input type="hidden" name="price" value="'.$objp->subprice.'" />';
1336 print '</td>';
1337 // Warehouse
1338 print '<td class="tdoverflowmax150">';
1339 if ($action == 'editline' && $lineid == $objp->dispatchlineid) {
1340 $warehouse_id = GETPOSTINT("fk_entrepot") ? GETPOSTINT("fk_entrepot") : ($objp->warehouse_id ? $objp->warehouse_id : '');
1341 if (count($listwarehouses) > 1) {
1342 print $formproduct->selectWarehouses($warehouse_id, "fk_entrepot", '', 1, 0, $objp->fk_product, '', 1, 1, array(), 'csswarehouse');
1343 } elseif (count($listwarehouses) == 1) {
1344 print $formproduct->selectWarehouses($warehouse_id, "fk_entrepot", '', 0, 0, $objp->fk_product, '', 1, 1, array(), 'csswarehouse');
1345 } else {
1346 $langs->load("errors");
1347 print $langs->trans("ErrorNoWarehouseDefined");
1348 }
1349 } else {
1350 $warehouse_static->id = $objp->warehouse_id;
1351 $warehouse_static->label = $objp->entrepot;
1352 print $warehouse_static->getNomUrl(1);
1353 }
1354 print '</td>';
1355
1356 // Comment
1357 print '<td class="tdoverflowmax300" style="white-space: pre;">'.$objp->comment.'</td>';
1358
1359 // Status
1360 if (getDolGlobalString('SUPPLIER_ORDER_USE_DISPATCH_STATUS') && !isModEnabled("reception")) {
1361 print '<td class="right">';
1362 $supplierorderdispatch->status = (empty($objp->status) ? 0 : $objp->status);
1363 // print $supplierorderdispatch->status;
1364 print $supplierorderdispatch->getLibStatut(5);
1365 print '</td>';
1366
1367 // Add button to check/uncheck disaptching
1368 print '<td class="center">';
1369 if (!$permissiontocontrol) {
1370 if (empty($objp->status)) {
1371 print '<a class="button buttonRefused" href="#">'.$langs->trans("Approve").'</a>';
1372 print '<a class="button buttonRefused" href="#">'.$langs->trans("Deny").'</a>';
1373 } else {
1374 print '<a class="button buttonRefused" href="#">'.$langs->trans("Disapprove").'</a>';
1375 print '<a class="button buttonRefused" href="#">'.$langs->trans("Deny").'</a>';
1376 }
1377 } else {
1378 $disabled = '';
1379 if ($object->status == $object::STATUS_RECEIVED_COMPLETELY) {
1380 $disabled = 1;
1381 }
1382 if (empty($objp->status)) {
1383 print '<a class="button'.($disabled ? ' buttonRefused' : '').'" href="'.$_SERVER["PHP_SELF"]."?id=".$id."&action=checkdispatchline&lineid=".$objp->dispatchlineid.'">'.$langs->trans("Approve").'</a>';
1384 print '<a class="button'.($disabled ? ' buttonRefused' : '').'" href="'.$_SERVER["PHP_SELF"]."?id=".$id."&action=denydispatchline&lineid=".$objp->dispatchlineid.'">'.$langs->trans("Deny").'</a>';
1385 }
1386 if ($objp->status == 1) {
1387 print '<a class="button'.($disabled ? ' buttonRefused' : '').'" href="'.$_SERVER["PHP_SELF"]."?id=".$id."&action=uncheckdispatchline&lineid=".$objp->dispatchlineid.'">'.$langs->trans("Reinit").'</a>';
1388 print '<a class="button'.($disabled ? ' buttonRefused' : '').'" href="'.$_SERVER["PHP_SELF"]."?id=".$id."&action=denydispatchline&lineid=".$objp->dispatchlineid.'">'.$langs->trans("Deny").'</a>';
1389 }
1390 if ($objp->status == 2) {
1391 print '<a class="button'.($disabled ? ' buttonRefused' : '').'" href="'.$_SERVER["PHP_SELF"]."?id=".$id."&action=uncheckdispatchline&lineid=".$objp->dispatchlineid.'">'.$langs->trans("Reinit").'</a>';
1392 print '<a class="button'.($disabled ? ' buttonRefused' : '').'" href="'.$_SERVER["PHP_SELF"]."?id=".$id."&action=checkdispatchline&lineid=".$objp->dispatchlineid.'">'.$langs->trans("Approve").'</a>';
1393 }
1394 }
1395 print '</td>';
1396 } elseif (isModEnabled("reception")) {
1397 print '<td class="right">';
1398 if ($reception !== null && !empty($reception->id)) {
1399 print $reception->getLibStatut(5);
1400 }
1401 print '</td>';
1402 }
1403
1404 // Action
1405 if ($action != 'editline' || $lineid != $objp->dispatchlineid) {
1406 if (($reception === null) || empty($reception->id) || ($reception->statut == Reception::STATUS_DRAFT)) { // only allow edit on draft reception
1407 print '<td class="linecoledit center">';
1408 print '<a class="reposition" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=editline&token='.newToken().'&lineid='.$objp->dispatchlineid.'#line_'.$objp->dispatchlineid.'">';
1409 print img_edit();
1410 print '</a>';
1411 print '</td>';
1412
1413 print '<td class="linecoldelete center">';
1414 print '<a href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=ask_deleteline&token='.newToken().'&lineid='.$objp->dispatchlineid.'#dispatch_received_products">';
1415 print img_delete();
1416 print '</a>';
1417 print '</td>';
1418 } else {
1419 print '<td></td><td></td>';
1420 }
1421 } else {
1422 print '<td class="center valignmiddle">';
1423 print '<input type="submit" class="button button-save" id="savelinebutton" name="save" value="'.$langs->trans("Save").'" />';
1424 print '</td>';
1425 print '<td class="center valignmiddle">';
1426 print '<input type="submit" class="button button-cancel" id="cancellinebutton" name="cancel" value="'.$langs->trans("Cancel").'" />';
1427 print '</td>';
1428 }
1429
1430
1431 print "</tr>\n";
1432 if ($action == 'editline' && $lineid == $objp->dispatchlineid) {
1433 print '</form>';
1434 }
1435
1436 $i++;
1437 }
1438 $db->free($resql);
1439
1440 print "</table>\n";
1441 print '</div>';
1442 }
1443 } else {
1444 dol_print_error($db);
1445 }
1446}
1447
1448// End of page
1449llxFooter();
1450$db->close();
$id
Definition account.php:48
if( $user->socid > 0) if(! $user->hasRight('accounting', 'chartofaccount')) $object
Definition card.php:66
llxFooter($comment='', $zone='private', $disabledoutputofmessages=0)
Empty footer.
Definition wrapper.php:87
if(!defined('NOREQUIRESOC')) if(!defined( 'NOREQUIRETRAN')) if(!defined('NOTOKENRENEWAL')) if(!defined( 'NOREQUIREMENU')) if(!defined('NOREQUIREHTML')) if(!defined( 'NOREQUIREAJAX')) llxHeader($head='', $title='', $help_url='', $target='', $disablejs=0, $disablehead=0, $arrayofjs='', $arrayofcss='', $morequerystring='', $morecssonbody='', $replacemainareaby='', $disablenofollow=0, $disablenoindex=0)
Empty header.
Definition wrapper.php:71
Class to manage table ReceptionLineBatch.
Class to manage predefined suppliers products.
const STATUS_RECEIVED_PARTIALLY
Received partially.
const STATUS_CANCELED
Order canceled.
const STATUS_RECEIVED_COMPLETELY
Received completely.
const STATUS_ORDERSENT
Order sent, shipment on process.
Class to manage comment.
Class to manage warehouses.
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 stock movements.
Class to manage products or services.
Class with list of lots and properties.
Class to manage projects.
Class to manage receptions.
Class to manage third parties objects (customers, suppliers, prospects...)
Class to manage Dolibarr users.
ordersupplier_prepare_head(CommandeFournisseur $object)
Prepare array with list of tabs.
dol_mktime($hour, $minute, $second, $month, $day, $year, $gm='auto', $check=1)
Return a timestamp date built from detailed information (by default a local PHP server timestamp) Rep...
load_fiche_titre($title, $morehtmlright='', $picto='generic', $pictoisfullpath=0, $id='', $morecssontable='', $morehtmlcenter='')
Load a title with picto.
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='', $noduplicate=0, $attop=0)
Set event messages in dol_events session object.
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2, $allowothertags=array())
Show picto whatever it's its name (generic function)
img_delete($titlealt='default', $other='class="pictodelete"', $morecss='')
Show delete logo.
GETPOSTINT($paramname, $method=0)
Return the value of a $_GET or $_POST supervariable, converted into integer.
dol_get_fiche_head($links=array(), $active='', $title='', $notab=0, $picto='', $pictoisfullpath=0, $morehtmlright='', $morecss='', $limittoshow=0, $moretabssuffix='', $dragdropfile=0)
Show tabs of a record.
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
dol_now($mode='auto')
Return date for now.
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs=null, $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
newToken()
Return the value of token currently saved into session with name 'newtoken'.
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
GETPOSTFLOAT($paramname, $rounding='')
Return the value of a $_GET or $_POST supervariable, converted into float.
dol_print_error($db=null, $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
img_edit($titlealt='default', $float=0, $other='')
Show logo edit/modify fiche.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0, $cleanalsojavascript=0)
Returns text escaped for inclusion in HTML alt or title or value tags, or into values of HTML input f...
treeview li table
No Email.
ui state ui widget content ui state ui widget header ui state a ui button
0 = Do not include form tag and submit button -1 = Do not include form tag but include submit button
global $conf
The following vars must be defined: $type2label $form $conf, $lang, The following vars may also be de...
Definition member.php:79
$conf db name
Only used if Module[ID]Name translation string is not found.
Definition repair.php:153
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.
accessforbidden($message='', $printheader=1, $printfooter=1, $showonlymessage=0, $params=null)
Show a message to say access is forbidden and stop program.