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