dolibarr  19.0.0-dev
dispatch.php
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 require_once DOL_DOCUMENT_ROOT.'/core/lib/reception.lib.php';
43 
44 
45 if (isModEnabled('project')) {
46  require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
47 }
48 
49 // Load translation files required by the page
50 $langs->loadLangs(array("bills", "orders", "sendings", "companies", "deliveries", "products", "stocks", "receptions"));
51 
52 if (isModEnabled('productbatch')) {
53  $langs->load('productbatch');
54 }
55 
56  // Security check
57 $id = GETPOST("id", 'int');
58 $ref = GETPOST('ref');
59 $lineid = GETPOST('lineid', 'int');
60 $action = GETPOST('action', 'aZ09');
61 $fk_default_warehouse = GETPOST('fk_default_warehouse', 'int');
62 $cancel = GETPOST('cancel', 'alpha');
63 $confirm = GETPOST('confirm', 'alpha');
64 
65 if ($user->socid) {
66  $socid = $user->socid;
67 }
68 
69 $hookmanager->initHooks(array('ordersupplierdispatch'));
70 
71 // Recuperation de l'id de projet
72 $projectid = 0;
73 if (GETPOSTISSET("projectid")) {
74  $projectid = GETPOST("projectid", 'int');
75 }
76 
77 $object = new Reception($db);
78 
79 if ($id > 0 || !empty($ref)) {
80  $result = $object->fetch($id, $ref);
81  if ($result < 0) {
82  setEventMessages($object->error, $object->errors, 'errors');
83  }
84  $result = $object->fetch_thirdparty();
85  if ($result < 0) {
86  setEventMessages($object->error, $object->errors, 'errors');
87  }
88  if (!empty($object->origin)) {
89  $origin = $object->origin;
90 
91  $object->fetch_origin();
92  $typeobject = $object->origin;
93  }
94  if ($origin == 'order_supplier' && $object->$typeobject->id && (isModEnabled("fournisseur") && empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD) || isModEnabled("supplier_order"))) {
95  $origin_id = $object->$typeobject->id;
96  $objectsrc = new CommandeFournisseur($db);
97  $objectsrc->fetch($object->$typeobject->id);
98  }
99 }
100 
101 if (empty($conf->reception->enabled)) {
102  $permissiontoreceive = $user->rights->fournisseur->commande->receptionner;
103  $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)));
104 } else {
105  $permissiontoreceive = $user->rights->reception->creer;
106  $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)));
107 }
108 
109 // $id is id of a purchase order.
110 $result = restrictedArea($user, 'fournisseur', $object, 'reception');
111 
112 if (!isModEnabled('stock')) {
113  accessforbidden();
114 }
115 
116 $usercancreate = $user->hasRight('reception', 'creer');
117 $permissiontoadd = $usercancreate; // Used by the include of actions_addupdatedelete.inc.php
118 
119 
120 /*
121  * Actions
122  */
123 
124 $parameters = array();
125 $reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
126 if ($reshook < 0) {
127  setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
128 }
129 
130 // Update a dispatched line
131 if ($action == 'updatelines' && $permissiontoreceive) {
132  $db->begin();
133  $error = 0;
134 
135  $supplierorderdispatch = new CommandeFournisseurDispatch($db);
136  $pos = 0;
137 
138  foreach ($_POST as $key => $value) {
139  // without batch module enabled
140  $reg = array();
141  if (preg_match('/^product_.*([0-9]+)_([0-9]+)$/i', $key, $reg)) {
142  $pos++;
143  if (preg_match('/^product_([0-9]+)_([0-9]+)$/i', $key, $reg)) {
144  $modebatch = "barcode";
145  } elseif (preg_match('/^product_batch_([0-9]+)_([0-9]+)$/i', $key, $reg)) { // With batchmode enabled
146  $modebatch = "batch";
147  }
148 
149  $numline = $pos;
150  if ($modebatch == "barcode") {
151  $prod = "product_".$reg[1].'_'.$reg[2];
152  } else {
153  $prod = 'product_batch_'.$reg[1].'_'.$reg[2];
154  }
155  $qty = "qty_".$reg[1].'_'.$reg[2];
156  $ent = "entrepot_".$reg[1].'_'.$reg[2];
157  $pu = "pu_".$reg[1].'_'.$reg[2]; // This is unit price including discount
158  $fk_commandefourndet = "fk_commandefourndet_".$reg[1].'_'.$reg[2];
159  $idline = GETPOST("idline_".$reg[1].'_'.$reg[2]);
160  $lot = '';
161  $dDLUO = '';
162  $dDLC = '';
163  if ($modebatch == "batch") {
164  $lot = GETPOST('lot_number_'.$reg[1].'_'.$reg[2]);
165  $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'));
166  $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'));
167  }
168 
169  if (!empty($conf->global->SUPPLIER_ORDER_CAN_UPDATE_BUYINGPRICE_DURING_RECEIPT)) {
170  if (!isModEnabled("multicurrency") && empty($conf->dynamicprices->enabled)) {
171  $dto = GETPOST("dto_".$reg[1].'_'.$reg[2], 'int');
172  if (!empty($dto)) {
173  $unit_price = price2num(GETPOST("pu_".$reg[1]) * (100 - $dto) / 100, 'MU');
174  }
175  $saveprice = "saveprice_".$reg[1].'_'.$reg[2];
176  }
177  }
178 
179  // We ask to move a qty
180  if (($modebatch == "batch" && GETPOST($qty) > 0) || ($modebatch == "barcode" && GETPOST($qty) != 0)) {
181  if (!(GETPOST($ent, 'int') > 0)) {
182  dol_syslog('No dispatch for line '.$key.' as no warehouse was chosen.');
183  $text = $langs->transnoentities('Warehouse').', '.$langs->transnoentities('Line').' '.($numline);
184  setEventMessages($langs->trans('ErrorFieldRequired', $text), null, 'errors');
185  $error++;
186  }
187 
188  if (!$error) {
189  if ($idline > 0) {
190  $result = $supplierorderdispatch->fetch($idline);
191  if ($result < 0) {
192  setEventMessages($supplierorderdispatch->error, $supplierorderdispatch->errors, 'errors');
193  $error++;
194  } else {
195  $qtystart = $supplierorderdispatch->qty;
196  $supplierorderdispatch->qty = GETPOST($qty);
197  $supplierorderdispatch->fk_entrepot = GETPOST($ent, 'int');
198  if ($modebatch == "batch") {
199  $supplierorderdispatch->eatby = $dDLUO;
200  $supplierorderdispatch->sellby = $dDLC;
201  }
202 
203  $result = $supplierorderdispatch->update($user);
204  if ($result < 0) {
205  setEventMessages($supplierorderdispatch->error, $supplierorderdispatch->errors, 'errors');
206  $error++;
207  }
208 
209  // If module stock is enabled and the stock increase is done on purchase order dispatching
210  if (!$error && GETPOST($ent, 'int') > 0 && isModEnabled('stock') && !empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER)) {
211  $mouv = new MouvementStock($db);
212  $product = GETPOST($prod, 'int');
213  $entrepot = GETPOST($ent, 'int');
214  $qtymouv = GETPOST($qty) - $qtystart;
215  $price = GETPOST($pu);
216  $comment = GETPOST('comment');
217  $inventorycode = dol_print_date(dol_now(), 'dayhourlog');
218  $now = dol_now();
219  $eatby = '';
220  $sellby = '';
221  $batch = '';
222  if ($modebatch == "batch") {
223  $eatby = $dDLUO;
224  $sellby = $dDLC;
225  $batch = $supplierorderdispatch->batch;
226  }
227  if ($product > 0) {
228  // $price should take into account discount (except if option STOCK_EXCLUDE_DISCOUNT_FOR_PMP is on)
229  $mouv->origin = $objectsrc;
230  $mouv->setOrigin($objectsrc->element, $objectsrc->id);
231 
232  // Method change if qty < 0
233  if (!empty($conf->global->SUPPLIER_ORDER_ALLOW_NEGATIVE_QTY_FOR_SUPPLIER_ORDER_RETURN) && $qtymouv < 0) {
234  $result = $mouv->livraison($user, $product, $entrepot, $qtymouv*(-1), $price, $comment, $now, $eatby, $sellby, $batch, 0, $inventorycode);
235  } else {
236  $result = $mouv->reception($user, $product, $entrepot, $qtymouv, $price, $comment, $eatby, $sellby, $batch, '', 0, $inventorycode);
237  }
238 
239  if ($result < 0) {
240  setEventMessages($mouv->error, $mouv->errors, 'errors');
241  $error++;
242  }
243  }
244  }
245  }
246  } else {
247  $result = $objectsrc->dispatchProduct($user, GETPOST($prod, 'int'), GETPOST($qty), GETPOST($ent, 'int'), GETPOST($pu), GETPOST('comment'), $dDLUO, $dDLC, $lot, GETPOST($fk_commandefourndet, 'int'), 0, $object->id);
248  if ($result < 0) {
249  setEventMessages($objectsrc->error, $objectsrc->errors, 'errors');
250  $error++;
251  }
252  }
253 
254  if (!$error && !empty($conf->global->SUPPLIER_ORDER_CAN_UPDATE_BUYINGPRICE_DURING_RECEIPT)) {
255  if (!isModEnabled("multicurrency") && empty($conf->dynamicprices->enabled)) {
256  $dto = price2num(GETPOST("dto_".$reg[1].'_'.$reg[2], 'int'), '');
257  if (empty($dto)) {
258  $dto = 0;
259  }
260 
261  //update supplier price
262  if (GETPOSTISSET($saveprice)) {
263  // TODO Use class
264  $sql = "UPDATE ".MAIN_DB_PREFIX."product_fournisseur_price";
265  $sql .= " SET unitprice='".price2num(GETPOST($pu), 'MU')."'";
266  $sql .= ", price=".price2num(GETPOST($pu), 'MU')."*quantity";
267  $sql .= ", remise_percent = ".((float) $dto);
268  $sql .= " WHERE fk_soc=".((int) $object->socid);
269  $sql .= " AND fk_product=".((int) GETPOST($prod, 'int'));
270 
271  $resql = $db->query($sql);
272  }
273  }
274  }
275  }
276  }
277  }
278  }
279  if ($error > 0) {
280  $db->rollback();
281  setEventMessages($error, $errors, 'errors');
282  } else {
283  $db->commit();
284  setEventMessages($langs->trans("ReceptionUpdated"), null);
285  }
286 }
287 
288 
289 /*
290  * View
291  */
292 
293 $now = dol_now();
294 
295 $form = new Form($db);
296 $formproduct = new FormProduct($db);
297 $warehouse_static = new Entrepot($db);
298 $supplierorderdispatch = new CommandeFournisseurDispatch($db);
299 
300 $title = $object->ref." - ".$langs->trans('ReceptionDistribution');
301 $help_url = 'EN:Module_Suppliers_Orders|FR:CommandeFournisseur|ES:Módulo_Pedidos_a_proveedores';
302 $morejs = array('/fourn/js/lib_dispatch.js.php');
303 
304 llxHeader('', $title, $help_url, '', 0, 0, $morejs);
305 
306 if ($id > 0 || !empty($ref)) {
307  if (!empty($object->origin) && $object->origin_id > 0) {
308  $object->origin = 'CommandeFournisseur';
309  $typeobject = $object->origin;
310  $origin = $object->origin;
311  $origin_id = $object->origin_id;
312  $object->fetch_origin(); // Load property $object->commande, $object->propal, ...
313  }
314  $soc = new Societe($db);
315  $soc->fetch($object->socid);
316 
317  $author = new User($db);
318  $author->fetch($object->user_author_id);
319 
320  $head = reception_prepare_head($object);
321 
322  $title = $langs->trans("SupplierOrder");
323  print dol_get_fiche_head($head, 'dispatch', $langs->trans("Reception"), -1, 'dollyrevert');
324 
325 
326  $formconfirm = '';
327 
328  // Confirmation to delete line
329  if ($action == 'ask_deleteline') {
330  $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id.'&lineid='.$lineid, $langs->trans('DeleteLine'), $langs->trans('ConfirmDeleteLine'), 'confirm_deleteline', '', 0, 1);
331  }
332 
333  // Call Hook formConfirm
334  $parameters = array('lineid' => $lineid);
335  // Note that $action and $object may be modified by hook
336  $reshook = $hookmanager->executeHooks('formConfirm', $parameters, $object, $action);
337  if (empty($reshook)) {
338  $formconfirm .= $hookmanager->resPrint;
339  } elseif ($reshook > 0) {
340  $formconfirm = $hookmanager->resPrint;
341  }
342 
343  // Print form confirm
344  print $formconfirm;
345 
346  // Reception card
347  $linkback = '<a href="'.DOL_URL_ROOT.'/reception/list.php?restore_lastsearch_values=1'.(!empty($socid) ? '&socid='.$socid : '').'">'.$langs->trans("BackToList").'</a>';
348  $morehtmlref = '<div class="refidno">';
349  // Ref customer reception
350 
351  $morehtmlref .= $form->editfieldkey("RefSupplier", 'ref_supplier', $object->ref_supplier, $object, $user->rights->reception->creer, 'string', '', 0, 1);
352  $morehtmlref .= $form->editfieldval("RefSupplier", 'ref_supplier', $object->ref_supplier, $object, $user->rights->reception->creer, 'string', '', null, null, '', 1);
353 
354  // Thirdparty
355  $morehtmlref .= '<br>'.$object->thirdparty->getNomUrl(1);
356  // Project
357  if (isModEnabled('project')) {
358  $langs->load("projects");
359  $morehtmlref .= '<br>';
360  if (0) { // Do not change on reception
361  $morehtmlref .= img_picto($langs->trans("Project"), 'project', 'class="pictofixedwidth"');
362  if ($action != 'classify' && $permissiontoadd) {
363  $morehtmlref .= '<a class="editfielda" href="'.$_SERVER['PHP_SELF'].'?action=classify&token='.newToken().'&id='.$object->id.'">'.img_edit($langs->transnoentitiesnoconv('SetProject')).'</a> ';
364  }
365  $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');
366  } else {
367  if (!empty($objectsrc) && !empty($objectsrc->fk_project)) {
368  $proj = new Project($db);
369  $proj->fetch($objectsrc->fk_project);
370  $morehtmlref .= $proj->getNomUrl(1);
371  if ($proj->title) {
372  $morehtmlref .= '<span class="opacitymedium"> - '.dol_escape_htmltag($proj->title).'</span>';
373  }
374  }
375  }
376  }
377  $morehtmlref .= '</div>';
378 
379  dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref);
380 
381 
382  print '<div class="fichecenter">';
383  print '<div class="underbanner clearboth"></div>';
384 
385  print '<table class="border tableforfield" width="100%">';
386 
387  // Linked documents
388  if ($typeobject == 'commande' && $object->$typeobject->id && isModEnabled('commande')) {
389  print '<tr><td>';
390  print $langs->trans("RefOrder").'</td>';
391  print '<td colspan="3">';
392  print $objectsrc->getNomUrl(1, 'commande');
393  print "</td>\n";
394  print '</tr>';
395  }
396  if ($typeobject == 'propal' && $object->$typeobject->id && isModEnabled("propal")) {
397  print '<tr><td>';
398  print $langs->trans("RefProposal").'</td>';
399  print '<td colspan="3">';
400  print $objectsrc->getNomUrl(1, 'reception');
401  print "</td>\n";
402  print '</tr>';
403  }
404  if ($typeobject == 'CommandeFournisseur' && $object->$typeobject->id && isModEnabled("propal")) {
405  print '<tr><td>';
406  print $langs->trans("SupplierOrder").'</td>';
407  print '<td colspan="3">';
408  print $objectsrc->getNomUrl(1, 'reception');
409  print "</td>\n";
410  print '</tr>';
411  }
412 
413  // Date creation
414  print '<tr><td class="titlefield">'.$langs->trans("DateCreation").'</td>';
415  print '<td colspan="3">'.dol_print_date($object->date_creation, "dayhour", "tzuserrel")."</td>\n";
416  print '</tr>';
417 
418  // Delivery date planned
419  print '<tr><td height="10">';
420  print '<table class="nobordernopadding" width="100%"><tr><td>';
421  print $langs->trans('DateDeliveryPlanned');
422  print '</td>';
423  print '</tr></table>';
424  print '</td><td colspan="2">';
425  print $object->date_delivery ? dol_print_date($object->date_delivery, 'dayhour') : '&nbsp;';
426  print '</td>';
427  print '</tr>';
428  print '</table>';
429 
430  print '<br><center>';
431  print '<a href="#" id="resetalltoexpected" class="marginrightonly paddingright marginleftonly paddingleft">'.img_picto("", 'autofill', 'class="pictofixedwidth"').$langs->trans("RestoreWithCurrentQtySaved").'</a></td>';
432  // Link to clear qty
433  print '<a href="#" id="autoreset" class="marginrightonly paddingright marginleftonly paddingleft">'.img_picto("", 'eraser', 'class="pictofixedwidth"').$langs->trans("ClearQtys").'</a></td>';
434  print '<center>';
435 
436  print '<br>';
437  $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.
438 
439  if ($object->statut == Reception::STATUS_DRAFT) {
440  require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php';
441  $formproduct = new FormProduct($db);
442  $formproduct->loadWarehouses();
443  $entrepot = new Entrepot($db);
444  $listwarehouses = $entrepot->list_array(1);
445 
446 
447  print '<form method="post" action="'.$_SERVER["PHP_SELF"].'">';
448 
449  print '<input type="hidden" name="token" value="'.newToken().'">';
450  print '<input type="hidden" name="action" value="updatelines">';
451  print '<input type="hidden" name="id" value="'.$object->id.'">';
452 
453  print '<div class="div-table-responsive-no-min">';
454  print '<table class="noborder centpercent">';
455 
456  // Get list of lines from the original Order into $products_dispatched with qty dispatched for each product id
457  $products_dispatched = array();
458  $sql = "SELECT l.rowid, cfd.fk_product, sum(cfd.qty) as qty";
459  $sql .= " FROM ".MAIN_DB_PREFIX."commande_fournisseur_dispatch as cfd";
460  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."commande_fournisseurdet as l on l.rowid = cfd.fk_commandefourndet";
461  $sql .= " WHERE cfd.fk_reception = ".((int) $object->id);
462  $sql .= " GROUP BY l.rowid, cfd.fk_product";
463 
464  $resql = $db->query($sql);
465  if ($resql) {
466  $num = $db->num_rows($resql);
467  $i = 0;
468 
469  if ($num) {
470  while ($i < $num) {
471  $objd = $db->fetch_object($resql);
472  $products_dispatched[$objd->rowid] = price2num($objd->qty, 'MS');
473  $i++;
474  }
475  }
476  $db->free($resql);
477  }
478 
479 
480  //$sql = "SELECT l.rowid, l.fk_product, l.subprice, l.remise_percent, l.ref AS sref, SUM(l.qty) as qty,";
481  $sql = "SELECT l.rowid, l.fk_product, l.subprice, l.remise_percent, l.ref AS sref, l.qty as qty,";
482  $sql .= " p.ref, p.label, p.tobatch, p.fk_default_warehouse";
483  // Enable hooks to alter the SQL query (SELECT)
484  $parameters = array();
485  $reshook = $hookmanager->executeHooks(
486  'printFieldListSelect',
487  $parameters,
488  $object,
489  $action
490  );
491  if ($reshook < 0) {
492  setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
493  }
494  $sql .= $hookmanager->resPrint;
495  $sql .= " FROM ".MAIN_DB_PREFIX."commande_fournisseurdet as l";
496  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product as p ON l.fk_product=p.rowid";
497  $sql .= " WHERE l.fk_commande = ".((int) $objectsrc->id);
498  if (empty($conf->global->STOCK_SUPPORTS_SERVICES)) {
499  $sql .= " AND l.product_type = 0";
500  }
501  // Enable hooks to alter the SQL query (WHERE)
502  $parameters = array();
503  $reshook = $hookmanager->executeHooks(
504  'printFieldListWhere',
505  $parameters,
506  $object,
507  $action
508  );
509  if ($reshook < 0) {
510  setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
511  }
512  $sql .= $hookmanager->resPrint;
513 
514  //$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
515  $sql .= " ORDER BY l.rang, p.ref, p.label";
516 
517  $resql = $db->query($sql);
518  if ($resql) {
519  $num = $db->num_rows($resql);
520  $i = 0;
521 
522  if ($num) {
523  print '<tr class="liste_titre">';
524 
525  print '<td>'.$langs->trans("Description").'</td>';
526  if (isModEnabled('productbatch')) {
527  print '<td class="dispatch_batch_number_title">'.$langs->trans("batch_number").'</td>';
528  if (empty($conf->global->PRODUCT_DISABLE_SELLBY)) {
529  print '<td class="dispatch_dlc_title">'.$langs->trans("SellByDate").'</td>';
530  }
531  if (empty($conf->global->PRODUCT_DISABLE_EATBY)) {
532  print '<td class="dispatch_dluo_title">'.$langs->trans("EatByDate").'</td>';
533  }
534  } else {
535  print '<td></td>';
536  print '<td></td>';
537  print '<td></td>';
538  }
539  print '<td class="right">'.$langs->trans("SupplierRef").'</td>';
540  print '<td class="right">'.$langs->trans("QtyOrdered").'</td>';
541  print '<td class="right">'.$langs->trans("QtyDispatchedShort").'</td>';
542  print ' <td class="right">'.$langs->trans("QtyToDispatchShort");
543  //print '<br><a href="#" id="autoreset">'.img_picto($langs->trans("Reset"), 'eraser', 'class="pictofixedwidth opacitymedium"').$langs->trans("Reset").'</a></td>';
544  print '<td width="32"></td>';
545 
546  if (!empty($conf->global->SUPPLIER_ORDER_CAN_UPDATE_BUYINGPRICE_DURING_RECEIPT)) {
547  if (!isModEnabled("multicurrency") && empty($conf->dynamicprices->enabled)) {
548  print '<td class="right">'.$langs->trans("Price").'</td>';
549  print '<td class="right">'.$langs->trans("ReductionShort").' (%)</td>';
550  print '<td class="right">'.$langs->trans("UpdatePrice").'</td>';
551  }
552  }
553 
554  print '<td align="right">'.$langs->trans("Warehouse");
555 
556  // Select warehouse to force it everywhere
557  if (count($listwarehouses) > 1) {
558  print '<br><span class="opacitymedium">'.$langs->trans("ForceTo").'</span> '.$form->selectarray('fk_default_warehouse', $listwarehouses, $fk_default_warehouse, 1, 0, 0, '', 0, 0, $disabled, '', 'minwidth100 maxwidth300', 1);
559  } elseif (count($listwarehouses) == 1) {
560  print '<br><span class="opacitymedium">'.$langs->trans("ForceTo").'</span> '.$form->selectarray('fk_default_warehouse', $listwarehouses, $fk_default_warehouse, 0, 0, 0, '', 0, 0, $disabled, '', 'minwidth100 maxwidth300', 1);
561  }
562 
563  print '</td>';
564 
565  // Enable hooks to append additional columns
566  $parameters = array();
567  $reshook = $hookmanager->executeHooks(
568  'printFieldListTitle',
569  $parameters,
570  $object,
571  $action
572  );
573  if ($reshook < 0) {
574  setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
575  }
576  print $hookmanager->resPrint;
577 
578  print "</tr>\n";
579  }
580 
581  $nbfreeproduct = 0; // Nb of lins of free products/services
582  $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)
583  // or nb of line that remain to dispatch if SUPPLIER_ORDER_DISABLE_STOCK_DISPATCH_WHEN_TOTAL_REACHED is on.
584 
585  $conf->cache['product'] = array();
586 
587  // Loop on each source order line (may be more or less than current number of lines in llx_commande_fournisseurdet)
588  while ($i < $num) {
589  $objp = $db->fetch_object($resql);
590 
591  // On n'affiche pas les produits libres
592  if (!$objp->fk_product > 0) {
593  $nbfreeproduct++;
594  } else {
595  $alreadydispatched = isset($products_dispatched[$objp->rowid])?$products_dispatched[$objp->rowid]:0;
596  $remaintodispatch = price2num($objp->qty, 5); // Calculation of dispatched
597  if ($remaintodispatch < 0 && empty($conf->global->SUPPLIER_ORDER_ALLOW_NEGATIVE_QTY_FOR_SUPPLIER_ORDER_RETURN)) {
598  $remaintodispatch = 0;
599  }
600 
601  if ($remaintodispatch || empty($conf->global->SUPPLIER_ORDER_DISABLE_STOCK_DISPATCH_WHEN_TOTAL_REACHED)) {
602  $nbproduct++;
603 
604  // To show detail cref and description value, we must make calculation by cref
605  // print ($objp->cref?' ('.$objp->cref.')':'');
606  // if ($objp->description) print '<br>'.nl2br($objp->description);
607  $suffix = '_0_'.$i;
608 
609  print "\n";
610  print '<!-- Line to dispatch '.$suffix.' -->'."\n";
611  // hidden fields for js function
612  print '<input id="qty_ordered'.$suffix.'" type="hidden" value="'.$objp->qty.'">';
613  print '<input id="qty_dispatched'.$suffix.'" type="hidden" data-dispatched="'.((float) $alreadydispatched).'" value="'.(float) $alreadydispatched.'">';
614  print '<tr class="oddeven">';
615 
616  if (empty($conf->cache['product'][$objp->fk_product])) {
617  $tmpproduct = new Product($db);
618  $tmpproduct->fetch($objp->fk_product);
619  $conf->cache['product'][$objp->fk_product] = $tmpproduct;
620  } else {
621  $tmpproduct = $conf->cache['product'][$objp->fk_product];
622  }
623 
624  $linktoprod = $tmpproduct->getNomUrl(1);
625  $linktoprod .= ' - '.$objp->label."\n";
626 
627  if (isModEnabled('productbatch')) {
628  if ($objp->tobatch) {
629  // Product
630  print '<td>';
631  print $linktoprod;
632  print "</td>";
633  print '<td class="dispatch_batch_number"></td>';
634  if (empty($conf->global->PRODUCT_DISABLE_SELLBY)) {
635  print '<td class="dispatch_dlc"></td>';
636  }
637  if (empty($conf->global->PRODUCT_DISABLE_EATBY)) {
638  print '<td class="dispatch_dluo"></td>';
639  }
640  } else {
641  // Product
642  print '<td>';
643  print $linktoprod;
644  print "</td>";
645  print '<td class="dispatch_batch_number">';
646  print '<span class="opacitymedium small">'.$langs->trans("ProductDoesNotUseBatchSerial").'</small>';
647  print '</td>';
648  if (empty($conf->global->PRODUCT_DISABLE_SELLBY)) {
649  print '<td class="dispatch_dlc"></td>';
650  }
651  if (empty($conf->global->PRODUCT_DISABLE_EATBY)) {
652  print '<td class="dispatch_dluo"></td>';
653  }
654  }
655  } else {
656  print '<td colspan="4">';
657  print $linktoprod;
658  print "</td>";
659  }
660 
661  // Define unit price for PMP calculation
662  $up_ht_disc = $objp->subprice;
663  if (!empty($objp->remise_percent) && empty($conf->global->STOCK_EXCLUDE_DISCOUNT_FOR_PMP)) {
664  $up_ht_disc = price2num($up_ht_disc * (100 - $objp->remise_percent) / 100, 'MU');
665  }
666 
667  // Supplier ref
668  print '<td class="right">'.$objp->sref.'</td>';
669 
670  // Qty ordered
671  print '<td class="right">'.$objp->qty.'</td>';
672 
673  // Already dispatched
674  print '<td class="right">'.$alreadydispatched.'</td>';
675 
676  print '<td class="right">';
677  print '</td>'; // Qty to dispatch
678  print '<td>';
679  print '</td>'; // Dispatch column
680  print '<td></td>'; // Warehouse column
681 
682  $sql = "SELECT cfd.rowid, cfd.qty, cfd.fk_entrepot, cfd.batch, cfd.eatby, cfd.sellby, cfd.fk_product";
683  $sql .= " FROM ".MAIN_DB_PREFIX."commande_fournisseur_dispatch as cfd";
684  $sql .= " WHERE cfd.fk_reception = ".((int) $object->id);
685  $sql .= " AND cfd.fk_commande = ".((int) $objectsrc->id);
686  $sql .= " AND cfd.fk_commandefourndet = ".(int) $objp->rowid;
687 
688  //print $sql;
689  $resultsql = $db->query($sql);
690  $j = 0;
691  if ($resultsql) {
692  $numd = $db->num_rows($resultsql);
693 
694  while ($j < $numd) {
695  $suffix = "_".$j."_".$i;
696  $objd = $db->fetch_object($resultsql);
697 
698  if (isModEnabled('productbatch') && !empty($objd->batch)) {
699  $type = 'batch';
700 
701  // Enable hooks to append additional columns
702  $parameters = array(
703  // allows hook to distinguish between the rows with information and the rows with dispatch form input
704  'is_information_row' => true,
705  'j' => $j,
706  'suffix' => $suffix,
707  'objd' => $objd,
708  );
709  $reshook = $hookmanager->executeHooks(
710  'printFieldListValue',
711  $parameters,
712  $object,
713  $action
714  );
715  if ($reshook < 0) {
716  setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
717  }
718  print $hookmanager->resPrint;
719 
720  print '</tr>';
721 
722  print '<!-- line for batch '.$numline.' -->';
723  print '<tr class="oddeven autoresettr" name="'.$type.$suffix.'" data-remove="clear">';
724  print '<td>';
725  print '<input id="fk_commandefourndet'.$suffix.'" name="fk_commandefourndet'.$suffix.'" type="hidden" value="'.$objp->rowid.'">';
726  print '<input id="idline'.$suffix.'" name="idline'.$suffix.'" type="hidden" value="'.$objd->rowid.'">';
727  print '<input name="product_batch'.$suffix.'" type="hidden" value="'.$objd->fk_product.'">';
728 
729  print '<!-- This is a U.P. (may include discount or not depending on STOCK_EXCLUDE_DISCOUNT_FOR_PMP. will be used for PMP calculation) -->';
730  if (!empty($conf->global->SUPPLIER_ORDER_EDIT_BUYINGPRICE_DURING_RECEIPT)) { // Not tested !
731  print $langs->trans("BuyingPrice").': <input class="maxwidth75" name="pu'.$suffix.'" type="text" value="'.price2num($up_ht_disc, 'MU').'">';
732  } else {
733  print '<input class="maxwidth75" name="pu'.$suffix.'" type="hidden" value="'.price2num($up_ht_disc, 'MU').'">';
734  }
735 
736  print '</td>';
737 
738  print '<td>';
739  print '<input disabled="" type="text" class="inputlotnumber quatrevingtquinzepercent" id="lot_number'.$suffix.'" name="lot_number'.$suffix.'" value="'.$objd->batch.'">';
740  print '</td>';
741  if (empty($conf->global->PRODUCT_DISABLE_SELLBY)) {
742  print '<td class="nowraponall">';
743  $dlcdatesuffix = !empty($objd->sellby) ? dol_stringtotime($objd->sellby) : dol_mktime(0, 0, 0, GETPOST('dlc'.$suffix.'month'), GETPOST('dlc'.$suffix.'day'), GETPOST('dlc'.$suffix.'year'));
744  print $form->selectDate($dlcdatesuffix, 'dlc'.$suffix, '', '', 1, '');
745  print '</td>';
746  }
747  if (empty($conf->global->PRODUCT_DISABLE_EATBY)) {
748  print '<td class="nowraponall">';
749  $dluodatesuffix = !empty($objd->eatby) ? dol_stringtotime($objd->eatby) : dol_mktime(0, 0, 0, GETPOST('dluo'.$suffix.'month'), GETPOST('dluo'.$suffix.'day'), GETPOST('dluo'.$suffix.'year'));
750  print $form->selectDate($dluodatesuffix, 'dluo'.$suffix, '', '', 1, '');
751  print '</td>';
752  }
753  print '<td colspan="3">&nbsp;</td>'; // Supplier ref + Qty ordered + qty already dispatched
754  } else {
755  $type = 'dispatch';
756  $colspan = 7;
757  $colspan = (!empty($conf->global->PRODUCT_DISABLE_SELLBY)) ? --$colspan : $colspan;
758  $colspan = (!empty($conf->global->PRODUCT_DISABLE_EATBY)) ? --$colspan : $colspan;
759 
760  // Enable hooks to append additional columns
761  $parameters = array(
762  // allows hook to distinguish between the rows with information and the rows with dispatch form input
763  'is_information_row' => true,
764  'j' => $j,
765  'suffix' => $suffix,
766  'objd' => $objd,
767  );
768  $reshook = $hookmanager->executeHooks(
769  'printFieldListValue',
770  $parameters,
771  $object,
772  $action
773  );
774  if ($reshook < 0) {
775  setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
776  }
777  print $hookmanager->resPrint;
778 
779  print '</tr>';
780 
781  print '<!-- line no batch '.$numline.' -->';
782  print '<tr class="oddeven autoresettr" name="'.$type.$suffix.'" data-remove="clear">';
783  print '<td colspan="'.$colspan.'">';
784  print '<input id="fk_commandefourndet'.$suffix.'" name="fk_commandefourndet'.$suffix.'" type="hidden" value="'.$objp->rowid.'">';
785  print '<input id="idline'.$suffix.'" name="idline'.$suffix.'" type="hidden" value="'.$objd->rowid.'">';
786  print '<input name="product'.$suffix.'" type="hidden" value="'.$objd->fk_product.'">';
787 
788  print '<!-- This is a up (may include discount or not depending on STOCK_EXCLUDE_DISCOUNT_FOR_PMP. will be used for PMP calculation) -->';
789  if (!empty($conf->global->SUPPLIER_ORDER_EDIT_BUYINGPRICE_DURING_RECEIPT)) { // Not tested !
790  print $langs->trans("BuyingPrice").': <input class="maxwidth75" name="pu'.$suffix.'" type="text" value="'.price2num($up_ht_disc, 'MU').'">';
791  } else {
792  print '<input class="maxwidth75" name="pu'.$suffix.'" type="hidden" value="'.price2num($up_ht_disc, 'MU').'">';
793  }
794 
795  print '</td>';
796  }
797  // Qty to dispatch
798  print '<td class="right">';
799  print '<a href="#" id="reset'.$suffix.'" class="resetline">'.img_picto($langs->trans("Reset"), 'eraser', 'class="pictofixedwidth opacitymedium"').'</a>';
800  print '<input id="qty'.$suffix.'" onchange="onChangeDispatchLineQty($(this))" name="qty'.$suffix.'" data-type="'.$type.'" data-index="'.$i.'" class="width50 right qtydispatchinput" value="'.(GETPOSTISSET('qty'.$suffix) ? GETPOST('qty'.$suffix, 'int') : $objd->qty).'" data-expected="'.$objd->qty.'">';
801  print '</td>';
802  print '<td>';
803  if (isModEnabled('productbatch') && $objp->tobatch > 0) {
804  $type = 'batch';
805  print img_picto($langs->trans('AddStockLocationLine'), 'split.png', 'class="splitbutton" '.($numd != $j+1 ? 'style="display:none"' : '').' onClick="addDispatchLine('.$i.', \''.$type.'\')"');
806  } else {
807  $type = 'dispatch';
808  print img_picto($langs->trans('AddStockLocationLine'), 'split.png', 'class="splitbutton" '.($numd != $j+1 ? 'style="display:none"' : '').' onClick="addDispatchLine('.$i.', \''.$type.'\')"');
809  }
810 
811  print '</td>';
812 
813  if (!empty($conf->global->SUPPLIER_ORDER_CAN_UPDATE_BUYINGPRICE_DURING_RECEIPT)) {
814  if (!isModEnabled("multicurrency") && empty($conf->dynamicprices->enabled)) {
815  // Price
816  print '<td class="right">';
817  print '<input id="pu'.$suffix.'" name="pu'.$suffix.'" type="text" size="8" value="'.price((GETPOST('pu'.$suffix) != '' ? price2num(GETPOST('pu'.$suffix)) : $up_ht_disc)).'">';
818  print '</td>';
819 
820  // Discount
821  print '<td class="right">';
822  print '<input id="dto'.$suffix.'" name="dto'.$suffix.'" type="text" size="8" value="'.(GETPOST('dto'.$suffix) != '' ? GETPOST('dto'.$suffix) : '').'">';
823  print '</td>';
824 
825  // Save price
826  print '<td class="center">';
827  print '<input class="flat checkformerge" type="checkbox" name="saveprice'.$suffix.'" value="'.(GETPOST('saveprice'.$suffix) != '' ? GETPOST('saveprice'.$suffix) : '').'">';
828  print '</td>';
829  }
830  }
831 
832  // Warehouse
833  print '<td class="right">';
834  if (count($listwarehouses) > 1) {
835  print $formproduct->selectWarehouses(GETPOST("entrepot".$suffix) ?GETPOST("entrepot".$suffix) : $objd->fk_entrepot, "entrepot".$suffix, '', 1, 0, $objp->fk_product, '', 1, 0, null, 'csswarehouse'.$suffix);
836  } elseif (count($listwarehouses) == 1) {
837  print $formproduct->selectWarehouses(GETPOST("entrepot".$suffix) ?GETPOST("entrepot".$suffix) : $objd->fk_entrepot, "entrepot".$suffix, '', 0, 0, $objp->fk_product, '', 1, 0, null, 'csswarehouse'.$suffix);
838  } else {
839  $langs->load("errors");
840  print $langs->trans("ErrorNoWarehouseDefined");
841  }
842  print "</td>\n";
843 
844  // Enable hooks to append additional columns
845  $parameters = array(
846  'is_information_row' => false, // this is a dispatch form row
847  'i' => $i,
848  'suffix' => $suffix,
849  'objp' => $objp,
850  );
851  $reshook = $hookmanager->executeHooks(
852  'printFieldListValue',
853  $parameters,
854  $object,
855  $action
856  );
857  if ($reshook < 0) {
858  setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
859  }
860  print $hookmanager->resPrint;
861 
862  print "</tr>\n";
863  $j++;
864 
865  $numline++;
866  }
867  $suffix = "_".$j."_".$i;
868  }
869 
870  if ($j == 0) {
871  if (isModEnabled('productbatch') && !empty($objp->tobatch)) {
872  $type = 'batch';
873 
874  // Enable hooks to append additional columns
875  $parameters = array(
876  // allows hook to distinguish between the rows with information and the rows with dispatch form input
877  'is_information_row' => true,
878  'j' => $j,
879  'suffix' => $suffix,
880  'objp' => $objp,
881  );
882  $reshook = $hookmanager->executeHooks(
883  'printFieldListValue',
884  $parameters,
885  $object,
886  $action
887  );
888  if ($reshook < 0) {
889  setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
890  }
891  print $hookmanager->resPrint;
892 
893  print '</tr>';
894 
895  print '<!-- line for batch '.$numline.' (not dispatched line yet for this order line) -->';
896  print '<tr class="oddeven autoresettr" name="'.$type.$suffix.'">';
897  print '<td>';
898  print '<input id="fk_commandefourndet'.$suffix.'" name="fk_commandefourndet'.$suffix.'" type="hidden" value="'.$objp->rowid.'">';
899  print '<input id="idline'.$suffix.'" name="idline'.$suffix.'" type="hidden" value="-1">';
900  print '<input name="product_batch'.$suffix.'" type="hidden" value="'.$objp->fk_product.'">';
901 
902  print '<!-- This is a up (may include discount or not depending on STOCK_EXCLUDE_DISCOUNT_FOR_PMP. will be used for PMP calculation) -->';
903  if (!empty($conf->global->SUPPLIER_ORDER_EDIT_BUYINGPRICE_DURING_RECEIPT)) { // Not tested !
904  print $langs->trans("BuyingPrice").': <input class="maxwidth75" name="pu'.$suffix.'" type="text" value="'.price2num($up_ht_disc, 'MU').'">';
905  } else {
906  print '<input class="maxwidth75" name="pu'.$suffix.'" type="hidden" value="'.price2num($up_ht_disc, 'MU').'">';
907  }
908 
909  print '</td>';
910 
911  print '<td>';
912  print '<input type="text" class="inputlotnumber quatrevingtquinzepercent" id="lot_number'.$suffix.'" name="lot_number'.$suffix.'" value="'.GETPOST('lot_number'.$suffix).'">';
913  print '</td>';
914  if (empty($conf->global->PRODUCT_DISABLE_SELLBY)) {
915  print '<td class="nowraponall">';
916  $dlcdatesuffix = dol_mktime(0, 0, 0, GETPOST('dlc'.$suffix.'month'), GETPOST('dlc'.$suffix.'day'), GETPOST('dlc'.$suffix.'year'));
917  print $form->selectDate($dlcdatesuffix, 'dlc'.$suffix, '', '', 1, '');
918  print '</td>';
919  }
920  if (empty($conf->global->PRODUCT_DISABLE_EATBY)) {
921  print '<td class="nowraponall">';
922  $dluodatesuffix = dol_mktime(0, 0, 0, GETPOST('dluo'.$suffix.'month'), GETPOST('dluo'.$suffix.'day'), GETPOST('dluo'.$suffix.'year'));
923  print $form->selectDate($dluodatesuffix, 'dluo'.$suffix, '', '', 1, '');
924  print '</td>';
925  }
926  print '<td colspan="3">&nbsp;</td>'; // Supplier ref + Qty ordered + qty already dispatched
927  } else {
928  $type = 'dispatch';
929  $colspan = 7;
930  $colspan = (!empty($conf->global->PRODUCT_DISABLE_SELLBY)) ? --$colspan : $colspan;
931  $colspan = (!empty($conf->global->PRODUCT_DISABLE_EATBY)) ? --$colspan : $colspan;
932 
933  // Enable hooks to append additional columns
934  $parameters = array(
935  // allows hook to distinguish between the rows with information and the rows with dispatch form input
936  'is_information_row' => true,
937  'j' => $j,
938  'suffix' => $suffix,
939  'objp' => $objp,
940  );
941  $reshook = $hookmanager->executeHooks(
942  'printFieldListValue',
943  $parameters,
944  $object,
945  $action
946  );
947  if ($reshook < 0) {
948  setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
949  }
950  print $hookmanager->resPrint;
951 
952  print '</tr>';
953 
954  print '<!-- line no batch '.$numline.' (not dispatched line yet for this order line) -->';
955  print '<tr class="oddeven autoresettr" name="'.$type.$suffix.'" data-remove="clear">';
956  print '<td colspan="'.$colspan.'">';
957  print '<input id="fk_commandefourndet'.$suffix.'" name="fk_commandefourndet'.$suffix.'" type="hidden" value="'.$objp->rowid.'">';
958  print '<input id="idline'.$suffix.'" name="idline'.$suffix.'" type="hidden" value="-1">';
959  print '<input name="product'.$suffix.'" type="hidden" value="'.$objp->fk_product.'">';
960 
961  print '<!-- This is a up (may include discount or not depending on STOCK_EXCLUDE_DISCOUNT_FOR_PMP. will be used for PMP calculation) -->';
962  if (!empty($conf->global->SUPPLIER_ORDER_EDIT_BUYINGPRICE_DURING_RECEIPT)) { // Not tested !
963  print $langs->trans("BuyingPrice").': <input class="maxwidth75" name="pu'.$suffix.'" data-type="text" value="'.price2num($up_ht_disc, 'MU').'">';
964  } else {
965  print '<input class="maxwidth75" name="pu'.$suffix.'" type="hidden" value="'.price2num($up_ht_disc, 'MU').'">';
966  }
967 
968  print '</td>';
969  }
970  // Qty to dispatch
971  print '<td class="right">';
972  print '<a href="#" id="reset'.$suffix.'" class="resetline">'.img_picto($langs->trans("Reset"), 'eraser', 'class="pictofixedwidth opacitymedium"').'</a>';
973  print '<input id="qty'.$suffix.'" onchange="onChangeDispatchLineQty($(this))" name="qty'.$suffix.'" data-index="'.$i.'" data-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)).'" data-expected="'.$remaintodispatch.'">';
974  print '</td>';
975  print '<td>';
976  if (isModEnabled('productbatch') && $objp->tobatch > 0) {
977  $type = 'batch';
978  print img_picto($langs->trans('AddStockLocationLine'), 'split.png', 'class="splitbutton" onClick="addDispatchLine('.$i.', \''.$type.'\')"');
979  } else {
980  $type = 'dispatch';
981  print img_picto($langs->trans('AddStockLocationLine'), 'split.png', 'class="splitbutton" onClick="addDispatchLine('.$i.', \''.$type.'\')"');
982  }
983 
984  print '</td>';
985 
986  if (!empty($conf->global->SUPPLIER_ORDER_CAN_UPDATE_BUYINGPRICE_DURING_RECEIPT)) {
987  if (!isModEnabled("multicurrency") && empty($conf->dynamicprices->enabled)) {
988  // Price
989  print '<td class="right">';
990  print '<input id="pu'.$suffix.'" name="pu'.$suffix.'" type="text" size="8" value="'.price((GETPOST('pu'.$suffix) != '' ? price2num(GETPOST('pu'.$suffix)) : $up_ht_disc)).'">';
991  print '</td>';
992 
993  // Discount
994  print '<td class="right">';
995  print '<input id="dto'.$suffix.'" name="dto'.$suffix.'" type="text" size="8" value="'.(GETPOST('dto'.$suffix) != '' ? GETPOST('dto'.$suffix) : '').'">';
996  print '</td>';
997 
998  // Save price
999  print '<td class="center">';
1000  print '<input class="flat checkformerge" type="checkbox" name="saveprice'.$suffix.'" value="'.(GETPOST('saveprice'.$suffix) != '' ? GETPOST('saveprice'.$suffix) : '').'">';
1001  print '</td>';
1002  }
1003  }
1004 
1005  // Warehouse
1006  print '<td class="right">';
1007  if (count($listwarehouses) > 1) {
1008  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);
1009  } elseif (count($listwarehouses) == 1) {
1010  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);
1011  } else {
1012  $langs->load("errors");
1013  print $langs->trans("ErrorNoWarehouseDefined");
1014  }
1015  print "</td>\n";
1016 
1017  // Enable hooks to append additional columns
1018  $parameters = array(
1019  'is_information_row' => false, // this is a dispatch form row
1020  'i' => $i,
1021  'suffix' => $suffix,
1022  'objp' => $objp,
1023  );
1024  $reshook = $hookmanager->executeHooks(
1025  'printFieldListValue',
1026  $parameters,
1027  $object,
1028  $action
1029  );
1030  if ($reshook < 0) {
1031  setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
1032  }
1033  print $hookmanager->resPrint;
1034  print "</tr>\n";
1035  }
1036  }
1037  }
1038  $i++;
1039  }
1040  $db->free($resql);
1041  } else {
1042  dol_print_error($db);
1043  }
1044 
1045  print "</table>\n";
1046  print '</div>';
1047 
1048  if ($nbproduct) {
1049  $checkboxlabel = $langs->trans("CloseReceivedSupplierOrdersAutomatically", $langs->transnoentitiesnoconv('StatusOrderReceivedAll'));
1050 
1051  print '<div class="center">';
1052  $parameters = array();
1053  $reshook = $hookmanager->executeHooks('addMoreActionsButtons', $parameters, $object, $action); // Note that $action and $object may have been
1054  // modified by hook
1055  if (empty($reshook)) {
1056  if (empty($conf->reception->enabled)) {
1057  print $langs->trans("Comment").' : ';
1058  print '<input type="text" class="minwidth400" maxlength="128" name="comment" value="';
1059  print GETPOSTISSET("comment") ? GETPOST("comment") : $langs->trans("DispatchSupplierOrder", $object->ref);
1060  // print ' / '.$object->ref_supplier; // Not yet available
1061  print '" class="flat"><br>';
1062 
1063  print '<input type="checkbox" checked="checked" name="closeopenorder"> '.$checkboxlabel;
1064  }
1065 
1066  $dispatchBt = empty($conf->reception->enabled) ? $langs->trans("Receive") : $langs->trans("CreateReception");
1067 
1068  print '<br>';
1069  print '<input type="submit" id="submitform" class="button" name="dispatch" value="'.$langs->trans("Save").'"';
1070  $disabled = 0;
1071  if (!$permissiontoreceive) {
1072  $disabled = 1;
1073  }
1074  if (count($listwarehouses) <= 0) {
1075  $disabled = 1;
1076  }
1077  if ($disabled) {
1078  print ' disabled';
1079  }
1080 
1081  print '>';
1082  }
1083  print '</div>';
1084  }
1085 
1086  // Message if nothing to dispatch
1087  if (!$nbproduct) {
1088  print "<br>\n";
1089  if (empty($conf->global->SUPPLIER_ORDER_DISABLE_STOCK_DISPATCH_WHEN_TOTAL_REACHED)) {
1090  print '<div class="opacitymedium">'.$langs->trans("NoPredefinedProductToDispatch").'</div>'; // No predefined line at all
1091  } else {
1092  print '<div class="opacitymedium">'.$langs->trans("NoMorePredefinedProductToDispatch").'</div>'; // No predefined line that remain to be dispatched.
1093  }
1094  }
1095 
1096  print '</form>';
1097  }
1098 
1099  print dol_get_fiche_end();
1100 
1101  // traitement entrepot par défaut
1102  print '<script type="text/javascript">
1103  $(document).ready(function () {
1104  $("select[name=fk_default_warehouse]").change(function() {
1105  var fk_default_warehouse = $("option:selected", this).val();
1106  $("select[name^=entrepot_]").val(fk_default_warehouse).change();
1107  });
1108 
1109  $("#autoreset").click(function() {
1110  $(".autoresettr").each(function(){
1111  id = $(this).attr("name");
1112  idtab = id.split("_");
1113  if ($(this).data("remove") == "clear"){
1114  console.log("We clear the object to expected value")
1115  $("#qty_"+idtab[1]+"_"+idtab[2]).val("");
1116  /*
1117  qtyexpected = $("#qty_"+idtab[1]+"_"+idtab[2]).data("expected")
1118  console.log(qtyexpected);
1119  $("#qty_"+idtab[1]+"_"+idtab[2]).val(qtyexpected);
1120  qtydispatched = $("#qty_dispatched_0_"+idtab[2]).data("dispatched")
1121  $("#qty_dispatched_0_"+idtab[2]).val(qtydispatched);
1122  */
1123  } else {
1124  console.log("We remove the object")
1125  $(this).remove();
1126  $("tr[name^=\'"+idtab[0]+"_\'][name$=\'_"+idtab[2]+"\']:last .splitbutton").show();
1127  }
1128  });
1129  return false;
1130  });
1131 
1132  $("#resetalltoexpected").click(function(){
1133  $(".qtydispatchinput").each(function(){
1134  console.log("We reset to expected "+$(this).attr("id")+" qty to dispatch");
1135  $(this).val($(this).data("expected"));
1136  });
1137  return false;
1138  });
1139 
1140  $(".resetline").click(function(){
1141  id = $(this).attr("id");
1142  id = id.split("reset_");
1143  console.log("Reset trigger for id = qty_"+id[1]);
1144  $("#qty_"+id[1]).val("");
1145  });
1146  });
1147  </script>';
1148 }
1149 
1150 // End of page
1151 llxFooter();
1152 $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.
Class to manage comment.
Class to manage warehouses.
Class to manage generation of HTML components Only common components must be here.
Class with static methods for building HTML components related to products Only components common to ...
Class to manage stock movements.
Class to manage products or services.
Class to manage projects.
Class to manage receptions.
Class to manage third parties objects (customers, suppliers, prospects...)
Class to manage Dolibarr users.
Definition: user.class.php: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
dol_stringtotime($string, $gm=1)
Convert a string date into a GM Timestamps date Warning: YYYY-MM-DDTHH:MM:SS+02:00 (RFC3339) is not s...
Definition: date.lib.php:408
dol_banner_tab($object, $paramid, $morehtml='', $shownav=1, $fieldid='rowid', $fieldref='ref', $morehtmlref='', $moreparam='', $nodbprefix=0, $morehtmlleft='', $morehtmlstatus='', $onlybanner=0, $morehtmlright='')
Show tab footer of a card.
dol_mktime($hour, $minute, $second, $month, $day, $year, $gm='auto', $check=1)
Return a timestamp date built from detailed informations (by default a local PHP server timestamp) Re...
dol_get_fiche_head($links=array(), $active='', $title='', $notab=0, $picto='', $pictoisfullpath=0, $morehtmlright='', $morecss='', $limittoshow=0, $moretabssuffix='', $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_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
reception_prepare_head(Reception $object)
Prepare array with list of tabs.
$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.