dolibarr  16.0.5
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();
CommandeFournisseur\STATUS_ACCEPTED
const STATUS_ACCEPTED
Accepted.
Definition: fournisseur.commande.class.php:278
CommandeFournisseur\STATUS_CANCELED
const STATUS_CANCELED
Order canceled.
Definition: fournisseur.commande.class.php:298
Societe
Class to manage third parties objects (customers, suppliers, prospects...)
Definition: societe.class.php:48
Reception
Class to manage receptions.
Definition: reception.class.php:49
restrictedArea
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.
Definition: security.lib.php:234
Project
Class to manage projects.
Definition: project.class.php:35
CommandeFournisseurDispatch
Class to manage table commandefournisseurdispatch.
Definition: fournisseur.commande.dispatch.class.php:34
GETPOST
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
Definition: functions.lib.php:484
$form
if($cancel &&! $id) if($action=='add' &&! $cancel) if($action=='delete') if($id) $form
Actions.
Definition: card.php:142
name
$conf db name
Definition: repair.php:122
Comment
Class to manage comment.
Definition: comment.class.php:22
dol_banner_tab
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.
Definition: functions.lib.php:2046
$help_url
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
price2num
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
Definition: functions.lib.php:5661
dol_print_date
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs='', $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
Definition: functions.lib.php:2514
Status
Definition: api_status.class.php:27
img_picto
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2)
Show picto whatever it's its name (generic function)
Definition: functions.lib.php:3880
CommandeFournisseur\STATUS_ORDERSENT
const STATUS_ORDERSENT
Order sent, shipment on process.
Definition: fournisseur.commande.class.php:283
$formconfirm
$formconfirm
if ($action == 'delbookkeepingyear') {
Definition: listbyaccount.php:576
MouvementStock
Class to manage stock movements.
Definition: mouvementstock.class.php:31
dol_syslog
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
Definition: functions.lib.php:1603
CommandeFournisseur\STATUS_RECEIVED_COMPLETELY
const STATUS_RECEIVED_COMPLETELY
Received completely.
Definition: fournisseur.commande.class.php:293
dol_get_fiche_head
dol_get_fiche_head($links=array(), $active='', $title='', $notab=0, $picto='', $pictoisfullpath=0, $morehtmlright='', $morecss='', $limittoshow=0, $moretabssuffix='')
Show tabs of a record.
Definition: functions.lib.php:1822
FormProduct
Class with static methods for building HTML components related to products Only components common to ...
Definition: html.formproduct.class.php:30
CommandeFournisseur
Class to manage predefined suppliers products.
Definition: fournisseur.commande.class.php:47
User
Class to manage Dolibarr users.
Definition: user.class.php:44
GETPOSTISSET
GETPOSTISSET($paramname)
Return true if we are in a context of submitting the parameter $paramname from a POST of a form.
Definition: functions.lib.php:386
Product
Class to manage products or services.
Definition: product.class.php:46
Form
Class to manage generation of HTML components Only common components must be here.
Definition: html.form.class.php:52
ordersupplier_prepare_head
ordersupplier_prepare_head(CommandeFournisseur $object)
Prepare array with list of tabs.
Definition: fourn.lib.php:135
Entrepot
Class to manage warehouses.
Definition: entrepot.class.php:35
dol_now
dol_now($mode='auto')
Return date for now.
Definition: functions.lib.php:2845
$resql
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
price
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.
Definition: functions.lib.php:5541
setEventMessages
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='')
Set event messages in dol_events session object.
Definition: functions.lib.php:8137
CommandeFournisseur\STATUS_RECEIVED_PARTIALLY
const STATUS_RECEIVED_PARTIALLY
Received partially.
Definition: fournisseur.commande.class.php:288
accessforbidden
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 ...
Definition: security.lib.php:933
dol_mktime
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...
Definition: functions.lib.php:2757
llxHeader
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
float
div float
Buy price without taxes.
Definition: style.css.php:809
if
if(!defined( 'CSRFCHECK_WITH_TOKEN'))
Definition: journals_list.php:25