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