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