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