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