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