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