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