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