dolibarr  19.0.0-dev
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->hasRight("fournisseur", "commande", "receptionner");
90  $permissiontocontrol = ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && $user->hasRight("fournisseur", "commande", "receptionner")) || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && $user->hasRight("fournisseur", "commande_advance", "check")));
91 } else {
92  $permissiontoreceive = $user->hasRight("reception", "creer");
93  $permissiontocontrol = ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && $user->hasRight("reception", "creer")) || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && $user->hasRight("reception", "reception_advance", "validate")));
94 }
95 
96 // $id is id of a purchase order.
97 $result = restrictedArea($user, 'fournisseur', $object, 'commande_fournisseur', 'commande');
98 
99 if (!isModEnabled('stock')) {
100  accessforbidden();
101 }
102 
103 $usercancreate = ($user->hasRight("fournisseur", "commande", "creer") || $user->hasRight("supplier_order", "creer"));
104 $permissiontoadd = $usercancreate; // Used by the include of actions_addupdatedelete.inc.php
105 
106 
107 /*
108  * Actions
109  */
110 
111 $parameters = array();
112 $reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
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, 'MS');
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  // Loop on each source order line (may be more or less than current number of lines in llx_commande_fournisseurdet)
784  while ($i < $num) {
785  $objp = $db->fetch_object($resql);
786 
787  // On n'affiche pas les produits libres
788  if (!$objp->fk_product > 0) {
789  $nbfreeproduct++;
790  } else {
791  $alreadydispatched = isset($products_dispatched[$objp->rowid])?$products_dispatched[$objp->rowid]:0;
792  $remaintodispatch = price2num($objp->qty - ((float) $alreadydispatched), 5); // Calculation of dispatched
793  if ($remaintodispatch < 0 && empty($conf->global->SUPPLIER_ORDER_ALLOW_NEGATIVE_QTY_FOR_SUPPLIER_ORDER_RETURN)) {
794  $remaintodispatch = 0;
795  }
796 
797  if ($remaintodispatch || empty($conf->global->SUPPLIER_ORDER_DISABLE_STOCK_DISPATCH_WHEN_TOTAL_REACHED)) {
798  $nbproduct++;
799 
800  // To show detail cref and description value, we must make calculation by cref
801  // print ($objp->cref?' ('.$objp->cref.')':'');
802  // if ($objp->description) print '<br>'.nl2br($objp->description);
803  $suffix = '_0_'.$i;
804 
805  print "\n";
806  print '<!-- Line to dispatch '.$suffix.' -->'."\n";
807  // hidden fields for js function
808  print '<input id="qty_ordered'.$suffix.'" type="hidden" value="'.$objp->qty.'">';
809  print '<input id="qty_dispatched'.$suffix.'" type="hidden" value="'.(float) $alreadydispatched.'">';
810  print '<tr class="oddeven">';
811 
812  if (empty($conf->cache['product'][$objp->fk_product])) {
813  $tmpproduct = new Product($db);
814  $tmpproduct->fetch($objp->fk_product);
815  $conf->cache['product'][$objp->fk_product] = $tmpproduct;
816  } else {
817  $tmpproduct = $conf->cache['product'][$objp->fk_product];
818  }
819 
820  $linktoprod = $tmpproduct->getNomUrl(1);
821  $linktoprod .= ' - '.$objp->label."\n";
822 
823  if (isModEnabled('productbatch')) {
824  if ($objp->tobatch) {
825  // Product
826  print '<td>';
827  print $linktoprod;
828  print "</td>";
829  print '<td class="dispatch_batch_number"></td>';
830  if (empty($conf->global->PRODUCT_DISABLE_SELLBY)) {
831  print '<td class="dispatch_dlc"></td>';
832  }
833  if (empty($conf->global->PRODUCT_DISABLE_EATBY)) {
834  print '<td class="dispatch_dluo"></td>';
835  }
836  } else {
837  // Product
838  print '<td>';
839  print $linktoprod;
840  print "</td>";
841  print '<td class="dispatch_batch_number">';
842  print '<span class="opacitymedium small">'.$langs->trans("ProductDoesNotUseBatchSerial").'</small>';
843  print '</td>';
844  if (empty($conf->global->PRODUCT_DISABLE_SELLBY)) {
845  print '<td class="dispatch_dlc"></td>';
846  }
847  if (empty($conf->global->PRODUCT_DISABLE_EATBY)) {
848  print '<td class="dispatch_dluo"></td>';
849  }
850  }
851  } else {
852  print '<td colspan="4">';
853  print $linktoprod;
854  print "</td>";
855  }
856 
857  // Define unit price for PMP calculation
858  $up_ht_disc = $objp->subprice;
859  if (!empty($objp->remise_percent) && empty($conf->global->STOCK_EXCLUDE_DISCOUNT_FOR_PMP)) {
860  $up_ht_disc = price2num($up_ht_disc * (100 - $objp->remise_percent) / 100, 'MU');
861  }
862 
863  // Supplier ref
864  print '<td class="right">'.$objp->sref.'</td>';
865 
866  // Qty ordered
867  print '<td class="right">'.$objp->qty.'</td>';
868 
869  // Already dispatched
870  print '<td class="right">'.$alreadydispatched.'</td>';
871 
872  if (isModEnabled('productbatch') && $objp->tobatch > 0) {
873  $type = 'batch';
874  print '<td class="right">';
875  print '</td>'; // Qty to dispatch
876  print '<td>';
877  //print img_picto($langs->trans('AddDispatchBatchLine'), 'split.png', 'class="splitbutton" onClick="addDispatchLine(' . $i . ',\'' . $type . '\')"');
878  print '</td>'; // Dispatch column
879  print '<td></td>'; // Warehouse column
880 
881  // Enable hooks to append additional columns
882  $parameters = array(
883  // allows hook to distinguish between the rows with information and the rows with dispatch form input
884  'is_information_row' => true,
885  'i' => $i,
886  'suffix' => $suffix,
887  'objp' => $objp,
888  );
889  $reshook = $hookmanager->executeHooks(
890  'printFieldListValue',
891  $parameters,
892  $object,
893  $action
894  );
895  if ($reshook < 0) {
896  setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
897  }
898  print $hookmanager->resPrint;
899 
900  print '</tr>';
901 
902  print '<tr class="oddeven" name="'.$type.$suffix.'">';
903  print '<td>';
904  print '<input name="fk_commandefourndet'.$suffix.'" type="hidden" value="'.$objp->rowid.'">';
905  print '<input name="product_batch'.$suffix.'" type="hidden" value="'.$objp->fk_product.'">';
906 
907  print '<!-- This is a up (may include discount or not depending on STOCK_EXCLUDE_DISCOUNT_FOR_PMP. will be used for PMP calculation) -->';
908  if (!empty($conf->global->SUPPLIER_ORDER_EDIT_BUYINGPRICE_DURING_RECEIPT)) { // Not tested !
909  print $langs->trans("BuyingPrice").': <input class="maxwidth75" name="pu'.$suffix.'" type="text" value="'.price2num($up_ht_disc, 'MU').'">';
910  } else {
911  print '<input class="maxwidth75" name="pu'.$suffix.'" type="hidden" value="'.price2num($up_ht_disc, 'MU').'">';
912  }
913 
914  print '</td>';
915 
916  print '<td>';
917  print '<input type="text" class="inputlotnumber quatrevingtquinzepercent" id="lot_number'.$suffix.'" name="lot_number'.$suffix.'" value="'.GETPOST('lot_number'.$suffix).'">';
918  print '</td>';
919  if (empty($conf->global->PRODUCT_DISABLE_SELLBY)) {
920  print '<td class="nowraponall">';
921  $dlcdatesuffix = dol_mktime(0, 0, 0, GETPOST('dlc'.$suffix.'month'), GETPOST('dlc'.$suffix.'day'), GETPOST('dlc'.$suffix.'year'));
922  print $form->selectDate($dlcdatesuffix, 'dlc'.$suffix, '', '', 1, '');
923  print '</td>';
924  }
925  if (empty($conf->global->PRODUCT_DISABLE_EATBY)) {
926  print '<td class="nowraponall">';
927  $dluodatesuffix = dol_mktime(0, 0, 0, GETPOST('dluo'.$suffix.'month'), GETPOST('dluo'.$suffix.'day'), GETPOST('dluo'.$suffix.'year'));
928  print $form->selectDate($dluodatesuffix, 'dluo'.$suffix, '', '', 1, '');
929  print '</td>';
930  }
931  print '<td colspan="3">&nbsp;</td>'; // Supplier ref + Qty ordered + qty already dispatched
932  } else {
933  $type = 'dispatch';
934  $colspan = 7;
935  $colspan = (!empty($conf->global->PRODUCT_DISABLE_SELLBY)) ? --$colspan : $colspan;
936  $colspan = (!empty($conf->global->PRODUCT_DISABLE_EATBY)) ? --$colspan : $colspan;
937  print '<td class="right">';
938  print '</td>'; // Qty to dispatch
939  print '<td>';
940  //print img_picto($langs->trans('AddStockLocationLine'), 'split.png', 'class="splitbutton" onClick="addDispatchLine(' . $i . ',\'' . $type . '\')"');
941  print '</td>'; // Dispatch column
942  print '<td></td>'; // Warehouse column
943 
944  // Enable hooks to append additional columns
945  $parameters = array(
946  // allows hook to distinguish between the rows with information and the rows with dispatch form input
947  'is_information_row' => true,
948  'i' => $i,
949  'suffix' => $suffix,
950  'objp' => $objp,
951  );
952  $reshook = $hookmanager->executeHooks(
953  'printFieldListValue',
954  $parameters,
955  $object,
956  $action
957  );
958  if ($reshook < 0) {
959  setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
960  }
961  print $hookmanager->resPrint;
962 
963  print '</tr>';
964 
965  print '<tr class="oddeven" name="'.$type.$suffix.'">';
966  print '<td colspan="'.$colspan.'">';
967  print '<input name="fk_commandefourndet'.$suffix.'" type="hidden" value="'.$objp->rowid.'">';
968  print '<input name="product'.$suffix.'" type="hidden" value="'.$objp->fk_product.'">';
969 
970  print '<!-- This is a up (may include discount or not depending on STOCK_EXCLUDE_DISCOUNT_FOR_PMP. will be used for PMP calculation) -->';
971  if (!empty($conf->global->SUPPLIER_ORDER_EDIT_BUYINGPRICE_DURING_RECEIPT)) { // Not tested !
972  print $langs->trans("BuyingPrice").': <input class="maxwidth75" name="pu'.$suffix.'" type="text" value="'.price2num($up_ht_disc, 'MU').'">';
973  } else {
974  print '<input class="maxwidth75" name="pu'.$suffix.'" type="hidden" value="'.price2num($up_ht_disc, 'MU').'">';
975  }
976 
977  print '</td>';
978  }
979 
980  // Qty to dispatch
981  print '<td class="right">';
982  print '<a href="#" id="reset'.$suffix.'" class="resetline">'.img_picto($langs->trans("Reset"), 'eraser', 'class="pictofixedwidth opacitymedium"').'</a>';
983  print '<input id="qty'.$suffix.'" name="qty'.$suffix.'" type="text" class="width50 right qtydispatchinput" value="'.(GETPOSTISSET('qty'.$suffix) ? GETPOST('qty'.$suffix, 'int') : (empty($conf->global->SUPPLIER_ORDER_DISPATCH_FORCE_QTY_INPUT_TO_ZERO) ? $remaintodispatch : 0)).'">';
984  print '</td>';
985 
986  print '<td>';
987  if (isModEnabled('productbatch') && $objp->tobatch > 0) {
988  $type = 'batch';
989  print img_picto($langs->trans('AddStockLocationLine'), 'split.png', 'class="splitbutton" onClick="addDispatchLine('.$i.', \''.$type.'\')"');
990  } else {
991  $type = 'dispatch';
992  print img_picto($langs->trans('AddStockLocationLine'), 'split.png', 'class="splitbutton" onClick="addDispatchLine('.$i.', \''.$type.'\')"');
993  }
994  print '</td>';
995 
996  if (!empty($conf->global->SUPPLIER_ORDER_CAN_UPDATE_BUYINGPRICE_DURING_RECEIPT)) {
997  if (!isModEnabled("multicurrency") && empty($conf->dynamicprices->enabled)) {
998  // Price
999  print '<td class="right">';
1000  print '<input id="pu'.$suffix.'" name="pu'.$suffix.'" type="text" size="8" value="'.price((GETPOST('pu'.$suffix) != '' ? price2num(GETPOST('pu'.$suffix)) : $up_ht_disc)).'">';
1001  print '</td>';
1002 
1003  // Discount
1004  print '<td class="right">';
1005  print '<input id="dto'.$suffix.'" name="dto'.$suffix.'" type="text" size="8" value="'.(GETPOST('dto'.$suffix) != '' ? GETPOST('dto'.$suffix) : '').'">';
1006  print '</td>';
1007 
1008  // Save price
1009  print '<td class="center">';
1010  print '<input class="flat checkformerge" type="checkbox" name="saveprice'.$suffix.'" value="'.(GETPOST('saveprice'.$suffix) != '' ? GETPOST('saveprice'.$suffix) : '').'">';
1011  print '</td>';
1012  }
1013  }
1014 
1015  // Warehouse
1016  print '<td class="right">';
1017  if (count($listwarehouses) > 1) {
1018  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);
1019  } elseif (count($listwarehouses) == 1) {
1020  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);
1021  } else {
1022  $langs->load("errors");
1023  print $langs->trans("ErrorNoWarehouseDefined");
1024  }
1025  print "</td>\n";
1026 
1027  // Enable hooks to append additional columns
1028  $parameters = array(
1029  'is_information_row' => false, // this is a dispatch form row
1030  'i' => $i,
1031  'suffix' => $suffix,
1032  'objp' => $objp,
1033  );
1034  $reshook = $hookmanager->executeHooks(
1035  'printFieldListValue',
1036  $parameters,
1037  $object,
1038  $action
1039  );
1040  if ($reshook < 0) {
1041  setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
1042  }
1043  print $hookmanager->resPrint;
1044 
1045  print "</tr>\n";
1046  }
1047  }
1048  $i++;
1049  }
1050  $db->free($resql);
1051  } else {
1052  dol_print_error($db);
1053  }
1054 
1055  print "</table>\n";
1056  print '</div>';
1057 
1058  if ($nbproduct) {
1059  $checkboxlabel = $langs->trans("CloseReceivedSupplierOrdersAutomatically", $langs->transnoentitiesnoconv('StatusOrderReceivedAll'));
1060 
1061  print '<div class="center">';
1062  $parameters = array();
1063  $reshook = $hookmanager->executeHooks('addMoreActionsButtons', $parameters, $object, $action); // Note that $action and $object may have been
1064  // modified by hook
1065  if (empty($reshook)) {
1066  if (empty($conf->reception->enabled)) {
1067  print $langs->trans("Comment").' : ';
1068  print '<input type="text" class="minwidth400" maxlength="128" name="comment" value="';
1069  print GETPOSTISSET("comment") ? GETPOST("comment") : $langs->trans("DispatchSupplierOrder", $object->ref);
1070  // print ' / '.$object->ref_supplier; // Not yet available
1071  print '" class="flat"><br>';
1072 
1073  print '<input type="checkbox" checked="checked" name="closeopenorder"> '.$checkboxlabel;
1074  }
1075 
1076  $dispatchBt = empty($conf->reception->enabled) ? $langs->trans("Receive") : $langs->trans("CreateReception");
1077 
1078  print '<br>';
1079  print '<input type="hidden" name="backtopageforcancel" value="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'">';
1080  print '<input type="submit" class="button" name="dispatch" value="'.dol_escape_htmltag($dispatchBt).'"';
1081  $disabled = 0;
1082  if (!$permissiontoreceive) {
1083  $disabled = 1;
1084  }
1085  if (count($listwarehouses) <= 0) {
1086  $disabled = 1;
1087  }
1088  if ($disabled) {
1089  print ' disabled';
1090  }
1091 
1092  print '>';
1093  }
1094  print '</div>';
1095  }
1096 
1097  // Message if nothing to dispatch
1098  if (!$nbproduct) {
1099  print "<br>\n";
1100  if (empty($conf->global->SUPPLIER_ORDER_DISABLE_STOCK_DISPATCH_WHEN_TOTAL_REACHED)) {
1101  print '<div class="opacitymedium">'.$langs->trans("NoPredefinedProductToDispatch").'</div>'; // No predefined line at all
1102  } else {
1103  print '<div class="opacitymedium">'.$langs->trans("NoMorePredefinedProductToDispatch").'</div>'; // No predefined line that remain to be dispatched.
1104  }
1105  }
1106 
1107  print '</form>';
1108  }
1109 
1110  print dol_get_fiche_end();
1111 
1112  // traitement entrepot par défaut
1113  print '<script type="text/javascript">
1114  $(document).ready(function () {
1115  $("select[name=fk_default_warehouse]").change(function() {
1116  var fk_default_warehouse = $("option:selected", this).val();
1117  $("select[name^=entrepot_]").val(fk_default_warehouse).change();
1118  });
1119 
1120  $("#autoreset").click(function() {
1121  $(".qtydispatchinput").each(function(){
1122  id = $(this).attr("id");
1123  idtab = id.split("_");
1124  if(idtab[1] == 0){
1125  console.log(idtab);
1126  $(this).val("");
1127  $("#qty_dispatched_0_"+idtab[2]).val("0");
1128  } else {
1129  obj = $(this).parent().parent();
1130  nameobj = obj.attr("name");
1131  nametab = nameobj.split("_");
1132  obj.remove();
1133  $("tr[name^=\'"+nametab[0]+"_\'][name$=\'_"+nametab[2]+"\']:last .splitbutton").show();
1134  }
1135  });
1136  });
1137 
1138  $(".resetline").click(function(){
1139  id = $(this).attr("id");
1140  id = id.split("reset_");
1141  console.log("Reset trigger for id = qty_"+id[1]);
1142  $("#qty_"+id[1]).val("");
1143  });
1144  });
1145  </script>';
1146 
1147  // List of lines already dispatched
1148  $sql = "SELECT p.rowid as pid, p.ref, p.label,";
1149  $sql .= " e.rowid as warehouse_id, e.ref as entrepot,";
1150  $sql .= " cfd.rowid as dispatchlineid, cfd.fk_product, cfd.qty, cfd.eatby, cfd.sellby, cfd.batch, cfd.comment, cfd.status, cfd.datec";
1151  $sql .= " ,cd.rowid, cd.subprice";
1152  if ($conf->reception->enabled) {
1153  $sql .= " ,cfd.fk_reception, r.date_delivery";
1154  }
1155  $sql .= " FROM ".MAIN_DB_PREFIX."product as p,";
1156  $sql .= " ".MAIN_DB_PREFIX."commande_fournisseur_dispatch as cfd";
1157  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."commande_fournisseurdet as cd ON cd.rowid = cfd.fk_commandefourndet";
1158  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."entrepot as e ON cfd.fk_entrepot = e.rowid";
1159  if ($conf->reception->enabled) {
1160  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."reception as r ON cfd.fk_reception = r.rowid";
1161  }
1162  $sql .= " WHERE cfd.fk_commande = ".((int) $object->id);
1163  $sql .= " AND cfd.fk_product = p.rowid";
1164  $sql .= " ORDER BY cfd.rowid ASC";
1165 
1166  $resql = $db->query($sql);
1167  if ($resql) {
1168  $num = $db->num_rows($resql);
1169  $i = 0;
1170 
1171  if ($num > 0) {
1172  print "<br>\n";
1173 
1174  print load_fiche_titre($langs->trans("ReceivingForSameOrder"));
1175 
1176  print '<div class="div-table-responsive">';
1177  print '<table id="dispatch_received_products" class="noborder centpercent">';
1178 
1179  print '<tr class="liste_titre">';
1180  // Reception ref
1181  if ($conf->reception->enabled) {
1182  print '<td>'.$langs->trans("Reception").'</td>';
1183  }
1184  // Product
1185  print '<td>'.$langs->trans("Product").'</td>';
1186  print '<td class="center">'.$langs->trans("DateCreation").'</td>';
1187  print '<td class="center">'.$langs->trans("DateDeliveryPlanned").'</td>';
1188  if (isModEnabled('productbatch')) {
1189  print '<td class="dispatch_batch_number_title">'.$langs->trans("batch_number").'</td>';
1190  if (empty($conf->global->PRODUCT_DISABLE_SELLBY)) {
1191  print '<td class="dispatch_dlc_title">'.$langs->trans("SellByDate").'</td>';
1192  }
1193  if (empty($conf->global->PRODUCT_DISABLE_EATBY)) {
1194  print '<td class="dispatch_dluo_title">'.$langs->trans("EatByDate").'</td>';
1195  }
1196  }
1197  print '<td class="right">'.$langs->trans("QtyDispatched").'</td>';
1198  print '<td>'.$langs->trans("Warehouse").'</td>';
1199  print '<td>'.$langs->trans("Comment").'</td>';
1200 
1201  // Status
1202  if (!empty($conf->global->SUPPLIER_ORDER_USE_DISPATCH_STATUS) && empty($reception->rowid)) {
1203  print '<td class="center" colspan="2">'.$langs->trans("Status").'</td>';
1204  } elseif (isModEnabled("reception")) {
1205  print '<td class="center"></td>';
1206  }
1207 
1208  print '<td class="center" colspan="2"></td>';
1209 
1210  print "</tr>\n";
1211 
1212 
1213  while ($i < $num) {
1214  $objp = $db->fetch_object($resql);
1215 
1216  if ($action == 'editline' && $lineid == $objp->dispatchlineid) {
1217  print '<form name="editdispatchedlines" id="editdispatchedlines" action="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'#line_'.GETPOST('lineid', 'int').'" method="POST">
1218  <input type="hidden" name="token" value="'.newToken().'">
1219  <input type="hidden" name="action" value="updateline">
1220  <input type="hidden" name="mode" value="">
1221  <input type="hidden" name="lineid" value="'.$objp->dispatchlineid.'">';
1222  }
1223 
1224  print '<tr class="oddeven" id="line_'.$objp->dispatchlineid.'" >';
1225 
1226  // Reception ref
1227  if (isModEnabled("reception")) {
1228  print '<td class="nowraponall">';
1229  if (!empty($objp->fk_reception)) {
1230  $reception = new Reception($db);
1231  $reception->fetch($objp->fk_reception);
1232  print $reception->getNomUrl(1);
1233  }
1234 
1235  print "</td>";
1236  }
1237 
1238  // Product
1239  print '<td class="tdoverflowmax150">';
1240  if (empty($conf->cache['product'][$objp->fk_product])) {
1241  $tmpproduct = new Product($db);
1242  $tmpproduct->fetch($objp->fk_product);
1243  $conf->cache['product'][$objp->fk_product] = $tmpproduct;
1244  } else {
1245  $tmpproduct = $conf->cache['product'][$objp->fk_product];
1246  }
1247  print $tmpproduct->getNomUrl(1);
1248  print ' - '.$objp->label;
1249  print "</td>\n";
1250 
1251  // Date creation
1252  print '<td class="center">'.dol_print_date($db->jdate($objp->datec), 'day').'</td>';
1253 
1254  // Date delivery
1255  print '<td class="center">'.dol_print_date($db->jdate($objp->date_delivery), 'day').'</td>';
1256 
1257  // Batch / Eat by / Sell by
1258  if (isModEnabled('productbatch')) {
1259  if ($objp->batch) {
1260  include_once DOL_DOCUMENT_ROOT.'/product/stock/class/productlot.class.php';
1261  $lot = new Productlot($db);
1262  $lot->fetch(0, $objp->pid, $objp->batch);
1263  print '<td class="dispatch_batch_number">'.$lot->getNomUrl(1).'</td>';
1264  if (empty($conf->global->PRODUCT_DISABLE_SELLBY)) {
1265  print '<td class="dispatch_dlc">'.dol_print_date($lot->sellby, 'day').'</td>';
1266  }
1267  if (empty($conf->global->PRODUCT_DISABLE_EATBY)) {
1268  print '<td class="dispatch_dluo">'.dol_print_date($lot->eatby, 'day').'</td>';
1269  }
1270  } else {
1271  print '<td class="dispatch_batch_number"></td>';
1272  if (empty($conf->global->PRODUCT_DISABLE_SELLBY)) {
1273  print '<td class="dispatch_dlc"></td>';
1274  }
1275  if (empty($conf->global->PRODUCT_DISABLE_EATBY)) {
1276  print '<td class="dispatch_dluo"></td>';
1277  }
1278  }
1279  }
1280 
1281  // Qty
1282  print '<td class="right">';
1283  if ($action == 'editline' && $lineid == $objp->dispatchlineid) {
1284  print '<input style="width: 50px;" type="text" min="1" name="qty" value="'.$objp->qty.'" />';
1285  } else {
1286  print $objp->qty;
1287  }
1288  print '<input type="hidden" name="price" value="'.$objp->subprice.'" />';
1289  print '</td>';
1290 
1291  // Warehouse
1292  print '<td class="tdoverflowmax150">';
1293  if ($action == 'editline' && $lineid == $objp->dispatchlineid) {
1294  if (count($listwarehouses) > 1) {
1295  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');
1296  } elseif (count($listwarehouses) == 1) {
1297  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');
1298  } else {
1299  $langs->load("errors");
1300  print $langs->trans("ErrorNoWarehouseDefined");
1301  }
1302  } else {
1303  $warehouse_static->id = $objp->warehouse_id;
1304  $warehouse_static->label = $objp->entrepot;
1305  print $warehouse_static->getNomUrl(1);
1306  }
1307  print '</td>';
1308 
1309  // Comment
1310  print '<td class="tdoverflowmax300" style="white-space: pre;">'.$objp->comment.'</td>';
1311 
1312  // Status
1313  if (!empty($conf->global->SUPPLIER_ORDER_USE_DISPATCH_STATUS) && empty($reception->rowid)) {
1314  print '<td class="right">';
1315  $supplierorderdispatch->status = (empty($objp->status) ? 0 : $objp->status);
1316  // print $supplierorderdispatch->status;
1317  print $supplierorderdispatch->getLibStatut(5);
1318  print '</td>';
1319 
1320  // Add button to check/uncheck disaptching
1321  print '<td class="center">';
1322  if (!$permissiontocontrol) {
1323  if (empty($objp->status)) {
1324  print '<a class="button buttonRefused" href="#">'.$langs->trans("Approve").'</a>';
1325  print '<a class="button buttonRefused" href="#">'.$langs->trans("Deny").'</a>';
1326  } else {
1327  print '<a class="button buttonRefused" href="#">'.$langs->trans("Disapprove").'</a>';
1328  print '<a class="button buttonRefused" href="#">'.$langs->trans("Deny").'</a>';
1329  }
1330  } else {
1331  $disabled = '';
1332  if ($object->statut == 5) {
1333  $disabled = 1;
1334  }
1335  if (empty($objp->status)) {
1336  print '<a class="button'.($disabled ? ' buttonRefused' : '').'" href="'.$_SERVER["PHP_SELF"]."?id=".$id."&action=checkdispatchline&lineid=".$objp->dispatchlineid.'">'.$langs->trans("Approve").'</a>';
1337  print '<a class="button'.($disabled ? ' buttonRefused' : '').'" href="'.$_SERVER["PHP_SELF"]."?id=".$id."&action=denydispatchline&lineid=".$objp->dispatchlineid.'">'.$langs->trans("Deny").'</a>';
1338  }
1339  if ($objp->status == 1) {
1340  print '<a class="button'.($disabled ? ' buttonRefused' : '').'" href="'.$_SERVER["PHP_SELF"]."?id=".$id."&action=uncheckdispatchline&lineid=".$objp->dispatchlineid.'">'.$langs->trans("Reinit").'</a>';
1341  print '<a class="button'.($disabled ? ' buttonRefused' : '').'" href="'.$_SERVER["PHP_SELF"]."?id=".$id."&action=denydispatchline&lineid=".$objp->dispatchlineid.'">'.$langs->trans("Deny").'</a>';
1342  }
1343  if ($objp->status == 2) {
1344  print '<a class="button'.($disabled ? ' buttonRefused' : '').'" href="'.$_SERVER["PHP_SELF"]."?id=".$id."&action=uncheckdispatchline&lineid=".$objp->dispatchlineid.'">'.$langs->trans("Reinit").'</a>';
1345  print '<a class="button'.($disabled ? ' buttonRefused' : '').'" href="'.$_SERVER["PHP_SELF"]."?id=".$id."&action=checkdispatchline&lineid=".$objp->dispatchlineid.'">'.$langs->trans("Approve").'</a>';
1346  }
1347  }
1348  print '</td>';
1349  } elseif (isModEnabled("reception")) {
1350  print '<td class="right">';
1351  if (!empty($reception->id)) {
1352  print $reception->getLibStatut(5);
1353  }
1354  print '</td>';
1355  }
1356 
1357  // Action
1358  if ($action != 'editline' || $lineid != $objp->dispatchlineid) {
1359  if (empty($reception->id) || ($reception->statut == Reception::STATUS_DRAFT)) { // only allow edit on draft reception
1360  print '<td class="linecoledit center">';
1361  print '<a class="reposition" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=editline&token='.newToken().'&lineid='.$objp->dispatchlineid.'#line_'.$objp->dispatchlineid.'">';
1362  print img_edit();
1363  print '</a>';
1364  print '</td>';
1365 
1366  print '<td class="linecoldelete center">';
1367  print '<a href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=ask_deleteline&token='.newToken().'&lineid='.$objp->dispatchlineid.'#dispatch_received_products">';
1368  print img_delete();
1369  print '</a>';
1370  print '</td>';
1371  } else {
1372  print '<td></td><td></td>';
1373  }
1374  } else {
1375  print '<td class="center valignmiddle">';
1376  print '<input type="submit" class="button button-save" id="savelinebutton" name="save" value="'.$langs->trans("Save").'" />';
1377  print '</td>';
1378  print '<td class="center valignmiddle">';
1379  print '<input type="submit" class="button button-cancel" id="cancellinebutton" name="cancel" value="'.$langs->trans("Cancel").'" />';
1380  print '</td>';
1381  }
1382 
1383 
1384  print "</tr>\n";
1385  if ($action == 'editline' && $lineid == $objp->dispatchlineid) {
1386  print '</form>';
1387  }
1388 
1389  $i++;
1390  }
1391  $db->free($resql);
1392 
1393  print "</table>\n";
1394  print '</div>';
1395  }
1396  } else {
1397  dol_print_error($db);
1398  }
1399 }
1400 
1401 // End of page
1402 llxFooter();
1403 $db->close();
if(GETPOST('button_removefilter_x', 'alpha')||GETPOST('button_removefilter.x', 'alpha')||GETPOST('button_removefilter', 'alpha')) if(GETPOST('button_search_x', 'alpha')||GETPOST('button_search.x', 'alpha')||GETPOST('button_search', 'alpha')) if($action=="save" &&empty($cancel)) $help_url
View.
Definition: agenda.php:118
if(!defined('NOREQUIRESOC')) if(!defined('NOREQUIRETRAN')) if(!defined('NOTOKENRENEWAL')) if(!defined('NOREQUIREMENU')) if(!defined('NOREQUIREHTML')) if(!defined('NOREQUIREAJAX')) llxHeader()
Empty header.
Definition: wrapper.php:56
llxFooter()
Empty footer.
Definition: wrapper.php:70
Class to manage table commandefournisseurdispatch.
Class to manage predefined suppliers products.
const STATUS_RECEIVED_PARTIALLY
Received partially.
const STATUS_CANCELED
Order canceled.
const STATUS_RECEIVED_COMPLETELY
Received completely.
const STATUS_ORDERSENT
Order sent, shipment on process.
Class to manage comment.
Class to manage warehouses.
Class to manage generation of HTML components Only common components must be here.
Class with static methods for building HTML components related to products Only components common to ...
Class to manage stock movements.
Class to manage products or services.
Class with list of lots and properties.
Class to manage projects.
Class to manage receptions.
Class to manage third parties objects (customers, suppliers, prospects...)
Class to manage Dolibarr users.
Definition: user.class.php:48
if(isModEnabled('facture') && $user->hasRight('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') && $user->hasRight('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:746
if($cancel &&! $id) if($action=='add' &&! $cancel) if($action=='delete') if($id) $form
Actions.
Definition: card.php:143
ordersupplier_prepare_head(CommandeFournisseur $object)
Prepare array with list of tabs.
Definition: fourn.lib.php:138
dol_banner_tab($object, $paramid, $morehtml='', $shownav=1, $fieldid='rowid', $fieldref='ref', $morehtmlref='', $moreparam='', $nodbprefix=0, $morehtmlleft='', $morehtmlstatus='', $onlybanner=0, $morehtmlright='')
Show tab footer of a card.
dol_mktime($hour, $minute, $second, $month, $day, $year, $gm='auto', $check=1)
Return a timestamp date built from detailed informations (by default a local PHP server timestamp) Re...
load_fiche_titre($titre, $morehtmlright='', $picto='generic', $pictoisfullpath=0, $id='', $morecssontable='', $morehtmlcenter='')
Load a title with picto.
img_delete($titlealt='default', $other='class="pictodelete"', $morecss='')
Show delete logo.
dol_get_fiche_head($links=array(), $active='', $title='', $notab=0, $picto='', $pictoisfullpath=0, $morehtmlright='', $morecss='', $limittoshow=0, $moretabssuffix='', $dragdropfile=0)
Show tabs of a record.
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
dol_print_error($db='', $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs='', $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
dol_now($mode='auto')
Return date for now.
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2)
Show picto whatever it's its name (generic function)
newToken()
Return the value of token currently saved into session with name 'newtoken'.
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='', $noduplicate=0)
Set event messages in dol_events session object.
GETPOSTISSET($paramname)
Return true if we are in a context of submitting the parameter $paramname from a POST of a form.
isModEnabled($module)
Is Dolibarr module enabled.
img_edit($titlealt='default', $float=0, $other='')
Show logo editer/modifier fiche.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
if(!defined( 'CSRFCHECK_WITH_TOKEN'))
$formconfirm
if ($action == 'delbookkeepingyear') {
table tableforfield button
0 = Do not include form tag and submit button -1 = Do not include form tag but include submit button
Definition: style.css.php:848
div float
Buy price without taxes.
Definition: style.css.php:921
$conf db name
Only used if Module[ID]Name translation string is not found.
Definition: repair.php:123
restrictedArea(User $user, $features, $object=0, $tableandshare='', $feature2='', $dbt_keyfield='fk_soc', $dbt_select='rowid', $isdraft=0, $mode=0)
Check permissions of a user to show a page and an object.
accessforbidden($message='', $printheader=1, $printfooter=1, $showonlymessage=0, $params=null)
Show a message to say access is forbidden and stop program.