dolibarr  17.0.4
dispatch.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (C) 2004-2006 Rodolphe Quiedeville <rodolphe@quiedeville.org>
3  * Copyright (C) 2004-2016 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
34 require '../../main.inc.php';
35 require_once DOL_DOCUMENT_ROOT.'/core/modules/supplier_order/modules_commandefournisseur.php';
36 require_once DOL_DOCUMENT_ROOT.'/product/stock/class/entrepot.class.php';
37 require_once DOL_DOCUMENT_ROOT.'/core/lib/fourn.lib.php';
38 require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.commande.class.php';
39 require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.commande.dispatch.class.php';
40 require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php';
41 require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
42 
43 if (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 
50 if (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 
63 if ($user->socid) {
64  $socid = $user->socid;
65 }
66 
67 $hookmanager->initHooks(array('ordersupplierdispatch'));
68 
69 // Recuperation de l'id de projet
70 $projectid = 0;
71 if (GETPOSTISSET("projectid")) {
72  $projectid = GETPOST("projectid", 'int');
73 }
74 
75 $object = new CommandeFournisseur($db);
76 
77 if ($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 
88 if (empty($conf->reception->enabled)) {
89  $permissiontoreceive = $user->rights->fournisseur->commande->receptionner;
90  $permissiontocontrol = ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->fournisseur->commande->receptionner)) || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->fournisseur->commande_advance->check)));
91 } else {
92  $permissiontoreceive = $user->rights->reception->creer;
93  $permissiontocontrol = ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->reception->creer)) || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->reception->reception_advance->validate)));
94 }
95 
96 // $id is id of a purchase order.
97 $result = restrictedArea($user, 'fournisseur', $id, 'commande_fournisseur', 'commande');
98 
99 if (!isModEnabled('stock')) {
100  accessforbidden();
101 }
102 
103 $usercancreate = ($user->rights->fournisseur->commande->creer || $user->rights->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
113 if ($reshook < 0) {
114  setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
115 }
116 
117 if ($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 
154 if ($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 
190 if ($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 
226 if ($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  header("Location: dispatch.php?id=".$id);
385  exit();
386  } else {
387  $db->rollback();
388  }
389 }
390 
391 // Remove a dispatched line
392 if ($action == 'confirm_deleteline' && $confirm == 'yes' && $permissiontoreceive) {
393  $db->begin();
394 
395  $supplierorderdispatch = new CommandeFournisseurDispatch($db);
396  $result = $supplierorderdispatch->fetch($lineid);
397  if ($result > 0) {
398  $qty = $supplierorderdispatch->qty;
399  $entrepot = $supplierorderdispatch->fk_entrepot;
400  $product = $supplierorderdispatch->fk_product;
401  $price = price2num(GETPOST('price', 'alpha'), 'MU');
402  $comment = $supplierorderdispatch->comment;
403  $eatby = $supplierorderdispatch->eatby;
404  $sellby = $supplierorderdispatch->sellby;
405  $batch = $supplierorderdispatch->batch;
406 
407  $result = $supplierorderdispatch->delete($user);
408  }
409  if ($result < 0) {
410  $errors = $object->errors;
411  $error++;
412  } else {
413  // If module stock is enabled and the stock increase is done on purchase order dispatching
414  if ($entrepot > 0 && isModEnabled('stock') && !empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER) && empty($supplierorderdispatch->fk_reception)) {
415  $mouv = new MouvementStock($db);
416  if ($product > 0) {
417  $mouv->origin = &$object;
418  $mouv->setOrigin($object->element, $object->id);
419  $result = $mouv->livraison($user, $product, $entrepot, $qty, $price, $comment, '', $eatby, $sellby, $batch);
420  if ($result < 0) {
421  $errors = $mouv->errors;
422  $error++;
423  }
424  }
425  }
426  }
427  if ($error > 0) {
428  $db->rollback();
429  setEventMessages($error, $errors, 'errors');
430  } else {
431  $db->commit();
432  }
433 }
434 
435 // Update a dispatched line
436 if ($action == 'updateline' && $permissiontoreceive) {
437  $db->begin();
438  $error = 0;
439 
440  $supplierorderdispatch = new CommandeFournisseurDispatch($db);
441  $result = $supplierorderdispatch->fetch($lineid);
442  if ($result > 0) {
443  $qty = $supplierorderdispatch->qty;
444  $entrepot = $supplierorderdispatch->fk_entrepot;
445  $product = $supplierorderdispatch->fk_product;
446  $price = price2num(GETPOST('price'), '', 2);
447  $comment = $supplierorderdispatch->comment;
448  $eatby = $supplierorderdispatch->eatby;
449  $sellby = $supplierorderdispatch->sellby;
450  $batch = $supplierorderdispatch->batch;
451 
452  $supplierorderdispatch->qty = price2num(GETPOST('qty', 'alpha'), 'MS', 2);
453  $supplierorderdispatch->fk_entrepot = GETPOST('fk_entrepot');
454  $result = $supplierorderdispatch->update($user);
455  }
456  if ($result < 0) {
457  $error++;
458  $errors = $supplierorderdispatch->errors;
459  } else {
460  // If module stock is enabled and the stock increase is done on purchase order dispatching
461  if ($entrepot > 0 && isModEnabled('stock') && !empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER)) {
462  $mouv = new MouvementStock($db);
463  if ($product > 0) {
464  $mouv->origin = &$object;
465  $mouv->setOrigin($object->element, $object->id);
466  $result = $mouv->livraison($user, $product, $entrepot, $qty, $price, $comment, '', $eatby, $sellby, $batch);
467  if ($result < 0) {
468  $errors = $mouv->errors;
469  $error++;
470  } else {
471  $mouv->origin = &$object;
472  $result = $mouv->reception($user, $product, $supplierorderdispatch->fk_entrepot, $supplierorderdispatch->qty, $price, $comment, $eatby, $sellby, $batch);
473  if ($result < 0) {
474  $errors = $mouv->errors;
475  $error++;
476  }
477  }
478  }
479  }
480  }
481  if ($error > 0) {
482  $db->rollback();
483  setEventMessages($error, $errors, 'errors');
484  } else {
485  $db->commit();
486  }
487 }
488 
489 /*
490  * View
491  */
492 
493 $now = dol_now();
494 
495 $form = new Form($db);
496 $formproduct = new FormProduct($db);
497 $warehouse_static = new Entrepot($db);
498 $supplierorderdispatch = new CommandeFournisseurDispatch($db);
499 
500 $title = $object->ref." - ".$langs->trans('OrderDispatch');
501 $help_url = 'EN:Module_Suppliers_Orders|FR:CommandeFournisseur|ES:Módulo_Pedidos_a_proveedores';
502 $morejs = array('/fourn/js/lib_dispatch.js.php');
503 
504 llxHeader('', $title, $help_url, '', 0, 0, $morejs);
505 
506 if ($id > 0 || !empty($ref)) {
507  $soc = new Societe($db);
508  $soc->fetch($object->socid);
509 
510  $author = new User($db);
511  $author->fetch($object->user_author_id);
512 
513  $head = ordersupplier_prepare_head($object);
514 
515  $title = $langs->trans("SupplierOrder");
516  print dol_get_fiche_head($head, 'dispatch', $title, -1, 'order');
517 
518  $formconfirm = '';
519 
520  // Confirmation to delete line
521  if ($action == 'ask_deleteline') {
522  $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id.'&lineid='.$lineid, $langs->trans('DeleteLine'), $langs->trans('ConfirmDeleteLine'), 'confirm_deleteline', '', 0, 1);
523  }
524 
525  // Call Hook formConfirm
526  $parameters = array('lineid' => $lineid);
527  // Note that $action and $object may be modified by hook
528  $reshook = $hookmanager->executeHooks('formConfirm', $parameters, $object, $action);
529  if (empty($reshook)) {
530  $formconfirm .= $hookmanager->resPrint;
531  } elseif ($reshook > 0) {
532  $formconfirm = $hookmanager->resPrint;
533  }
534 
535  // Print form confirm
536  print $formconfirm;
537 
538  // Supplier order card
539 
540  $linkback = '<a href="'.DOL_URL_ROOT.'/fourn/commande/list.php'.(!empty($socid) ? '?socid='.$socid : '').'">'.$langs->trans("BackToList").'</a>';
541 
542  $morehtmlref = '<div class="refidno">';
543  // Ref supplier
544  $morehtmlref .= $form->editfieldkey("RefSupplier", 'ref_supplier', $object->ref_supplier, $object, 0, 'string', '', 0, 1);
545  $morehtmlref .= $form->editfieldval("RefSupplier", 'ref_supplier', $object->ref_supplier, $object, 0, 'string', '', null, null, '', 1);
546  // Thirdparty
547  $morehtmlref .= '<br>'.$object->thirdparty->getNomUrl(1);
548  // Project
549  if (isModEnabled('project')) {
550  $langs->load("projects");
551  $morehtmlref .= '<br>';
552  if (0) {
553  $morehtmlref .= img_picto($langs->trans("Project"), 'project', 'class="pictofixedwidth"');
554  if ($action != 'classify' && $caneditproject) {
555  $morehtmlref .= '<a class="editfielda" href="'.$_SERVER['PHP_SELF'].'?action=classify&token='.newToken().'&id='.$object->id.'">'.img_edit($langs->transnoentitiesnoconv('SetProject')).'</a> ';
556  }
557  $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');
558  } else {
559  if (!empty($object->fk_project)) {
560  $proj = new Project($db);
561  $proj->fetch($object->fk_project);
562  $morehtmlref .= $proj->getNomUrl(1);
563  if ($proj->title) {
564  $morehtmlref .= '<span class="opacitymedium"> - '.dol_escape_htmltag($proj->title).'</span>';
565  }
566  }
567  }
568  }
569  $morehtmlref .= '</div>';
570 
571 
572  dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref);
573 
574 
575  print '<div class="fichecenter">';
576  print '<div class="underbanner clearboth"></div>';
577 
578  print '<table class="border tableforfield" width="100%">';
579 
580  // Date
581  if ($object->methode_commande_id > 0) {
582  print '<tr><td class="titlefield">'.$langs->trans("Date").'</td><td>';
583  if ($object->date_commande) {
584  print dol_print_date($object->date_commande, "dayhour")."\n";
585  }
586  print "</td></tr>";
587 
588  if ($object->methode_commande) {
589  print '<tr><td>'.$langs->trans("Method").'</td><td>'.$object->getInputMethod().'</td></tr>';
590  }
591  }
592 
593  // Author
594  print '<tr><td class="titlefield">'.$langs->trans("AuthorRequest").'</td>';
595  print '<td>'.$author->getNomUrl(1, '', 0, 0, 0).'</td>';
596  print '</tr>';
597 
598  $parameters = array();
599  $reshook = $hookmanager->executeHooks('formObjectOptions', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
600 
601  print "</table>";
602 
603  print '</div>';
604 
605  // if ($mesg) print $mesg;
606  print '<br>';
607 
608  /*$disabled = 1;
609  if (!empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER)) {
610  $disabled = 0;
611  }*/
612  $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.
613 
614  // Line of orders
615  if ($object->statut <= CommandeFournisseur::STATUS_ACCEPTED || $object->statut >= CommandeFournisseur::STATUS_CANCELED) {
616  print '<br><span class="opacitymedium">'.$langs->trans("OrderStatusNotReadyToDispatch").'</span>';
617  }
618 
619  if ($object->statut == CommandeFournisseur::STATUS_ORDERSENT
621  || $object->statut == CommandeFournisseur::STATUS_RECEIVED_COMPLETELY) {
622  require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php';
623  $formproduct = new FormProduct($db);
624  $formproduct->loadWarehouses();
625  $entrepot = new Entrepot($db);
626  $listwarehouses = $entrepot->list_array(1);
627 
628 
629  if (empty($conf->reception->enabled)) {
630  print '<form method="POST" action="dispatch.php?id='.$object->id.'">';
631  } else {
632  print '<form method="post" action="'.dol_buildpath('/reception/card.php', 1).'?originid='.$object->id.'&origin=supplierorder">';
633  }
634 
635  print '<input type="hidden" name="token" value="'.newToken().'">';
636  if (empty($conf->reception->enabled)) {
637  print '<input type="hidden" name="action" value="dispatch">';
638  } else {
639  print '<input type="hidden" name="action" value="create">';
640  }
641 
642  print '<div class="div-table-responsive-no-min">';
643  print '<table class="noborder centpercent">';
644 
645  // Set $products_dispatched with qty dispatched for each product id
646  $products_dispatched = array();
647  $sql = "SELECT l.rowid, cfd.fk_product, sum(cfd.qty) as qty";
648  $sql .= " FROM ".MAIN_DB_PREFIX."commande_fournisseur_dispatch as cfd";
649  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."commande_fournisseurdet as l on l.rowid = cfd.fk_commandefourndet";
650  $sql .= " WHERE cfd.fk_commande = ".((int) $object->id);
651  $sql .= " GROUP BY l.rowid, cfd.fk_product";
652 
653  $resql = $db->query($sql);
654  if ($resql) {
655  $num = $db->num_rows($resql);
656  $i = 0;
657 
658  if ($num) {
659  while ($i < $num) {
660  $objd = $db->fetch_object($resql);
661  $products_dispatched[$objd->rowid] = price2num($objd->qty, 5);
662  $i++;
663  }
664  }
665  $db->free($resql);
666  }
667 
668  //$sql = "SELECT l.rowid, l.fk_product, l.subprice, l.remise_percent, l.ref AS sref, SUM(l.qty) as qty,";
669  $sql = "SELECT l.rowid, l.fk_product, l.subprice, l.remise_percent, l.ref AS sref, l.qty as qty,";
670  $sql .= " p.ref, p.label, p.tobatch, p.fk_default_warehouse";
671 
672  // Enable hooks to alter the SQL query (SELECT)
673  $parameters = array();
674  $reshook = $hookmanager->executeHooks(
675  'printFieldListSelect',
676  $parameters,
677  $object,
678  $action
679  );
680  if ($reshook < 0) {
681  setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
682  }
683  $sql .= $hookmanager->resPrint;
684 
685  $sql .= " FROM ".MAIN_DB_PREFIX."commande_fournisseurdet as l";
686  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product as p ON l.fk_product=p.rowid";
687  $sql .= " WHERE l.fk_commande = ".((int) $object->id);
688  if (empty($conf->global->STOCK_SUPPORTS_SERVICES)) {
689  $sql .= " AND l.product_type = 0";
690  }
691 
692  // Enable hooks to alter the SQL query (WHERE)
693  $parameters = array();
694  $reshook = $hookmanager->executeHooks(
695  'printFieldListWhere',
696  $parameters,
697  $object,
698  $action
699  );
700  if ($reshook < 0) {
701  setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
702  }
703  $sql .= $hookmanager->resPrint;
704 
705  //$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
706  $sql .= " ORDER BY l.rang, p.ref, p.label";
707 
708  $resql = $db->query($sql);
709  if ($resql) {
710  $num = $db->num_rows($resql);
711  $i = 0;
712 
713  if ($num) {
714  print '<tr class="liste_titre">';
715 
716  print '<td>'.$langs->trans("Description").'</td>';
717  if (isModEnabled('productbatch')) {
718  print '<td class="dispatch_batch_number_title">'.$langs->trans("batch_number").'</td>';
719  if (empty($conf->global->PRODUCT_DISABLE_SELLBY)) {
720  print '<td class="dispatch_dlc_title">'.$langs->trans("SellByDate").'</td>';
721  }
722  if (empty($conf->global->PRODUCT_DISABLE_EATBY)) {
723  print '<td class="dispatch_dluo_title">'.$langs->trans("EatByDate").'</td>';
724  }
725  } else {
726  print '<td></td>';
727  print '<td></td>';
728  print '<td></td>';
729  }
730  print '<td class="right">'.$langs->trans("SupplierRef").'</td>';
731  print '<td class="right">'.$langs->trans("QtyOrdered").'</td>';
732  print '<td class="right">'.$langs->trans("QtyDispatchedShort").'</td>';
733  print ' <td class="right">'.$langs->trans("QtyToDispatchShort");
734  print '<br><a href="#" id="autoreset">'.$langs->trans("Reset").'</a></td>';
735  print '<td width="32"></td>';
736 
737  if (!empty($conf->global->SUPPLIER_ORDER_CAN_UPDATE_BUYINGPRICE_DURING_RECEIPT)) {
738  if (!isModEnabled("multicurrency") && empty($conf->dynamicprices->enabled)) {
739  print '<td class="right">'.$langs->trans("Price").'</td>';
740  print '<td class="right">'.$langs->trans("ReductionShort").' (%)</td>';
741  print '<td class="right">'.$langs->trans("UpdatePrice").'</td>';
742  }
743  }
744 
745  print '<td align="right">'.$langs->trans("Warehouse");
746 
747  // Select warehouse to force it everywhere
748  if (count($listwarehouses) > 1) {
749  print '<br><span class="opacitymedium">'.$langs->trans("ForceTo").'</span> '.$form->selectarray('fk_default_warehouse', $listwarehouses, $fk_default_warehouse, 1, 0, 0, '', 0, 0, $disabled, '', 'minwidth100 maxwidth300', 1);
750  } elseif (count($listwarehouses) == 1) {
751  print '<br><span class="opacitymedium">'.$langs->trans("ForceTo").'</span> '.$form->selectarray('fk_default_warehouse', $listwarehouses, $fk_default_warehouse, 0, 0, 0, '', 0, 0, $disabled, '', 'minwidth100 maxwidth300', 1);
752  }
753 
754  print '</td>';
755 
756  // Enable hooks to append additional columns
757  $parameters = array();
758  $reshook = $hookmanager->executeHooks(
759  'printFieldListTitle',
760  $parameters,
761  $object,
762  $action
763  );
764  if ($reshook < 0) {
765  setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
766  }
767  print $hookmanager->resPrint;
768 
769  print "</tr>\n";
770  }
771 
772  $nbfreeproduct = 0; // Nb of lins of free products/services
773  $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)
774  // or nb of line that remain to dispatch if SUPPLIER_ORDER_DISABLE_STOCK_DISPATCH_WHEN_TOTAL_REACHED is on.
775 
776  $conf->cache['product'] = array();
777 
778  while ($i < $num) {
779  $objp = $db->fetch_object($resql);
780 
781  // On n'affiche pas les produits libres
782  if (!$objp->fk_product > 0) {
783  $nbfreeproduct++;
784  } else {
785  $alreadydispatched = isset($products_dispatched[$objp->rowid])?$products_dispatched[$objp->rowid]:0;
786  $remaintodispatch = price2num($objp->qty - ((float) $alreadydispatched), 5); // Calculation of dispatched
787  if ($remaintodispatch < 0 && empty($conf->global->SUPPLIER_ORDER_ALLOW_NEGATIVE_QTY_FOR_SUPPLIER_ORDER_RETURN)) {
788  $remaintodispatch = 0;
789  }
790 
791  if ($remaintodispatch || empty($conf->global->SUPPLIER_ORDER_DISABLE_STOCK_DISPATCH_WHEN_TOTAL_REACHED)) {
792  $nbproduct++;
793 
794  // To show detail cref and description value, we must make calculation by cref
795  // print ($objp->cref?' ('.$objp->cref.')':'');
796  // if ($objp->description) print '<br>'.nl2br($objp->description);
797  $suffix = '_0_'.$i;
798 
799  print "\n";
800  print '<!-- Line to dispatch '.$suffix.' -->'."\n";
801  // hidden fields for js function
802  print '<input id="qty_ordered'.$suffix.'" type="hidden" value="'.$objp->qty.'">';
803  print '<input id="qty_dispatched'.$suffix.'" type="hidden" value="'.(float) $alreadydispatched.'">';
804  print '<tr class="oddeven">';
805 
806  if (empty($conf->cache['product'][$objp->fk_product])) {
807  $tmpproduct = new Product($db);
808  $tmpproduct->fetch($objp->fk_product);
809  $conf->cache['product'][$objp->fk_product] = $tmpproduct;
810  } else {
811  $tmpproduct = $conf->cache['product'][$objp->fk_product];
812  }
813 
814  $linktoprod = $tmpproduct->getNomUrl(1);
815  $linktoprod .= ' - '.$objp->label."\n";
816 
817  if (isModEnabled('productbatch')) {
818  if ($objp->tobatch) {
819  // Product
820  print '<td>';
821  print $linktoprod;
822  print "</td>";
823  print '<td class="dispatch_batch_number"></td>';
824  if (empty($conf->global->PRODUCT_DISABLE_SELLBY)) {
825  print '<td class="dispatch_dlc"></td>';
826  }
827  if (empty($conf->global->PRODUCT_DISABLE_EATBY)) {
828  print '<td class="dispatch_dluo"></td>';
829  }
830  } else {
831  // Product
832  print '<td>';
833  print $linktoprod;
834  print "</td>";
835  print '<td class="dispatch_batch_number">';
836  print $langs->trans("ProductDoesNotUseBatchSerial");
837  print '</td>';
838  if (empty($conf->global->PRODUCT_DISABLE_SELLBY)) {
839  print '<td class="dispatch_dlc"></td>';
840  }
841  if (empty($conf->global->PRODUCT_DISABLE_EATBY)) {
842  print '<td class="dispatch_dluo"></td>';
843  }
844  }
845  } else {
846  print '<td colspan="4">';
847  print $linktoprod;
848  print "</td>";
849  }
850 
851  // Define unit price for PMP calculation
852  $up_ht_disc = $objp->subprice;
853  if (!empty($objp->remise_percent) && empty($conf->global->STOCK_EXCLUDE_DISCOUNT_FOR_PMP)) {
854  $up_ht_disc = price2num($up_ht_disc * (100 - $objp->remise_percent) / 100, 'MU');
855  }
856 
857  // Supplier ref
858  print '<td class="right">'.$objp->sref.'</td>';
859 
860  // Qty ordered
861  print '<td class="right">'.$objp->qty.'</td>';
862 
863  // Already dispatched
864  print '<td class="right">'.$alreadydispatched.'</td>';
865 
866  if (isModEnabled('productbatch') && $objp->tobatch > 0) {
867  $type = 'batch';
868  print '<td class="right">';
869  print '</td>'; // Qty to dispatch
870  print '<td>';
871  //print img_picto($langs->trans('AddDispatchBatchLine'), 'split.png', 'onClick="addDispatchLine(' . $i . ',\'' . $type . '\')"');
872  print '</td>'; // Dispatch column
873  print '<td></td>'; // Warehouse column
874 
875  // Enable hooks to append additional columns
876  $parameters = array(
877  // allows hook to distinguish between the rows with information and the rows with dispatch form input
878  'is_information_row' => true,
879  'i' => $i,
880  'suffix' => $suffix,
881  'objp' => $objp,
882  );
883  $reshook = $hookmanager->executeHooks(
884  'printFieldListValue',
885  $parameters,
886  $object,
887  $action
888  );
889  if ($reshook < 0) {
890  setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
891  }
892  print $hookmanager->resPrint;
893 
894  print '</tr>';
895 
896  print '<tr class="oddeven" name="'.$type.$suffix.'">';
897  print '<td>';
898  print '<input name="fk_commandefourndet'.$suffix.'" type="hidden" value="'.$objp->rowid.'">';
899  print '<input name="product_batch'.$suffix.'" type="hidden" value="'.$objp->fk_product.'">';
900 
901  print '<!-- This is a up (may include discount or not depending on STOCK_EXCLUDE_DISCOUNT_FOR_PMP. will be used for PMP calculation) -->';
902  if (!empty($conf->global->SUPPLIER_ORDER_EDIT_BUYINGPRICE_DURING_RECEIPT)) { // Not tested !
903  print $langs->trans("BuyingPrice").': <input class="maxwidth75" name="pu'.$suffix.'" type="text" value="'.price2num($up_ht_disc, 'MU').'">';
904  } else {
905  print '<input class="maxwidth75" name="pu'.$suffix.'" type="hidden" value="'.price2num($up_ht_disc, 'MU').'">';
906  }
907 
908  print '</td>';
909 
910  print '<td>';
911  print '<input type="text" class="inputlotnumber quatrevingtquinzepercent" id="lot_number'.$suffix.'" name="lot_number'.$suffix.'" value="'.GETPOST('lot_number'.$suffix).'">';
912  print '</td>';
913  if (empty($conf->global->PRODUCT_DISABLE_SELLBY)) {
914  print '<td class="nowraponall">';
915  $dlcdatesuffix = dol_mktime(0, 0, 0, GETPOST('dlc'.$suffix.'month'), GETPOST('dlc'.$suffix.'day'), GETPOST('dlc'.$suffix.'year'));
916  print $form->selectDate($dlcdatesuffix, 'dlc'.$suffix, '', '', 1, '');
917  print '</td>';
918  }
919  if (empty($conf->global->PRODUCT_DISABLE_EATBY)) {
920  print '<td class="nowraponall">';
921  $dluodatesuffix = dol_mktime(0, 0, 0, GETPOST('dluo'.$suffix.'month'), GETPOST('dluo'.$suffix.'day'), GETPOST('dluo'.$suffix.'year'));
922  print $form->selectDate($dluodatesuffix, 'dluo'.$suffix, '', '', 1, '');
923  print '</td>';
924  }
925  print '<td colspan="3">&nbsp;</td>'; // Supplier ref + Qty ordered + qty already dispatched
926  } else {
927  $type = 'dispatch';
928  $colspan = 7;
929  $colspan = (!empty($conf->global->PRODUCT_DISABLE_SELLBY)) ? --$colspan : $colspan;
930  $colspan = (!empty($conf->global->PRODUCT_DISABLE_EATBY)) ? --$colspan : $colspan;
931  print '<td class="right">';
932  print '</td>'; // Qty to dispatch
933  print '<td>';
934  //print img_picto($langs->trans('AddStockLocationLine'), 'split.png', 'onClick="addDispatchLine(' . $i . ',\'' . $type . '\')"');
935  print '</td>'; // Dispatch column
936  print '<td></td>'; // Warehouse column
937 
938  // Enable hooks to append additional columns
939  $parameters = array(
940  // allows hook to distinguish between the rows with information and the rows with dispatch form input
941  'is_information_row' => true,
942  'i' => $i,
943  'suffix' => $suffix,
944  'objp' => $objp,
945  );
946  $reshook = $hookmanager->executeHooks(
947  'printFieldListValue',
948  $parameters,
949  $object,
950  $action
951  );
952  if ($reshook < 0) {
953  setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
954  }
955  print $hookmanager->resPrint;
956 
957  print '</tr>';
958 
959  print '<tr class="oddeven" name="'.$type.$suffix.'">';
960  print '<td colspan="'.$colspan.'">';
961  print '<input name="fk_commandefourndet'.$suffix.'" type="hidden" value="'.$objp->rowid.'">';
962  print '<input name="product'.$suffix.'" type="hidden" value="'.$objp->fk_product.'">';
963 
964  print '<!-- This is a up (may include discount or not depending on STOCK_EXCLUDE_DISCOUNT_FOR_PMP. will be used for PMP calculation) -->';
965  if (!empty($conf->global->SUPPLIER_ORDER_EDIT_BUYINGPRICE_DURING_RECEIPT)) { // Not tested !
966  print $langs->trans("BuyingPrice").': <input class="maxwidth75" name="pu'.$suffix.'" type="text" value="'.price2num($up_ht_disc, 'MU').'">';
967  } else {
968  print '<input class="maxwidth75" name="pu'.$suffix.'" type="hidden" value="'.price2num($up_ht_disc, 'MU').'">';
969  }
970 
971  print '</td>';
972  }
973 
974  // Qty to dispatch
975  print '<td class="right">';
976  print '<input id="qty'.$suffix.'" name="qty'.$suffix.'" type="text" class="width50 right" value="'.(GETPOSTISSET('qty'.$suffix) ? GETPOST('qty'.$suffix, 'int') : (empty($conf->global->SUPPLIER_ORDER_DISPATCH_FORCE_QTY_INPUT_TO_ZERO) ? $remaintodispatch : 0)).'">';
977  print '</td>';
978 
979  print '<td>';
980  if (isModEnabled('productbatch') && $objp->tobatch > 0) {
981  $type = 'batch';
982  print img_picto($langs->trans('AddStockLocationLine'), 'split.png', 'class="splitbutton" onClick="addDispatchLine('.$i.', \''.$type.'\')"');
983  } else {
984  $type = 'dispatch';
985  print img_picto($langs->trans('AddStockLocationLine'), 'split.png', 'class="splitbutton" onClick="addDispatchLine('.$i.', \''.$type.'\')"');
986  }
987  print '</td>';
988 
989  if (!empty($conf->global->SUPPLIER_ORDER_CAN_UPDATE_BUYINGPRICE_DURING_RECEIPT)) {
990  if (!isModEnabled("multicurrency") && empty($conf->dynamicprices->enabled)) {
991  // Price
992  print '<td class="right">';
993  print '<input id="pu'.$suffix.'" name="pu'.$suffix.'" type="text" size="8" value="'.price((GETPOST('pu'.$suffix) != '' ? price2num(GETPOST('pu'.$suffix)) : $up_ht_disc)).'">';
994  print '</td>';
995 
996  // Discount
997  print '<td class="right">';
998  print '<input id="dto'.$suffix.'" name="dto'.$suffix.'" type="text" size="8" value="'.(GETPOST('dto'.$suffix) != '' ? GETPOST('dto'.$suffix) : '').'">';
999  print '</td>';
1000 
1001  // Save price
1002  print '<td class="center">';
1003  print '<input class="flat checkformerge" type="checkbox" name="saveprice'.$suffix.'" value="'.(GETPOST('saveprice'.$suffix) != '' ? GETPOST('saveprice'.$suffix) : '').'">';
1004  print '</td>';
1005  }
1006  }
1007 
1008  // Warehouse
1009  print '<td class="right">';
1010  if (count($listwarehouses) > 1) {
1011  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);
1012  } elseif (count($listwarehouses) == 1) {
1013  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);
1014  } else {
1015  $langs->load("errors");
1016  print $langs->trans("ErrorNoWarehouseDefined");
1017  }
1018  print "</td>\n";
1019 
1020  // Enable hooks to append additional columns
1021  $parameters = array(
1022  'is_information_row' => false, // this is a dispatch form row
1023  'i' => $i,
1024  'suffix' => $suffix,
1025  'objp' => $objp,
1026  );
1027  $reshook = $hookmanager->executeHooks(
1028  'printFieldListValue',
1029  $parameters,
1030  $object,
1031  $action
1032  );
1033  if ($reshook < 0) {
1034  setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
1035  }
1036  print $hookmanager->resPrint;
1037 
1038  print "</tr>\n";
1039  }
1040  }
1041  $i++;
1042  }
1043  $db->free($resql);
1044  } else {
1045  dol_print_error($db);
1046  }
1047 
1048  print "</table>\n";
1049  print '</div>';
1050 
1051  if ($nbproduct) {
1052  $checkboxlabel = $langs->trans("CloseReceivedSupplierOrdersAutomatically", $langs->transnoentitiesnoconv('StatusOrderReceivedAll'));
1053 
1054  print '<div class="center">';
1055  $parameters = array();
1056  $reshook = $hookmanager->executeHooks('addMoreActionsButtons', $parameters, $object, $action); // Note that $action and $object may have been
1057  // modified by hook
1058  if (empty($reshook)) {
1059  if (empty($conf->reception->enabled)) {
1060  print $langs->trans("Comment").' : ';
1061  print '<input type="text" class="minwidth400" maxlength="128" name="comment" value="';
1062  print GETPOSTISSET("comment") ? GETPOST("comment") : $langs->trans("DispatchSupplierOrder", $object->ref);
1063  // print ' / '.$object->ref_supplier; // Not yet available
1064  print '" class="flat"><br>';
1065 
1066  print '<input type="checkbox" checked="checked" name="closeopenorder"> '.$checkboxlabel;
1067  }
1068 
1069  $dispatchBt = empty($conf->reception->enabled) ? $langs->trans("Receive") : $langs->trans("CreateReception");
1070 
1071  print '<br>';
1072  print '<input type="hidden" name="backtopageforcancel" value="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'">';
1073  print '<input type="submit" class="button" name="dispatch" value="'.dol_escape_htmltag($dispatchBt).'"';
1074  $disabled = 0;
1075  if (!$permissiontoreceive) {
1076  $disabled = 1;
1077  }
1078  if (count($listwarehouses) <= 0) {
1079  $disabled = 1;
1080  }
1081  if ($disabled) {
1082  print ' disabled';
1083  }
1084 
1085  print '>';
1086  }
1087  print '</div>';
1088  }
1089 
1090  // Message if nothing to dispatch
1091  if (!$nbproduct) {
1092  print "<br>\n";
1093  if (empty($conf->global->SUPPLIER_ORDER_DISABLE_STOCK_DISPATCH_WHEN_TOTAL_REACHED)) {
1094  print '<div class="opacitymedium">'.$langs->trans("NoPredefinedProductToDispatch").'</div>'; // No predefined line at all
1095  } else {
1096  print '<div class="opacitymedium">'.$langs->trans("NoMorePredefinedProductToDispatch").'</div>'; // No predefined line that remain to be dispatched.
1097  }
1098  }
1099 
1100  print '</form>';
1101  }
1102 
1103  print dol_get_fiche_end();
1104 
1105  // traitement entrepot par défaut
1106  print '<script type="text/javascript">
1107  $(document).ready(function () {
1108  $("select[name=fk_default_warehouse]").change(function() {
1109  var fk_default_warehouse = $("option:selected", this).val();
1110  $("select[name^=entrepot_]").val(fk_default_warehouse).change();
1111  });
1112 
1113  jQuery("#autoreset").click(function() {';
1114  $i = 0;
1115  while ($i < $nbproduct) {
1116  print ' jQuery("#qty_0_'.$i.'").val("");';
1117  $i++;
1118  }
1119  print '
1120  });
1121  });
1122  </script>';
1123 
1124  // List of lines already dispatched
1125  $sql = "SELECT p.rowid as pid, p.ref, p.label,";
1126  $sql .= " e.rowid as warehouse_id, e.ref as entrepot,";
1127  $sql .= " cfd.rowid as dispatchlineid, cfd.fk_product, cfd.qty, cfd.eatby, cfd.sellby, cfd.batch, cfd.comment, cfd.status, cfd.datec";
1128  $sql .= " ,cd.rowid, cd.subprice";
1129  if ($conf->reception->enabled) {
1130  $sql .= " ,cfd.fk_reception, r.date_delivery";
1131  }
1132  $sql .= " FROM ".MAIN_DB_PREFIX."product as p,";
1133  $sql .= " ".MAIN_DB_PREFIX."commande_fournisseur_dispatch as cfd";
1134  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."commande_fournisseurdet as cd ON cd.rowid = cfd.fk_commandefourndet";
1135  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."entrepot as e ON cfd.fk_entrepot = e.rowid";
1136  if ($conf->reception->enabled) {
1137  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."reception as r ON cfd.fk_reception = r.rowid";
1138  }
1139  $sql .= " WHERE cfd.fk_commande = ".((int) $object->id);
1140  $sql .= " AND cfd.fk_product = p.rowid";
1141  $sql .= " ORDER BY cfd.rowid ASC";
1142 
1143  $resql = $db->query($sql);
1144  if ($resql) {
1145  $num = $db->num_rows($resql);
1146  $i = 0;
1147 
1148  if ($num > 0) {
1149  print "<br>\n";
1150 
1151  print load_fiche_titre($langs->trans("ReceivingForSameOrder"));
1152 
1153  print '<div class="div-table-responsive">';
1154  print '<table id="dispatch_received_products" class="noborder centpercent">';
1155 
1156  print '<tr class="liste_titre">';
1157  // Reception ref
1158  if ($conf->reception->enabled) {
1159  print '<td>'.$langs->trans("Reception").'</td>';
1160  }
1161  // Product
1162  print '<td>'.$langs->trans("Product").'</td>';
1163  print '<td class="center">'.$langs->trans("DateCreation").'</td>';
1164  print '<td class="center">'.$langs->trans("DateDeliveryPlanned").'</td>';
1165  if (isModEnabled('productbatch')) {
1166  print '<td class="dispatch_batch_number_title">'.$langs->trans("batch_number").'</td>';
1167  if (empty($conf->global->PRODUCT_DISABLE_SELLBY)) {
1168  print '<td class="dispatch_dlc_title">'.$langs->trans("SellByDate").'</td>';
1169  }
1170  if (empty($conf->global->PRODUCT_DISABLE_EATBY)) {
1171  print '<td class="dispatch_dluo_title">'.$langs->trans("EatByDate").'</td>';
1172  }
1173  }
1174  print '<td class="right">'.$langs->trans("QtyDispatched").'</td>';
1175  print '<td>'.$langs->trans("Warehouse").'</td>';
1176  print '<td>'.$langs->trans("Comment").'</td>';
1177 
1178  // Status
1179  if (!empty($conf->global->SUPPLIER_ORDER_USE_DISPATCH_STATUS) && empty($reception->rowid)) {
1180  print '<td class="center" colspan="2">'.$langs->trans("Status").'</td>';
1181  } elseif (isModEnabled("reception")) {
1182  print '<td class="center"></td>';
1183  }
1184 
1185  print '<td class="center" colspan="2"></td>';
1186 
1187  print "</tr>\n";
1188 
1189 
1190  while ($i < $num) {
1191  $objp = $db->fetch_object($resql);
1192 
1193  if ($action == 'editline' && $lineid == $objp->dispatchlineid) {
1194  print '<form name="editdispatchedlines" id="editdispatchedlines" action="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'#line_'.GETPOST('lineid', 'int').'" method="POST">
1195  <input type="hidden" name="token" value="'.newToken().'">
1196  <input type="hidden" name="action" value="updateline">
1197  <input type="hidden" name="mode" value="">
1198  <input type="hidden" name="lineid" value="'.$objp->dispatchlineid.'">';
1199  }
1200 
1201  print '<tr class="oddeven" id="line_'.$objp->dispatchlineid.'" >';
1202 
1203  // Reception ref
1204  if (isModEnabled("reception")) {
1205  print '<td class="nowraponall">';
1206  if (!empty($objp->fk_reception)) {
1207  $reception = new Reception($db);
1208  $reception->fetch($objp->fk_reception);
1209  print $reception->getNomUrl(1);
1210  }
1211 
1212  print "</td>";
1213  }
1214 
1215  // Product
1216  print '<td class="tdoverflowmax150">';
1217  if (empty($conf->cache['product'][$objp->fk_product])) {
1218  $tmpproduct = new Product($db);
1219  $tmpproduct->fetch($objp->fk_product);
1220  $conf->cache['product'][$objp->fk_product] = $tmpproduct;
1221  } else {
1222  $tmpproduct = $conf->cache['product'][$objp->fk_product];
1223  }
1224  print $tmpproduct->getNomUrl(1);
1225  print ' - '.$objp->label;
1226  print "</td>\n";
1227 
1228  // Date creation
1229  print '<td class="center">'.dol_print_date($db->jdate($objp->datec), 'day').'</td>';
1230 
1231  // Date delivery
1232  print '<td class="center">'.dol_print_date($db->jdate($objp->date_delivery), 'day').'</td>';
1233 
1234  // Batch / Eat by / Sell by
1235  if (isModEnabled('productbatch')) {
1236  if ($objp->batch) {
1237  include_once DOL_DOCUMENT_ROOT.'/product/stock/class/productlot.class.php';
1238  $lot = new Productlot($db);
1239  $lot->fetch(0, $objp->pid, $objp->batch);
1240  print '<td class="dispatch_batch_number">'.$lot->getNomUrl(1).'</td>';
1241  if (empty($conf->global->PRODUCT_DISABLE_SELLBY)) {
1242  print '<td class="dispatch_dlc">'.dol_print_date($lot->sellby, 'day').'</td>';
1243  }
1244  if (empty($conf->global->PRODUCT_DISABLE_EATBY)) {
1245  print '<td class="dispatch_dluo">'.dol_print_date($lot->eatby, 'day').'</td>';
1246  }
1247  } else {
1248  print '<td class="dispatch_batch_number"></td>';
1249  if (empty($conf->global->PRODUCT_DISABLE_SELLBY)) {
1250  print '<td class="dispatch_dlc"></td>';
1251  }
1252  if (empty($conf->global->PRODUCT_DISABLE_EATBY)) {
1253  print '<td class="dispatch_dluo"></td>';
1254  }
1255  }
1256  }
1257 
1258  // Qty
1259  print '<td class="right">';
1260  if ($action == 'editline' && $lineid == $objp->dispatchlineid) {
1261  print '<input style="width: 50px;" type="text" min="1" name="qty" value="'.$objp->qty.'" />';
1262  } else {
1263  print $objp->qty;
1264  }
1265  print '<input type="hidden" name="price" value="'.$objp->subprice.'" />';
1266  print '</td>';
1267 
1268  // Warehouse
1269  print '<td class="tdoverflowmax150">';
1270  if ($action == 'editline' && $lineid == $objp->dispatchlineid) {
1271  if (count($listwarehouses) > 1) {
1272  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');
1273  } elseif (count($listwarehouses) == 1) {
1274  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');
1275  } else {
1276  $langs->load("errors");
1277  print $langs->trans("ErrorNoWarehouseDefined");
1278  }
1279  } else {
1280  $warehouse_static->id = $objp->warehouse_id;
1281  $warehouse_static->label = $objp->entrepot;
1282  print $warehouse_static->getNomUrl(1);
1283  }
1284  print '</td>';
1285 
1286  // Comment
1287  print '<td class="tdoverflowmax300" style="white-space: pre;">'.$objp->comment.'</td>';
1288 
1289  // Status
1290  if (!empty($conf->global->SUPPLIER_ORDER_USE_DISPATCH_STATUS) && empty($reception->rowid)) {
1291  print '<td class="right">';
1292  $supplierorderdispatch->status = (empty($objp->status) ? 0 : $objp->status);
1293  // print $supplierorderdispatch->status;
1294  print $supplierorderdispatch->getLibStatut(5);
1295  print '</td>';
1296 
1297  // Add button to check/uncheck disaptching
1298  print '<td class="center">';
1299  if (!$permissiontocontrol) {
1300  if (empty($objp->status)) {
1301  print '<a class="button buttonRefused" href="#">'.$langs->trans("Approve").'</a>';
1302  print '<a class="button buttonRefused" href="#">'.$langs->trans("Deny").'</a>';
1303  } else {
1304  print '<a class="button buttonRefused" href="#">'.$langs->trans("Disapprove").'</a>';
1305  print '<a class="button buttonRefused" href="#">'.$langs->trans("Deny").'</a>';
1306  }
1307  } else {
1308  $disabled = '';
1309  if ($object->statut == 5) {
1310  $disabled = 1;
1311  }
1312  if (empty($objp->status)) {
1313  print '<a class="button'.($disabled ? ' buttonRefused' : '').'" href="'.$_SERVER["PHP_SELF"]."?id=".$id."&action=checkdispatchline&lineid=".$objp->dispatchlineid.'">'.$langs->trans("Approve").'</a>';
1314  print '<a class="button'.($disabled ? ' buttonRefused' : '').'" href="'.$_SERVER["PHP_SELF"]."?id=".$id."&action=denydispatchline&lineid=".$objp->dispatchlineid.'">'.$langs->trans("Deny").'</a>';
1315  }
1316  if ($objp->status == 1) {
1317  print '<a class="button'.($disabled ? ' buttonRefused' : '').'" href="'.$_SERVER["PHP_SELF"]."?id=".$id."&action=uncheckdispatchline&lineid=".$objp->dispatchlineid.'">'.$langs->trans("Reinit").'</a>';
1318  print '<a class="button'.($disabled ? ' buttonRefused' : '').'" href="'.$_SERVER["PHP_SELF"]."?id=".$id."&action=denydispatchline&lineid=".$objp->dispatchlineid.'">'.$langs->trans("Deny").'</a>';
1319  }
1320  if ($objp->status == 2) {
1321  print '<a class="button'.($disabled ? ' buttonRefused' : '').'" href="'.$_SERVER["PHP_SELF"]."?id=".$id."&action=uncheckdispatchline&lineid=".$objp->dispatchlineid.'">'.$langs->trans("Reinit").'</a>';
1322  print '<a class="button'.($disabled ? ' buttonRefused' : '').'" href="'.$_SERVER["PHP_SELF"]."?id=".$id."&action=checkdispatchline&lineid=".$objp->dispatchlineid.'">'.$langs->trans("Approve").'</a>';
1323  }
1324  }
1325  print '</td>';
1326  } elseif (isModEnabled("reception")) {
1327  print '<td class="right">';
1328  if (!empty($reception->id)) {
1329  print $reception->getLibStatut(5);
1330  }
1331  print '</td>';
1332  }
1333 
1334  // Action
1335  if ($action != 'editline' || $lineid != $objp->dispatchlineid) {
1336  if (empty($reception->id) || ($reception->statut == Reception::STATUS_DRAFT)) { // only allow edit on draft reception
1337  print '<td class="linecoledit center">';
1338  print '<a class="reposition" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=editline&token='.newToken().'&lineid='.$objp->dispatchlineid.'#line_'.$objp->dispatchlineid.'">';
1339  print img_edit();
1340  print '</a>';
1341  print '</td>';
1342 
1343  print '<td class="linecoldelete center">';
1344  print '<a href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=ask_deleteline&token='.newToken().'&lineid='.$objp->dispatchlineid.'#dispatch_received_products">';
1345  print img_delete();
1346  print '</a>';
1347  print '</td>';
1348  } else {
1349  print '<td></td><td></td>';
1350  }
1351  } else {
1352  print '<td class="center valignmiddle">';
1353  print '<input type="submit" class="button button-save" id="savelinebutton" name="save" value="'.$langs->trans("Save").'" />';
1354  print '</td>';
1355  print '<td class="center valignmiddle">';
1356  print '<input type="submit" class="button button-cancel" id="cancellinebutton" name="cancel" value="'.$langs->trans("Cancel").'" />';
1357  print '</td>';
1358  }
1359 
1360 
1361  print "</tr>\n";
1362  if ($action == 'editline' && $lineid == $objp->dispatchlineid) {
1363  print '</form>';
1364  }
1365 
1366  $i++;
1367  }
1368  $db->free($resql);
1369 
1370  print "</table>\n";
1371  print '</div>';
1372  }
1373  } else {
1374  dol_print_error($db);
1375  }
1376 }
1377 
1378 // End of page
1379 llxFooter();
1380 $db->close();
if(GETPOST('button_removefilter_x', 'alpha')||GETPOST('button_removefilter.x', 'alpha')||GETPOST('button_removefilter', 'alpha')) if(GETPOST('button_search_x', 'alpha')||GETPOST('button_search.x', 'alpha')||GETPOST('button_search', 'alpha')) if($action=="save" &&empty($cancel)) $help_url
View.
Definition: agenda.php:118
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
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 to manage projects.
Class to manage receptions.
Class to manage third parties objects (customers, suppliers, prospects...)
Class to manage Dolibarr users.
Definition: user.class.php:47
if(isModEnabled('facture') &&!empty($user->rights->facture->lire)) if((isModEnabled('fournisseur') &&empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD) && $user->hasRight("fournisseur", "facture", "lire"))||(isModEnabled('supplier_invoice') && $user->hasRight("supplier_invoice", "lire"))) if(isModEnabled('don') &&!empty($user->rights->don->lire)) if(isModEnabled('tax') &&!empty($user->rights->tax->charges->lire)) if(isModEnabled('facture') &&isModEnabled('commande') && $user->hasRight("commande", "lire") &&empty($conf->global->WORKFLOW_DISABLE_CREATE_INVOICE_FROM_ORDER)) $resql
Social contributions to pay.
Definition: index.php:745
if($cancel &&! $id) if($action=='add' &&! $cancel) if($action=='delete') if($id) $form
Actions.
Definition: card.php:143
ordersupplier_prepare_head(CommandeFournisseur $object)
Prepare array with list of tabs.
Definition: fourn.lib.php:138
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...
dol_get_fiche_head($links=array(), $active='', $title='', $notab=0, $picto='', $pictoisfullpath=0, $morehtmlright='', $morecss='', $limittoshow=0, $moretabssuffix='')
Show tabs of a record.
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='')
Set event messages in dol_events session object.
price($amount, $form=0, $outlangs='', $trunc=1, $rounding=-1, $forcerounding=-1, $currency_code='')
Function to format a value into an amount for visual output Function used into PDF and HTML pages.
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)
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.
GETPOSTISSET($paramname)
Return true if we are in a context of submitting the parameter $paramname from a POST of a form.
isModEnabled($module)
Is Dolibarr module enabled.
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.
if(!defined( 'CSRFCHECK_WITH_TOKEN'))
$formconfirm
if ($action == 'delbookkeepingyear') {
table tableforfield button
0 = Do not include form tag and submit button -1 = Do not include form tag but include submit button
Definition: style.css.php:843
div float
Buy price without taxes.
Definition: style.css.php:913
$conf db name
Only used if Module[ID]Name translation string is not found.
Definition: repair.php:122
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.