dolibarr 21.0.0-beta
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 = 1;
643 if (!empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER)) {
644 $disabled = 0;
645 }*/
646 $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.
647
648 // Line of orders
650 print '<br><span class="opacitymedium">'.$langs->trans("OrderStatusNotReadyToDispatch").'</span>';
651 }
652
653
654 print '<br>';
655
656 $listwarehouses = array();
657
661 require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php';
662 $formproduct = new FormProduct($db);
663 $formproduct->loadWarehouses();
664 $entrepot = new Entrepot($db);
665 $listwarehouses = $entrepot->list_array(1);
666
667
668 if (empty($conf->reception->enabled)) {
669 print '<form method="POST" action="dispatch.php?id='.$object->id.'">';
670 } else {
671 print '<form method="post" action="'.dol_buildpath('/reception/card.php', 1).'?originid='.$object->id.'&origin=supplierorder">';
672 }
673
674 print '<input type="hidden" name="token" value="'.newToken().'">';
675 if (empty($conf->reception->enabled)) {
676 print '<input type="hidden" name="action" value="dispatch">';
677 } else {
678 print '<input type="hidden" name="action" value="create">';
679 }
680
681 print '<div class="div-table-responsive-no-min">';
682 print '<table class="noborder centpercent">';
683
684 // Set $products_dispatched with qty dispatched for each product id
685 $products_dispatched = array();
686 $sql = "SELECT l.rowid, cfd.fk_product, sum(cfd.qty) as qty";
687 $sql .= " FROM ".MAIN_DB_PREFIX."receptiondet_batch as cfd";
688 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."commande_fournisseurdet as l on l.rowid = cfd.fk_elementdet";
689 $sql .= " WHERE cfd.fk_element = ".((int) $object->id);
690 $sql .= " GROUP BY l.rowid, cfd.fk_product";
691
692 $resql = $db->query($sql);
693 if ($resql) {
694 $num = $db->num_rows($resql);
695 $i = 0;
696
697 if ($num) {
698 while ($i < $num) {
699 $objd = $db->fetch_object($resql);
700 $products_dispatched[$objd->rowid] = price2num($objd->qty, 'MS');
701 $i++;
702 }
703 }
704 $db->free($resql);
705 }
706
707 //$sql = "SELECT l.rowid, l.fk_product, l.subprice, l.remise_percent, l.ref AS sref, SUM(l.qty) as qty,";
708 $sql = "SELECT l.rowid, l.fk_product, l.subprice, l.remise_percent, l.ref AS sref, l.qty as qty,";
709 $sql .= " p.ref, p.label, p.tobatch, p.fk_default_warehouse";
710
711 // Enable hooks to alter the SQL query (SELECT)
712 $parameters = array();
713 $reshook = $hookmanager->executeHooks(
714 'printFieldListSelect',
715 $parameters,
716 $object,
717 $action
718 );
719 if ($reshook < 0) {
720 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
721 }
722 $sql .= $hookmanager->resPrint;
723
724 $sql .= " FROM ".MAIN_DB_PREFIX."commande_fournisseurdet as l";
725 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product as p ON l.fk_product=p.rowid";
726 $sql .= " WHERE l.fk_commande = ".((int) $object->id);
727 if (!getDolGlobalString('STOCK_SUPPORTS_SERVICES')) {
728 $sql .= " AND l.product_type = 0";
729 }
730
731 // Enable hooks to alter the SQL query (WHERE)
732 $parameters = array();
733 $reshook = $hookmanager->executeHooks(
734 'printFieldListWhere',
735 $parameters,
736 $object,
737 $action
738 );
739 if ($reshook < 0) {
740 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
741 }
742 $sql .= $hookmanager->resPrint;
743
744 //$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
745 $sql .= " ORDER BY l.rang, p.ref, p.label";
746
747 // Nb of predefined product lines to dispatch (already done or not) if SUPPLIER_ORDER_DISABLE_STOCK_DISPATCH_WHEN_TOTAL_REACHED is off (default)
748 // or nb of line that remain to dispatch if SUPPLIER_ORDER_DISABLE_STOCK_DISPATCH_WHEN_TOTAL_REACHED is on.
749 $nbproduct = 0;
750
751 $resql = $db->query($sql);
752 if ($resql) {
753 $num = $db->num_rows($resql);
754 $i = 0;
755
756 if ($num) {
757 print '<tr class="liste_titre">';
758
759 print '<td>'.$langs->trans("Description").'</td>';
760 if (isModEnabled('productbatch')) {
761 print '<td class="dispatch_batch_number_title">'.$langs->trans("batch_number").'</td>';
762 if (!getDolGlobalString('PRODUCT_DISABLE_SELLBY')) {
763 print '<td class="dispatch_dlc_title">'.$langs->trans("SellByDate").'</td>';
764 }
765 if (!getDolGlobalString('PRODUCT_DISABLE_EATBY')) {
766 print '<td class="dispatch_dluo_title">'.$langs->trans("EatByDate").'</td>';
767 }
768 } else {
769 print '<td></td>';
770 print '<td></td>';
771 print '<td></td>';
772 }
773 print '<td class="right">'.$langs->trans("SupplierRef").'</td>';
774 print '<td class="right">'.$langs->trans("QtyOrdered").'</td>';
775 print '<td class="right">'.$langs->trans("QtyDispatchedShort").'</td>';
776 print ' <td class="right">'.$langs->trans("QtyToDispatchShort");
777 print '<br><a href="#" id="autoreset">'.img_picto($langs->trans("Reset"), 'eraser', 'class="pictofixedwidth opacitymedium"').$langs->trans("Reset").'</a></td>';
778 print '<td width="32"></td>';
779
780 if (getDolGlobalString('SUPPLIER_ORDER_CAN_UPDATE_BUYINGPRICE_DURING_RECEIPT')) {
781 if (!isModEnabled("multicurrency") && empty($conf->dynamicprices->enabled)) {
782 print '<td class="right">'.$langs->trans("Price").'</td>';
783 print '<td class="right">'.$langs->trans("ReductionShort").' (%)</td>';
784 print '<td class="right">'.$langs->trans("UpdatePrice").'</td>';
785 }
786 }
787
788 print '<td align="right">'.$langs->trans("Warehouse");
789
790 // Select warehouse to force it everywhere
791 if (count($listwarehouses) > 1) {
792 print '<br>'.$form->selectarray('fk_default_warehouse', $listwarehouses, $fk_default_warehouse, $langs->trans("ForceTo"), 0, 0, '', 0, 0, $disabled, '', 'minwidth100 maxwidth300', 1);
793 } elseif (count($listwarehouses) == 1) {
794 print '<br>'.$form->selectarray('fk_default_warehouse', $listwarehouses, $fk_default_warehouse, 0, 0, 0, '', 0, 0, $disabled, '', 'minwidth100 maxwidth300', 1);
795 }
796
797 print '</td>';
798
799 // Enable hooks to append additional columns
800 $parameters = array();
801 $reshook = $hookmanager->executeHooks(
802 'printFieldListTitle',
803 $parameters,
804 $object,
805 $action
806 );
807 if ($reshook < 0) {
808 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
809 }
810 print $hookmanager->resPrint;
811
812 print "</tr>\n";
813 }
814
815 $nbfreeproduct = 0; // Nb of lines of free products/services
816
817 $conf->cache['product'] = array();
818
819 // Loop on each source order line (may be more or less than current number of lines in llx_commande_fournisseurdet)
820 while ($i < $num) {
821 $objp = $db->fetch_object($resql);
822
823 // On n'affiche pas les produits libres
824 if (!$objp->fk_product > 0) {
825 $nbfreeproduct++;
826 } else {
827 $alreadydispatched = isset($products_dispatched[$objp->rowid]) ? $products_dispatched[$objp->rowid] : 0;
828 $remaintodispatch = price2num($objp->qty - ((float) $alreadydispatched), 5); // Calculation of dispatched
829 if ($remaintodispatch < 0 && !getDolGlobalString('SUPPLIER_ORDER_ALLOW_NEGATIVE_QTY_FOR_SUPPLIER_ORDER_RETURN')) {
830 $remaintodispatch = 0;
831 }
832
833 if ($remaintodispatch || !getDolGlobalString('SUPPLIER_ORDER_DISABLE_STOCK_DISPATCH_WHEN_TOTAL_REACHED')) {
834 $nbproduct++;
835
836 // To show detail cref and description value, we must make calculation by cref
837 // print ($objp->cref?' ('.$objp->cref.')':'');
838 // if ($objp->description) print '<br>'.nl2br($objp->description);
839 $suffix = '_0_'.$i;
840
841 print "\n";
842 print '<!-- Line to dispatch '.$suffix.' -->'."\n";
843 // hidden fields for js function
844 print '<input id="qty_ordered'.$suffix.'" type="hidden" value="'.$objp->qty.'">';
845 print '<input id="qty_dispatched'.$suffix.'" type="hidden" value="'.(float) $alreadydispatched.'">';
846 print '<tr class="oddeven">';
847
848 if (empty($conf->cache['product'][$objp->fk_product])) {
849 $tmpproduct = new Product($db);
850 $tmpproduct->fetch($objp->fk_product);
851 $conf->cache['product'][$objp->fk_product] = $tmpproduct;
852 } else {
853 $tmpproduct = $conf->cache['product'][$objp->fk_product];
854 }
855
856 $linktoprod = $tmpproduct->getNomUrl(1);
857 $linktoprod .= ' - '.$objp->label."\n";
858
859 if (isModEnabled('productbatch')) {
860 if ($objp->tobatch) {
861 // Product
862 print '<td>';
863 print $linktoprod;
864 print "</td>";
865 print '<td class="dispatch_batch_number"></td>';
866 if (!getDolGlobalString('PRODUCT_DISABLE_SELLBY')) {
867 print '<td class="dispatch_dlc"></td>';
868 }
869 if (!getDolGlobalString('PRODUCT_DISABLE_EATBY')) {
870 print '<td class="dispatch_dluo"></td>';
871 }
872 } else {
873 // Product
874 print '<td>';
875 print $linktoprod;
876 print "</td>";
877 print '<td class="dispatch_batch_number">';
878 print '<span class="opacitymedium small">'.$langs->trans("ProductDoesNotUseBatchSerial").'</small>';
879 print '</td>';
880 if (!getDolGlobalString('PRODUCT_DISABLE_SELLBY')) {
881 print '<td class="dispatch_dlc"></td>';
882 }
883 if (!getDolGlobalString('PRODUCT_DISABLE_EATBY')) {
884 print '<td class="dispatch_dluo"></td>';
885 }
886 }
887 } else {
888 print '<td colspan="4">';
889 print $linktoprod;
890 print "</td>";
891 }
892
893 // Define unit price for PMP calculation
894 $up_ht_disc = $objp->subprice;
895 if (!empty($objp->remise_percent) && !getDolGlobalString('STOCK_EXCLUDE_DISCOUNT_FOR_PMP')) {
896 $up_ht_disc = price2num($up_ht_disc * (100 - $objp->remise_percent) / 100, 'MU');
897 }
898
899 // Supplier ref
900 print '<td class="right">'.$objp->sref.'</td>';
901
902 // Qty ordered
903 print '<td class="right">'.$objp->qty.'</td>';
904
905 // Already dispatched
906 print '<td class="right">'.$alreadydispatched.'</td>';
907
908 if (isModEnabled('productbatch') && $objp->tobatch > 0) {
909 $type = 'batch';
910 print '<td class="right">';
911 print '</td>'; // Qty to dispatch
912 print '<td>';
913 //print img_picto($langs->trans('AddDispatchBatchLine'), 'split.png', 'class="splitbutton" onClick="addDispatchLine(' . $i . ',\'' . $type . '\')"');
914 print '</td>'; // Dispatch column
915 print '<td></td>'; // Warehouse column
916
917 // Enable hooks to append additional columns
918 $parameters = array(
919 // allows hook to distinguish between the rows with information and the rows with dispatch form input
920 'is_information_row' => true,
921 'i' => $i,
922 'suffix' => $suffix,
923 'objp' => $objp,
924 );
925 $reshook = $hookmanager->executeHooks(
926 'printFieldListValue',
927 $parameters,
928 $object,
929 $action
930 );
931 if ($reshook < 0) {
932 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
933 }
934 print $hookmanager->resPrint;
935
936 print '</tr>';
937
938 print '<tr class="oddeven" name="'.$type.$suffix.'">';
939 print '<td>';
940 print '<input name="fk_commandefourndet'.$suffix.'" type="hidden" value="'.$objp->rowid.'">';
941 print '<input name="product_batch'.$suffix.'" type="hidden" value="'.$objp->fk_product.'">';
942
943 print '<!-- This is a up (may include discount or not depending on STOCK_EXCLUDE_DISCOUNT_FOR_PMP. will be used for PMP calculation) -->';
944 if (getDolGlobalString('SUPPLIER_ORDER_EDIT_BUYINGPRICE_DURING_RECEIPT')) { // Not tested !
945 print $langs->trans("BuyingPrice").': <input class="maxwidth75" name="pu'.$suffix.'" type="text" value="'.price2num($up_ht_disc, 'MU').'">';
946 } else {
947 print '<input class="maxwidth75" name="pu'.$suffix.'" type="hidden" value="'.price2num($up_ht_disc, 'MU').'">';
948 }
949
950 print '</td>';
951
952 print '<td>';
953 print '<input type="text" class="inputlotnumber quatrevingtquinzepercent" id="lot_number'.$suffix.'" name="lot_number'.$suffix.'" value="'.GETPOST('lot_number'.$suffix).'">';
954 print '</td>';
955 if (!getDolGlobalString('PRODUCT_DISABLE_SELLBY')) {
956 print '<td class="nowraponall">';
957 $dlcdatesuffix = dol_mktime(0, 0, 0, GETPOST('dlc'.$suffix.'month'), GETPOST('dlc'.$suffix.'day'), GETPOST('dlc'.$suffix.'year'));
958 print $form->selectDate($dlcdatesuffix, 'dlc'.$suffix, 0, 0, 1, '');
959 print '</td>';
960 }
961 if (!getDolGlobalString('PRODUCT_DISABLE_EATBY')) {
962 print '<td class="nowraponall">';
963 $dluodatesuffix = dol_mktime(0, 0, 0, GETPOST('dluo'.$suffix.'month'), GETPOST('dluo'.$suffix.'day'), GETPOST('dluo'.$suffix.'year'));
964 print $form->selectDate($dluodatesuffix, 'dluo'.$suffix, 0, 0, 1, '');
965 print '</td>';
966 }
967 print '<td colspan="3">&nbsp;</td>'; // Supplier ref + Qty ordered + qty already dispatched
968 } else {
969 $type = 'dispatch';
970 $colspan = 7;
971 $colspan = (getDolGlobalString('PRODUCT_DISABLE_SELLBY')) ? --$colspan : $colspan;
972 $colspan = (getDolGlobalString('PRODUCT_DISABLE_EATBY')) ? --$colspan : $colspan;
973 print '<td class="right">';
974 print '</td>'; // Qty to dispatch
975 print '<td>';
976 //print img_picto($langs->trans('AddStockLocationLine'), 'split.png', 'class="splitbutton" onClick="addDispatchLine(' . $i . ',\'' . $type . '\')"');
977 print '</td>'; // Dispatch column
978 print '<td></td>'; // Warehouse column
979
980 // Enable hooks to append additional columns
981 $parameters = array(
982 // allows hook to distinguish between the rows with information and the rows with dispatch form input
983 'is_information_row' => true,
984 'i' => $i,
985 'suffix' => $suffix,
986 'objp' => $objp,
987 );
988 $reshook = $hookmanager->executeHooks(
989 'printFieldListValue',
990 $parameters,
991 $object,
992 $action
993 );
994 if ($reshook < 0) {
995 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
996 }
997 print $hookmanager->resPrint;
998
999 print '</tr>';
1000
1001 print '<tr class="oddeven" name="'.$type.$suffix.'">';
1002 print '<td colspan="'.$colspan.'">';
1003 print '<input name="fk_commandefourndet'.$suffix.'" type="hidden" value="'.$objp->rowid.'">';
1004 print '<input name="product'.$suffix.'" type="hidden" value="'.$objp->fk_product.'">';
1005
1006 print '<!-- This is a up (may include discount or not depending on STOCK_EXCLUDE_DISCOUNT_FOR_PMP. will be used for PMP calculation) -->';
1007 if (getDolGlobalString('SUPPLIER_ORDER_EDIT_BUYINGPRICE_DURING_RECEIPT')) { // Not tested !
1008 print $langs->trans("BuyingPrice").': <input class="maxwidth75" name="pu'.$suffix.'" type="text" value="'.price2num($up_ht_disc, 'MU').'">';
1009 } else {
1010 print '<input class="maxwidth75" name="pu'.$suffix.'" type="hidden" value="'.price2num($up_ht_disc, 'MU').'">';
1011 }
1012
1013 print '</td>';
1014 }
1015
1016 // Qty to dispatch
1017 print '<td class="right nowrap">';
1018 if ($remaintodispatch > 0) {
1019 $btnLabel = $langs->trans("Fill").' : '.$remaintodispatch;
1020 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>';
1021 }
1022 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)).'">';
1023 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>';
1024 print '</td>';
1025
1026 print '<td>';
1027 if (isModEnabled('productbatch') && $objp->tobatch > 0) {
1028 $type = 'batch';
1029 print img_picto($langs->trans('AddStockLocationLine'), 'split.png', 'class="splitbutton" onClick="addDispatchLine('.$i.', \''.$type.'\')"');
1030 } else {
1031 $type = 'dispatch';
1032 print img_picto($langs->trans('AddStockLocationLine'), 'split.png', 'class="splitbutton" onClick="addDispatchLine('.$i.', \''.$type.'\')"');
1033 }
1034 print '</td>';
1035
1036 if (getDolGlobalString('SUPPLIER_ORDER_CAN_UPDATE_BUYINGPRICE_DURING_RECEIPT')) {
1037 if (!isModEnabled("multicurrency") && empty($conf->dynamicprices->enabled)) {
1038 // Price
1039 print '<td class="right">';
1040 print '<input id="pu'.$suffix.'" name="pu'.$suffix.'" type="text" size="8" value="'.price((GETPOST('pu'.$suffix) != '' ? price2num(GETPOST('pu'.$suffix)) : $up_ht_disc)).'">';
1041 print '</td>';
1042
1043 // Discount
1044 print '<td class="right">';
1045 print '<input id="dto'.$suffix.'" name="dto'.$suffix.'" type="text" size="8" value="'.(GETPOST('dto'.$suffix) != '' ? GETPOST('dto'.$suffix) : '').'">';
1046 print '</td>';
1047
1048 // Save price
1049 print '<td class="center">';
1050 print '<input class="flat checkformerge" type="checkbox" name="saveprice'.$suffix.'" value="'.(GETPOST('saveprice'.$suffix) != '' ? GETPOST('saveprice'.$suffix) : '').'">';
1051 print '</td>';
1052 }
1053 }
1054
1055 // Warehouse
1056 print '<td class="right">';
1057 if (count($listwarehouses) > 1) {
1058 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);
1059 } elseif (count($listwarehouses) == 1) {
1060 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);
1061 } else {
1062 $langs->load("errors");
1063 print $langs->trans("ErrorNoWarehouseDefined");
1064 }
1065 print "</td>\n";
1066
1067 // Enable hooks to append additional columns
1068 $parameters = array(
1069 'is_information_row' => false, // this is a dispatch form row
1070 'i' => $i,
1071 'suffix' => $suffix,
1072 'objp' => $objp,
1073 );
1074 $reshook = $hookmanager->executeHooks(
1075 'printFieldListValue',
1076 $parameters,
1077 $object,
1078 $action
1079 );
1080 if ($reshook < 0) {
1081 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
1082 }
1083 print $hookmanager->resPrint;
1084
1085 print "</tr>\n";
1086 }
1087 }
1088 $i++;
1089 }
1090 $db->free($resql);
1091 } else {
1092 dol_print_error($db);
1093 }
1094
1095 print "</table>\n";
1096 print '</div>';
1097
1098 if ($nbproduct) {
1099 $checkboxlabel = $langs->trans("CloseReceivedSupplierOrdersAutomatically", $langs->transnoentitiesnoconv('StatusOrderReceivedAll'));
1100
1101 print '<div class="center">';
1102 $parameters = array();
1103 $reshook = $hookmanager->executeHooks('addMoreActionsButtons', $parameters, $object, $action); // Note that $action and $object may have been
1104 // modified by hook
1105 if (empty($reshook)) {
1106 if (empty($conf->reception->enabled)) {
1107 print $langs->trans("Comment").' : ';
1108 print '<input type="text" class="minwidth400" maxlength="128" name="comment" value="';
1109 print GETPOSTISSET("comment") ? GETPOST("comment") : $langs->trans("DispatchSupplierOrder", $object->ref);
1110 // print ' / '.$object->ref_supplier; // Not yet available
1111 print '" class="flat"><br>';
1112
1113 print '<input type="checkbox" checked="checked" name="closeopenorder"> '.$checkboxlabel;
1114 }
1115
1116 $dispatchBt = empty($conf->reception->enabled) ? $langs->trans("Receive") : $langs->trans("CreateReception");
1117
1118 print '<br>';
1119 print '<input type="hidden" name="backtopageforcancel" value="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'">';
1120 print '<input type="submit" class="button" name="dispatch" value="'.dol_escape_htmltag($dispatchBt).'"';
1121 $disabled = 0;
1122 if (!$permissiontoreceive) {
1123 $disabled = 1;
1124 }
1125 if (count($listwarehouses) <= 0) {
1126 $disabled = 1;
1127 }
1128 if ($disabled) {
1129 print ' disabled';
1130 }
1131
1132 print '>';
1133 }
1134 print '</div>';
1135 }
1136
1137 // Message if nothing to dispatch
1138 if (!$nbproduct) {
1139 print "<br>\n";
1140 if (!getDolGlobalString('SUPPLIER_ORDER_DISABLE_STOCK_DISPATCH_WHEN_TOTAL_REACHED')) {
1141 print '<div class="opacitymedium">'.$langs->trans("NoPredefinedProductToDispatch").'</div>'; // No predefined line at all
1142 } else {
1143 print '<div class="opacitymedium">'.$langs->trans("NoMorePredefinedProductToDispatch").'</div>'; // No predefined line that remain to be dispatched.
1144 }
1145 }
1146
1147 print '</form>';
1148 }
1149
1150 print dol_get_fiche_end();
1151
1152 // traitement entrepot par défaut
1153 print '<script type="text/javascript">
1154 $(document).ready(function () {
1155 $("select[name=fk_default_warehouse]").change(function() {
1156 var fk_default_warehouse = $("option:selected", this).val();
1157 $("select[name^=entrepot_]").val(fk_default_warehouse).change();
1158 });
1159
1160 $(".auto-fill-qty").on("click touchstart", function(e){
1161 e.preventDefault();
1162 $("input[name="+$(this).data("rowname")+"]").val($(this).data("value")).trigger("change");
1163 });
1164
1165 $("#autoreset").click(function() {
1166 $(".qtydispatchinput").each(function(){
1167 id = $(this).attr("id");
1168 idtab = id.split("_");
1169 if(idtab[1] == 0){
1170 console.log(idtab);
1171 $(this).val("");
1172 $("#qty_dispatched_0_"+idtab[2]).val("0");
1173 } else {
1174 obj = $(this).parent().parent();
1175 nameobj = obj.attr("name");
1176 nametab = nameobj.split("_");
1177 obj.remove();
1178 $("tr[name^=\'"+nametab[0]+"_\'][name$=\'_"+nametab[2]+"\']:last .splitbutton").show();
1179 }
1180 });
1181 });
1182
1183 $(".resetline").click(function(e){
1184 e.preventDefault();
1185 id = $(this).attr("id");
1186 id = id.split("reset_");
1187 console.log("Reset trigger for id = qty_"+id[1]);
1188 $("#qty_"+id[1]).val("");
1189 });
1190 });
1191 </script>';
1192
1193 // List of lines already dispatched
1194 $sql = "SELECT p.rowid as pid, p.ref, p.label,";
1195 $sql .= " e.rowid as warehouse_id, e.ref as entrepot,";
1196 $sql .= " cfd.rowid as dispatchlineid, cfd.fk_product, cfd.qty, cfd.eatby, cfd.sellby, cfd.batch, cfd.comment, cfd.status, cfd.datec";
1197 $sql .= " ,cd.rowid, cd.subprice";
1198 if (isModEnabled('reception')) {
1199 $sql .= " ,cfd.fk_reception, r.date_delivery";
1200 }
1201 $sql .= " FROM ".MAIN_DB_PREFIX."product as p,";
1202 $sql .= " ".MAIN_DB_PREFIX."receptiondet_batch as cfd";
1203 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."commande_fournisseurdet as cd ON cd.rowid = cfd.fk_elementdet";
1204 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."entrepot as e ON cfd.fk_entrepot = e.rowid";
1205 if (isModEnabled('reception')) {
1206 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."reception as r ON cfd.fk_reception = r.rowid";
1207 }
1208 $sql .= " WHERE cfd.fk_element = ".((int) $object->id);
1209 $sql .= " AND cfd.fk_product = p.rowid";
1210 $sql .= " ORDER BY cfd.rowid ASC";
1211
1212 $resql = $db->query($sql);
1213 if ($resql) {
1214 $num = $db->num_rows($resql);
1215 $i = 0;
1216
1217 if ($num > 0) {
1218 print "<br>\n";
1219
1220 print load_fiche_titre($langs->trans("ReceivingForSameOrder"));
1221
1222 print '<div class="div-table-responsive">';
1223 print '<table id="dispatch_received_products" class="noborder centpercent">';
1224
1225 print '<tr class="liste_titre">';
1226 // Reception ref
1227 if (isModEnabled("reception")) {
1228 print '<td>'.$langs->trans("Reception").'</td>';
1229 }
1230 // Product
1231 print '<td>'.$langs->trans("Product").'</td>';
1232 print '<td class="center">'.$langs->trans("DateCreation").'</td>';
1233 print '<td class="center">'.$langs->trans("DateDeliveryPlanned").'</td>';
1234 if (isModEnabled('productbatch')) {
1235 print '<td class="dispatch_batch_number_title">'.$langs->trans("batch_number").'</td>';
1236 if (!getDolGlobalString('PRODUCT_DISABLE_SELLBY')) {
1237 print '<td class="dispatch_dlc_title">'.$langs->trans("SellByDate").'</td>';
1238 }
1239 if (!getDolGlobalString('PRODUCT_DISABLE_EATBY')) {
1240 print '<td class="dispatch_dluo_title">'.$langs->trans("EatByDate").'</td>';
1241 }
1242 }
1243 print '<td class="right">'.$langs->trans("QtyDispatched").'</td>';
1244 print '<td>'.$langs->trans("Warehouse").'</td>';
1245 print '<td>'.$langs->trans("Comment").'</td>';
1246
1247 // Status
1248 if (getDolGlobalString('SUPPLIER_ORDER_USE_DISPATCH_STATUS') && $reception !== null && empty($reception->rowid)) {
1249 print '<td class="center" colspan="2">'.$langs->trans("Status").'</td>';
1250 } elseif (isModEnabled("reception")) {
1251 print '<td class="center"></td>';
1252 }
1253
1254 print '<td class="center" colspan="2"></td>';
1255
1256 print "</tr>\n";
1257
1258
1259
1260 $reception = null;
1261
1262 while ($i < $num) {
1263 $objp = $db->fetch_object($resql);
1264
1265 if ($action == 'editline' && $lineid == $objp->dispatchlineid) {
1266 print '<form name="editdispatchedlines" id="editdispatchedlines" action="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'#line_'.GETPOSTINT('lineid').'" method="POST">
1267 <input type="hidden" name="token" value="'.newToken().'">
1268 <input type="hidden" name="action" value="updateline">
1269 <input type="hidden" name="mode" value="">
1270 <input type="hidden" name="lineid" value="'.$objp->dispatchlineid.'">';
1271 }
1272
1273 print '<tr class="oddeven" id="line_'.$objp->dispatchlineid.'" >';
1274
1275 // Reception ref
1276 $reception = null;
1277 if (isModEnabled("reception")) {
1278 print '<td class="nowraponall">';
1279 if (!empty($objp->fk_reception)) {
1280 $reception = new Reception($db);
1281 $reception->fetch($objp->fk_reception);
1282 print $reception->getNomUrl(1);
1283 }
1284
1285 print "</td>";
1286 }
1287
1288 // Product
1289 print '<td class="tdoverflowmax150">';
1290 if (empty($conf->cache['product'][$objp->fk_product])) {
1291 $tmpproduct = new Product($db);
1292 $tmpproduct->fetch($objp->fk_product);
1293 $conf->cache['product'][$objp->fk_product] = $tmpproduct;
1294 } else {
1295 $tmpproduct = $conf->cache['product'][$objp->fk_product];
1296 }
1297 print $tmpproduct->getNomUrl(1);
1298 print ' - '.$objp->label;
1299 print "</td>\n";
1300
1301 // Date creation
1302 print '<td class="center">'.dol_print_date($db->jdate($objp->datec), 'day').'</td>';
1303
1304 // Date delivery
1305 if (property_exists($objp, "date_delivery")) {
1306 print '<td class="center">' . dol_print_date($db->jdate($objp->date_delivery), 'day') . '</td>';
1307 } else {
1308 print '<td class="center"></td>';
1309 }
1310
1311 // Batch / Eat by / Sell by
1312 if (isModEnabled('productbatch')) {
1313 if ($objp->batch) {
1314 include_once DOL_DOCUMENT_ROOT.'/product/stock/class/productlot.class.php';
1315 $lot = new Productlot($db);
1316 $lot->fetch(0, $objp->pid, $objp->batch);
1317 print '<td class="dispatch_batch_number">'.$lot->getNomUrl(1).'</td>';
1318 if (!getDolGlobalString('PRODUCT_DISABLE_SELLBY')) {
1319 print '<td class="dispatch_dlc">'.dol_print_date($lot->sellby, 'day').'</td>';
1320 }
1321 if (!getDolGlobalString('PRODUCT_DISABLE_EATBY')) {
1322 print '<td class="dispatch_dluo">'.dol_print_date($lot->eatby, 'day').'</td>';
1323 }
1324 } else {
1325 print '<td class="dispatch_batch_number"></td>';
1326 if (!getDolGlobalString('PRODUCT_DISABLE_SELLBY')) {
1327 print '<td class="dispatch_dlc"></td>';
1328 }
1329 if (!getDolGlobalString('PRODUCT_DISABLE_EATBY')) {
1330 print '<td class="dispatch_dluo"></td>';
1331 }
1332 }
1333 }
1334
1335 // Qty
1336 print '<td class="right">';
1337 if ($action == 'editline' && $lineid == $objp->dispatchlineid) {
1338 print '<input style="width: 50px;" type="text" min="1" name="qty" value="'.$objp->qty.'" />';
1339 } else {
1340 print $objp->qty;
1341 }
1342 print '<input type="hidden" name="price" value="'.$objp->subprice.'" />';
1343 print '</td>';
1344 // Warehouse
1345 print '<td class="tdoverflowmax150">';
1346 if ($action == 'editline' && $lineid == $objp->dispatchlineid) {
1347 $warehouse_id = GETPOSTINT("fk_entrepot") ? GETPOSTINT("fk_entrepot") : ($objp->warehouse_id ? $objp->warehouse_id : '');
1348 if (count($listwarehouses) > 1) {
1349 print $formproduct->selectWarehouses($warehouse_id, "fk_entrepot", '', 1, 0, $objp->fk_product, '', 1, 1, array(), 'csswarehouse');
1350 } elseif (count($listwarehouses) == 1) {
1351 print $formproduct->selectWarehouses($warehouse_id, "fk_entrepot", '', 0, 0, $objp->fk_product, '', 1, 1, array(), 'csswarehouse');
1352 } else {
1353 $langs->load("errors");
1354 print $langs->trans("ErrorNoWarehouseDefined");
1355 }
1356 } else {
1357 $warehouse_static->id = $objp->warehouse_id;
1358 $warehouse_static->label = $objp->entrepot;
1359 print $warehouse_static->getNomUrl(1);
1360 }
1361 print '</td>';
1362
1363 // Comment
1364 print '<td class="tdoverflowmax300" style="white-space: pre;">'.$objp->comment.'</td>';
1365
1366 // Status
1367 if (getDolGlobalString('SUPPLIER_ORDER_USE_DISPATCH_STATUS') && ($reception === null || empty($reception->rowid))) {
1368 print '<td class="right">';
1369 $supplierorderdispatch->status = (empty($objp->status) ? 0 : $objp->status);
1370 // print $supplierorderdispatch->status;
1371 print $supplierorderdispatch->getLibStatut(5);
1372 print '</td>';
1373
1374 // Add button to check/uncheck disaptching
1375 print '<td class="center">';
1376 if (!$permissiontocontrol) {
1377 if (empty($objp->status)) {
1378 print '<a class="button buttonRefused" href="#">'.$langs->trans("Approve").'</a>';
1379 print '<a class="button buttonRefused" href="#">'.$langs->trans("Deny").'</a>';
1380 } else {
1381 print '<a class="button buttonRefused" href="#">'.$langs->trans("Disapprove").'</a>';
1382 print '<a class="button buttonRefused" href="#">'.$langs->trans("Deny").'</a>';
1383 }
1384 } else {
1385 $disabled = '';
1386 if ($object->statut == 5) {
1387 $disabled = 1;
1388 }
1389 if (empty($objp->status)) {
1390 print '<a class="button'.($disabled ? ' buttonRefused' : '').'" href="'.$_SERVER["PHP_SELF"]."?id=".$id."&action=checkdispatchline&lineid=".$objp->dispatchlineid.'">'.$langs->trans("Approve").'</a>';
1391 print '<a class="button'.($disabled ? ' buttonRefused' : '').'" href="'.$_SERVER["PHP_SELF"]."?id=".$id."&action=denydispatchline&lineid=".$objp->dispatchlineid.'">'.$langs->trans("Deny").'</a>';
1392 }
1393 if ($objp->status == 1) {
1394 print '<a class="button'.($disabled ? ' buttonRefused' : '').'" href="'.$_SERVER["PHP_SELF"]."?id=".$id."&action=uncheckdispatchline&lineid=".$objp->dispatchlineid.'">'.$langs->trans("Reinit").'</a>';
1395 print '<a class="button'.($disabled ? ' buttonRefused' : '').'" href="'.$_SERVER["PHP_SELF"]."?id=".$id."&action=denydispatchline&lineid=".$objp->dispatchlineid.'">'.$langs->trans("Deny").'</a>';
1396 }
1397 if ($objp->status == 2) {
1398 print '<a class="button'.($disabled ? ' buttonRefused' : '').'" href="'.$_SERVER["PHP_SELF"]."?id=".$id."&action=uncheckdispatchline&lineid=".$objp->dispatchlineid.'">'.$langs->trans("Reinit").'</a>';
1399 print '<a class="button'.($disabled ? ' buttonRefused' : '').'" href="'.$_SERVER["PHP_SELF"]."?id=".$id."&action=checkdispatchline&lineid=".$objp->dispatchlineid.'">'.$langs->trans("Approve").'</a>';
1400 }
1401 }
1402 print '</td>';
1403 } elseif (isModEnabled("reception")) {
1404 print '<td class="right">';
1405 if ($reception !== null && !empty($reception->id)) {
1406 print $reception->getLibStatut(5);
1407 }
1408 print '</td>';
1409 }
1410
1411 // Action
1412 if ($action != 'editline' || $lineid != $objp->dispatchlineid) {
1413 if (($reception === null) || empty($reception->id) || ($reception->statut == Reception::STATUS_DRAFT)) { // only allow edit on draft reception
1414 print '<td class="linecoledit center">';
1415 print '<a class="reposition" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=editline&token='.newToken().'&lineid='.$objp->dispatchlineid.'#line_'.$objp->dispatchlineid.'">';
1416 print img_edit();
1417 print '</a>';
1418 print '</td>';
1419
1420 print '<td class="linecoldelete center">';
1421 print '<a href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=ask_deleteline&token='.newToken().'&lineid='.$objp->dispatchlineid.'#dispatch_received_products">';
1422 print img_delete();
1423 print '</a>';
1424 print '</td>';
1425 } else {
1426 print '<td></td><td></td>';
1427 }
1428 } else {
1429 print '<td class="center valignmiddle">';
1430 print '<input type="submit" class="button button-save" id="savelinebutton" name="save" value="'.$langs->trans("Save").'" />';
1431 print '</td>';
1432 print '<td class="center valignmiddle">';
1433 print '<input type="submit" class="button button-cancel" id="cancellinebutton" name="cancel" value="'.$langs->trans("Cancel").'" />';
1434 print '</td>';
1435 }
1436
1437
1438 print "</tr>\n";
1439 if ($action == 'editline' && $lineid == $objp->dispatchlineid) {
1440 print '</form>';
1441 }
1442
1443 $i++;
1444 }
1445 $db->free($resql);
1446
1447 print "</table>\n";
1448 print '</div>';
1449 }
1450 } else {
1451 dol_print_error($db);
1452 }
1453}
1454
1455// End of page
1456llxFooter();
1457$db->close();
$id
Definition account.php:48
if( $user->socid > 0) if(! $user->hasRight('accounting', 'chartofaccount')) $object
Definition card.php:66
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.
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
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:152
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.