dolibarr  20.0.0-alpha
dispatch.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (C) 2004-2006 Rodolphe Quiedeville <rodolphe@quiedeville.org>
3  * Copyright (C) 2004-2016 Laurent Destailleur <eldy@users.sourceforge.net>
4  * Copyright (C) 2005 Eric Seigne <eric.seigne@ryxeo.com>
5  * Copyright (C) 2005-2009 Regis Houssin <regis.houssin@inodbox.com>
6  * Copyright (C) 2010-2021 Juanjo Menent <jmenent@2byte.es>
7  * Copyright (C) 2014 Cedric Gross <c.gross@kreiz-it.fr>
8  * Copyright (C) 2016 Florian Henry <florian.henry@atm-consulting.fr>
9  * Copyright (C) 2017-2022 Ferran Marcet <fmarcet@2byte.es>
10  * Copyright (C) 2018-2022 Frédéric France <frederic.france@netlogic.fr>
11  * Copyright (C) 2019-2020 Christophe Battarel <christophe@altairis.fr>
12  *
13  * This program is free software; you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License as published by
15  * the Free Software Foundation; either version 3 of the License, or
16  * (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program. If not, see <https://www.gnu.org/licenses/>.
25  */
26 
33 // Load Dolibarr environment
34 require '../main.inc.php';
35 require_once DOL_DOCUMENT_ROOT.'/core/modules/supplier_order/modules_commandefournisseur.php';
36 require_once DOL_DOCUMENT_ROOT.'/product/stock/class/entrepot.class.php';
37 require_once DOL_DOCUMENT_ROOT.'/core/lib/fourn.lib.php';
38 require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.commande.class.php';
39 require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.commande.dispatch.class.php';
40 require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php';
41 require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
42 require_once DOL_DOCUMENT_ROOT.'/core/lib/sendings.lib.php';
43 if (isModEnabled('project')) {
44  require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
45 }
46 
47 // Load translation files required by the page
48 $langs->loadLangs(array("sendings", "companies", "bills", 'deliveries', 'orders', 'stocks', 'other', 'propal', 'receptions'));
49 
50 if (isModEnabled('productbatch')) {
51  $langs->load('productbatch');
52 }
53 
54 // Security check
55 $id = GETPOSTINT("id");
56 $ref = GETPOST('ref');
57 $lineid = GETPOSTINT('lineid');
58 $action = GETPOST('action', 'aZ09');
59 $fk_default_warehouse = GETPOSTINT('fk_default_warehouse');
60 $cancel = GETPOST('cancel', 'alpha');
61 $confirm = GETPOST('confirm', 'alpha');
62 
63 $error = 0;
64 $errors = array();
65 
66 if ($user->socid) {
67  $socid = $user->socid;
68 }
69 
70 $hookmanager->initHooks(array('expeditiondispatch'));
71 
72 // Recuperation de l'id de projet
73 $projectid = 0;
74 if (GETPOSTISSET("projectid")) {
75  $projectid = GETPOSTINT("projectid");
76 }
77 
78 $object = new Expedition($db);
79 $objectorder = new Commande($db);
80 
81 
82 if ($id > 0 || !empty($ref)) {
83  $result = $object->fetch($id, $ref);
84  if ($result <= 0) {
85  setEventMessages($object->error, $object->errors, 'errors');
86  }
87  $result = $object->fetch_thirdparty();
88  if ($result < 0) {
89  setEventMessages($object->error, $object->errors, 'errors');
90  }
91  if (!empty($object->origin)) {
92  $origin = $object->origin;
93  $typeobject = $object->origin;
94 
95  $object->fetch_origin();
96  }
97 }
98 
99 // $id is id of a purchase order.
100 $result = restrictedArea($user, 'expedition', $object, '');
101 
102 if (!isModEnabled('stock')) {
103  accessforbidden('Module stock disabled');
104 }
105 
106 $usercancreate = $user->hasRight('expedition', 'creer');
107 $permissiontoadd = $usercancreate; // Used by the include of actions_addupdatedelete.inc.php
108 
109 
110 /*
111  * Actions
112  */
113 
114 $parameters = array();
115 $reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
116 if ($reshook < 0) {
117  setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
118 }
119 
120 // Update a dispatched line
121 if ($action == 'updatelines' && $usercancreate) {
122  $db->begin();
123  $error = 0;
124 
125  $expeditiondispatch = new ExpeditionLigne($db);
126  $expeditionlinebatch = new ExpeditionLineBatch($db);
127 
128  $pos = 0;
129 
130  foreach ($_POST as $key => $value) {
131  // without batch module enabled
132  $reg = array();
133  if (preg_match('/^product_.*([0-9]+)_([0-9]+)$/i', $key, $reg)) {
134  $pos++;
135  if (preg_match('/^product_([0-9]+)_([0-9]+)$/i', $key, $reg)) {
136  $modebatch = "barcode";
137  } elseif (preg_match('/^product_batch_([0-9]+)_([0-9]+)$/i', $key, $reg)) { // With batchmode enabled
138  $modebatch = "batch";
139  }
140 
141  $numline = $pos;
142  if ($modebatch == "barcode") {
143  $prod = "product_".$reg[1].'_'.$reg[2];
144  } else {
145  $prod = 'product_batch_'.$reg[1].'_'.$reg[2];
146  }
147  $qty = "qty_".$reg[1].'_'.$reg[2];
148  $ent = "entrepot_".$reg[1].'_'.$reg[2];
149  $fk_commandedet = "fk_commandedet_".$reg[1].'_'.$reg[2];
150  $idline = GETPOST("idline_".$reg[1].'_'.$reg[2]);
151  $warehouse_id = GETPOSTINT($ent);
152  $prod_id = GETPOSTINT($prod);
153  //$pu = "pu_".$reg[1].'_'.$reg[2]; // This is unit price including discount
154  $lot = '';
155  $dDLUO = '';
156  $dDLC = '';
157  if ($modebatch == "batch") { //TODO: Make impossible to input non existing batch code
158  $lot = GETPOST('lot_number_'.$reg[1].'_'.$reg[2]);
159  $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'));
160  $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'));
161  }
162 
163  $newqty = GETPOSTFLOAT($qty, 'MS');
164  //var_dump("modebatch=".$modebatch." newqty=".$newqty." ent=".$ent." idline=".$idline);
165 
166  // We ask to move a qty
167  if (($modebatch == "batch" && $newqty >= 0) || ($modebatch == "barcode" && $newqty != 0)) {
168  if ($newqty > 0) { // If we want a qty, we make test on input data
169  if (!($warehouse_id > 0)) {
170  dol_syslog('No dispatch for line '.$key.' as no warehouse was chosen.');
171  $text = $langs->transnoentities('Warehouse').', '.$langs->transnoentities('Line').' '.($numline);
172  setEventMessages($langs->trans('ErrorFieldRequired', $text), null, 'errors');
173  $error++;
174  }
175  if (!$error && $modebatch == "batch") {
176  $sql = "SELECT pb.rowid ";
177  $sql .= " FROM ".MAIN_DB_PREFIX."product_batch as pb";
178  $sql .= " JOIN ".MAIN_DB_PREFIX."product_stock as ps";
179  $sql .= " ON ps.rowid = pb.fk_product_stock";
180  $sql .= " WHERE pb.batch = '".$db->escape($lot)."'";
181  $sql .= " AND ps.fk_product = ".((int) $prod_id) ;
182  $sql .= " AND ps.fk_entrepot = ".((int) $warehouse_id) ;
183 
184  $resql = $db->query($sql);
185  if ($resql) {
186  $num = $db->num_rows($resql);
187  if ($num > 1) {
188  dol_syslog('No dispatch for line '.$key.' as too many combination warehouse, product, batch code was found ('.$num.').');
189  setEventMessages($langs->trans('ErrorTooManyCombinationBatchcode', $numline, $num), null, 'errors');
190  $error++;
191  } elseif ($num < 1) {
192  $tmpwarehouse = new Entrepot($db);
193  $tmpwarehouse->fetch($warehouse_id);
194  $tmpprod = new Product($db);
195  $tmpprod->fetch($prod_id);
196  dol_syslog('No dispatch for line '.$key.' as no combination warehouse, product, batch code was found.');
197  setEventMessages($langs->trans('ErrorNoCombinationBatchcode', $numline, $tmpwarehouse->ref, $tmpprod->ref, $lot), null, 'errors');
198  $error++;
199  }
200  $db->free($resql);
201  }
202  }
203  }
204  //var_dump($key.' '.$newqty.' '.$idline.' '.$error);
205 
206  if (!$error) {
207  $qtystart = 0;
208 
209  if ($idline > 0) {
210  $result = $expeditiondispatch->fetch($idline); // get line from llx_expeditiondet
211  if ($result < 0) {
212  setEventMessages($expeditiondispatch->error, $expeditiondispatch->errors, 'errors');
213  $error++;
214  } else {
215  $qtystart = $expeditiondispatch->qty;
216  $expeditiondispatch->qty = $newqty;
217  $expeditiondispatch->entrepot_id = GETPOSTINT($ent);
218 
219  if ($newqty > 0) {
220  $result = $expeditiondispatch->update($user);
221  } else {
222  $result = $expeditiondispatch->delete($user);
223  }
224  if ($result < 0) {
225  setEventMessages($expeditiondispatch->error, $expeditiondispatch->errors, 'errors');
226  $error++;
227  }
228 
229  if (!$error && $modebatch == "batch") {
230  if ($newqty > 0) {
231  $suffixkeyfordate = preg_replace('/^product_batch/', '', $key);
232  $sellby = dol_mktime(0, 0, 0, GETPOST('dlc'.$suffixkeyfordate.'month'), GETPOST('dlc'.$suffixkeyfordate.'day'), GETPOST('dlc'.$suffixkeyfordate.'year'), '');
233  $eatby = dol_mktime(0, 0, 0, GETPOST('dluo'.$suffixkeyfordate.'month'), GETPOST('dluo'.$suffixkeyfordate.'day'), GETPOST('dluo'.$suffixkeyfordate.'year'));
234 
235  $sqlsearchdet = "SELECT rowid FROM ".MAIN_DB_PREFIX.$expeditionlinebatch->table_element;
236  $sqlsearchdet .= " WHERE fk_expeditiondet = ".((int) $idline);
237  $sqlsearchdet .= " AND batch = '".$db->escape($lot)."'";
238  $resqlsearchdet = $db->query($sqlsearchdet);
239 
240  if ($resqlsearchdet) {
241  $objsearchdet = $db->fetch_object($resqlsearchdet);
242  } else {
243  dol_print_error($db);
244  }
245 
246  if ($objsearchdet) {
247  $sql = "UPDATE ".MAIN_DB_PREFIX.$expeditionlinebatch->table_element." SET";
248  $sql .= " eatby = ".($eatby ? "'".$db->idate($eatby)."'" : "null");
249  $sql .= " , sellby = ".($sellby ? "'".$db->idate($sellby)."'" : "null");
250  $sql .= " , qty = ".((float) $newqty);
251  $sql .= " , fk_warehouse = ".((int) $warehouse_id);
252  $sql .= " WHERE rowid = ".((int) $objsearchdet->rowid);
253  } else {
254  $sql = "INSERT INTO ".MAIN_DB_PREFIX.$expeditionlinebatch->table_element." (";
255  $sql .= "fk_expeditiondet, eatby, sellby, batch, qty, fk_origin_stock, fk_warehouse)";
256  $sql .= " VALUES (".((int) $idline).", ".($eatby ? "'".$db->idate($eatby)."'" : "null").", ".($sellby ? "'".$db->idate($sellby)."'" : "null").", ";
257  $sql .= " '".$db->escape($lot)."', ".((float) $newqty).", 0, ".((int) $warehouse_id).")";
258  }
259  } else {
260  $sql = " DELETE FROM ".MAIN_DB_PREFIX.$expeditionlinebatch->table_element;
261  $sql .= " WHERE fk_expeditiondet = ".((int) $idline);
262  $sql .= " AND batch = '".$db->escape($lot)."'";
263  }
264 
265  $resql = $db->query($sql);
266  if (!$resql) {
267  dol_print_error($db);
268  $error++;
269  }
270  }
271  }
272  } else {
273  $expeditiondispatch->fk_expedition = $object->id;
274  $expeditiondispatch->entrepot_id = GETPOSTINT($ent);
275  $expeditiondispatch->fk_elementdet = GETPOSTINT($fk_commandedet);
276  $expeditiondispatch->qty = $newqty;
277 
278  if ($newqty > 0) {
279  $idline = $expeditiondispatch->insert($user);
280  if ($idline < 0) {
281  setEventMessages($expeditiondispatch->error, $expeditiondispatch->errors, 'errors');
282  $error++;
283  }
284 
285  if ($modebatch == "batch" && !$error) {
286  $expeditionlinebatch->sellby = $dDLUO;
287  $expeditionlinebatch->eatby = $dDLC;
288  $expeditionlinebatch->batch = $lot;
289  $expeditionlinebatch->qty = $newqty;
290  $expeditionlinebatch->fk_origin_stock = 0;
291  $expeditionlinebatch->fk_warehouse = GETPOSTINT($ent);
292 
293  $result = $expeditionlinebatch->create($idline);
294  if ($result < 0) {
295  setEventMessages($expeditionlinebatch->error, $expeditionlinebatch->errors, 'errors');
296  $error++;
297  }
298  }
299  }
300  }
301 
302  // If module stock is enabled and the stock decrease is done on edition of this page
303  /*
304  if (!$error && GETPOST($ent, 'int') > 0 && isModEnabled('stock') && !empty($conf->global->STOCK_CALCULATE_ON_SHIPMENT_DISPATCH_ORDER)) {
305  $mouv = new MouvementStock($db);
306  $product = GETPOST($prod, 'int');
307  $entrepot = GETPOST($ent, 'int');
308  $qtymouv = price2num(GETPOST($qty, 'alpha'), 'MS') - $qtystart;
309  $price = price2num(GETPOST($pu), 'MU');
310  $comment = GETPOST('comment');
311  $inventorycode = dol_print_date(dol_now(), 'dayhourlog');
312  $now = dol_now();
313  $eatby = '';
314  $sellby = '';
315  $batch = '';
316  if ($modebatch == "batch") {
317  $eatby = $dDLUO;
318  $sellby = $dDLC;
319  $batch = $lot ;
320  }
321  if ($product > 0 && $qtymouv != 0) {
322  // $price should take into account discount (except if option STOCK_EXCLUDE_DISCOUNT_FOR_PMP is on)
323  $mouv->origin = $objectorder;
324  $mouv->setOrigin($objectorder->element, $objectorder->id);
325 
326  // Method change if qty < 0
327  if (!empty($conf->global->SUPPLIER_ORDER_ALLOW_NEGATIVE_QTY_FOR_SUPPLIER_ORDER_RETURN) && $qtymouv < 0) {
328  $result = $mouv->reception($user, $product, $entrepot, $qtymouv*(-1), $price, $comment, $eatby, $sellby, $batch, '', 0, $inventorycode);
329  } else {
330  $result = $mouv->livraison($user, $product, $entrepot, $qtymouv, $price, $comment, $now, $eatby, $sellby, $batch, 0, $inventorycode);
331  }
332 
333  if ($result < 0) {
334  setEventMessages($mouv->error, $mouv->errors, 'errors');
335  $error++;
336  }
337  }
338  }
339  */
340  }
341  }
342  }
343  }
344 
345  if ($error > 0) {
346  $db->rollback();
347  setEventMessages($error, $errors, 'errors');
348  } else {
349  $db->commit();
350  setEventMessages($langs->trans("ReceptionUpdated"), null);
351 
352  header("Location: ".DOL_URL_ROOT.'/expedition/dispatch.php?id='.$object->id);
353  exit;
354  }
355 } elseif ($action == 'setdate_livraison' && $usercancreate) {
356  $datedelivery = dol_mktime(GETPOSTINT('liv_hour'), GETPOSTINT('liv_min'), 0, GETPOSTINT('liv_month'), GETPOSTINT('liv_day'), GETPOSTINT('liv_year'));
357 
358  $object->fetch($id);
359  $result = $object->setDeliveryDate($user, $datedelivery);
360  if ($result < 0) {
361  setEventMessages($object->error, $object->errors, 'errors');
362  }
363 }
364 
365 
366 /*
367  * View
368  */
369 
370 $now = dol_now();
371 
372 $form = new Form($db);
373 $formproduct = new FormProduct($db);
374 $warehouse_static = new Entrepot($db);
375 
376 $title = $object->ref." - ".$langs->trans('ShipmentDistribution');
377 $help_url = 'EN:Module_Shipments|FR:Module_Expéditions|ES:M&oacute;dulo_Expediciones|DE:Modul_Lieferungen';
378 $morejs = array('/expedition/js/lib_dispatch.js.php');
379 
380 llxHeader('', $title, $help_url, '', 0, 0, $morejs);
381 
382 if ($object->id > 0 || !empty($object->ref)) {
383  $lines = $object->lines; // This is an array of detail of line, on line per source order line found intolines[]->fk_elementdet, then each line may have sub data
384  //var_dump($lines[0]->fk_elementdet); exit;
385 
386  $num_prod = count($lines);
387 
388  if (!empty($object->origin) && $object->origin_id > 0) {
389  $object->origin = 'commande';
390  $typeobject = $object->origin;
391  $origin = $object->origin;
392 
393  $object->fetch_origin(); // Load property $object->origin_object, $object->commande, $object->propal, ...
394  }
395  $soc = new Societe($db);
396  $soc->fetch($object->socid);
397 
398  $author = new User($db);
399  $author->fetch($object->user_author_id);
400 
402 
403  print dol_get_fiche_head($head, 'dispatch', $langs->trans("Shipment"), -1, $object->picto);
404 
405 
406  $formconfirm = '';
407 
408  // Confirmation to delete line
409  if ($action == 'ask_deleteline') {
410  $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id.'&lineid='.$lineid, $langs->trans('DeleteLine'), $langs->trans('ConfirmDeleteLine'), 'confirm_deleteline', '', 0, 1);
411  }
412 
413  // Call Hook formConfirm
414  $parameters = array('lineid' => $lineid);
415  // Note that $action and $object may be modified by hook
416  $reshook = $hookmanager->executeHooks('formConfirm', $parameters, $object, $action);
417  if (empty($reshook)) {
418  $formconfirm .= $hookmanager->resPrint;
419  } elseif ($reshook > 0) {
420  $formconfirm = $hookmanager->resPrint;
421  }
422 
423  // Print form confirm
424  print $formconfirm;
425 
426  if ($typeobject == 'commande' && $object->origin_object->id && isModEnabled('order')) {
427  $objectsrc = new Commande($db);
428  $objectsrc->fetch($object->origin_object->id);
429  }
430  if ($typeobject == 'propal' && $object->origin_object->id && isModEnabled("propal")) {
431  $objectsrc = new Propal($db);
432  $objectsrc->fetch($object->origin_object->id);
433  }
434 
435  // Shipment card
436  $linkback = '<a href="'.DOL_URL_ROOT.'/expedition/list.php?restore_lastsearch_values=1'.(!empty($socid) ? '&socid='.$socid : '').'">'.$langs->trans("BackToList").'</a>';
437  $morehtmlref = '<div class="refidno">';
438 
439  // Ref customer shipment
440  $morehtmlref .= $form->editfieldkey("RefCustomer", 'ref_customer', $object->ref_customer, $object, $user->hasRight('expedition', 'creer'), 'string', '', 0, 1);
441  $morehtmlref .= $form->editfieldval("RefCustomer", 'ref_customer', $object->ref_customer, $object, $user->hasRight('expedition', 'creer'), 'string'.(isset($conf->global->THIRDPARTY_REF_INPUT_SIZE) ? ':' . getDolGlobalString('THIRDPARTY_REF_INPUT_SIZE') : ''), '', null, null, '', 1);
442 
443  // Thirdparty
444  $morehtmlref .= '<br>'.$object->thirdparty->getNomUrl(1);
445  // Project
446  if (isModEnabled('project')) {
447  $langs->load("projects");
448  $morehtmlref .= '<br>';
449  if (0) { // Do not change on reception
450  $morehtmlref .= img_picto($langs->trans("Project"), 'project', 'class="pictofixedwidth"');
451  if ($action != 'classify' && $permissiontoadd) {
452  $morehtmlref .= '<a class="editfielda" href="'.$_SERVER['PHP_SELF'].'?action=classify&token='.newToken().'&id='.$object->id.'">'.img_edit($langs->transnoentitiesnoconv('SetProject')).'</a> ';
453  }
454  $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');
455  } else {
456  if (!empty($objectsrc) && !empty($objectsrc->fk_project)) {
457  $proj = new Project($db);
458  $proj->fetch($objectsrc->fk_project);
459  $morehtmlref .= $proj->getNomUrl(1);
460  if ($proj->title) {
461  $morehtmlref .= '<span class="opacitymedium"> - '.dol_escape_htmltag($proj->title).'</span>';
462  }
463  }
464  }
465  }
466  $morehtmlref .= '</div>';
467 
468  dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref);
469 
470 
471  print '<div class="fichecenter">';
472  print '<div class="underbanner clearboth"></div>';
473 
474  print '<table class="border tableforfield centpercent">';
475 
476  // Linked documents
477  if ($typeobject == 'commande' && $object->origin_object->id && isModEnabled('order')) {
478  print '<tr><td>';
479  print $langs->trans("RefOrder").'</td>';
480  print '<td colspan="3">';
481  print $objectsrc->getNomUrl(1, 'commande');
482  print "</td>\n";
483  print '</tr>';
484  }
485  if ($typeobject == 'propal' && $object->origin_object->id && isModEnabled("propal")) {
486  print '<tr><td>';
487  print $langs->trans("RefProposal").'</td>';
488  print '<td colspan="3">';
489  print $objectsrc->getNomUrl(1, 'expedition');
490  print "</td>\n";
491  print '</tr>';
492  }
493 
494  // Date creation
495  print '<tr><td class="titlefield">'.$langs->trans("DateCreation").'</td>';
496  print '<td colspan="3">'.dol_print_date($object->date_creation, "dayhour", "tzuserrel")."</td>\n";
497  print '</tr>';
498 
499  // Delivery date planned
500  print '<tr><td height="10">';
501  print '<table class="nobordernopadding" width="100%"><tr><td>';
502  print $langs->trans('DateDeliveryPlanned');
503  print '</td>';
504  if ($action != 'editdate_livraison') {
505  print '<td class="right"><a class="editfielda" href="'.$_SERVER["PHP_SELF"].'?action=editdate_livraison&token='.newToken().'&id='.$object->id.'">'.img_edit($langs->trans('SetDeliveryDate'), 1).'</a></td>';
506  }
507  print '</tr></table>';
508  print '</td><td colspan="2">';
509  if ($action == 'editdate_livraison') {
510  print '<form name="setdate_livraison" action="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'" method="post">';
511  print '<input type="hidden" name="token" value="'.newToken().'">';
512  print '<input type="hidden" name="action" value="setdate_livraison">';
513  print $form->selectDate($object->date_delivery ? $object->date_delivery : -1, 'liv_', 1, 1, 0, "setdate_livraison", 1, 0);
514  print '<input type="submit" class="button button-edit smallpaddingimp" value="'.$langs->trans('Modify').'">';
515  print '</form>';
516  } else {
517  print $object->date_delivery ? dol_print_date($object->date_delivery, 'dayhour') : '&nbsp;';
518  }
519  print '</td>';
520  print '</tr></table>';
521 
522  print '<br><center>';
523  if (isModEnabled('barcode') || isModEnabled('productbatch')) {
524  print '<a href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=updatebyscaning&token='.currentToken().'" class="marginrightonly paddingright marginleftonly paddingleft">'.img_picto('', 'barcode', 'class="paddingrightonly"').$langs->trans("UpdateByScaning").'</a>';
525  }
526  print '<a href="#" id="resetalltoexpected" class="marginrightonly paddingright marginleftonly paddingleft">'.img_picto("", 'autofill', 'class="pictofixedwidth"').$langs->trans("RestoreWithCurrentQtySaved").'</a></td>';
527  // Link to clear qty
528  print '<a href="#" id="autoreset" class="marginrightonly paddingright marginleftonly paddingleft">'.img_picto("", 'eraser', 'class="pictofixedwidth"').$langs->trans("ClearQtys").'</a></td>';
529  print '<center>';
530 
531  print '<br>';
532  $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.
533 
534  if ($object->statut == Expedition::STATUS_DRAFT) {
535  require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php';
536  $formproduct = new FormProduct($db);
537  $formproduct->loadWarehouses();
538  $entrepot = new Entrepot($db);
539  $listwarehouses = $entrepot->list_array(1);
540 
541 
542  print '<form method="post" action="'.$_SERVER["PHP_SELF"].'">';
543 
544  print '<input type="hidden" name="token" value="'.newToken().'">';
545  print '<input type="hidden" name="action" value="updatelines">';
546  print '<input type="hidden" name="id" value="'.$object->id.'">';
547 
548  print '<div class="div-table-responsive-no-min">';
549  print '<table class="noborder centpercent">';
550 
551  // Get list of lines of the shipment $products_dispatched, with qty dispatched for each product id
552  $products_dispatched = array();
553  $sql = "SELECT ed.fk_elementdet as rowid, sum(ed.qty) as qty";
554  $sql .= " FROM ".MAIN_DB_PREFIX."expeditiondet as ed";
555  $sql .= " WHERE ed.fk_expedition = ".((int) $object->id);
556  $sql .= " GROUP BY ed.fk_elementdet";
557 
558  $resql = $db->query($sql);
559  if ($resql) {
560  $num = $db->num_rows($resql);
561  $i = 0;
562 
563  if ($num) {
564  while ($i < $num) {
565  $objd = $db->fetch_object($resql);
566  $products_dispatched[$objd->rowid] = price2num($objd->qty, 'MS');
567  $i++;
568  }
569  }
570  $db->free($resql);
571  }
572 
573  //$sql = "SELECT l.rowid, l.fk_product, l.subprice, l.remise_percent, l.ref AS sref, SUM(l.qty) as qty,";
574  $sql = "SELECT l.rowid, l.fk_product, l.subprice, l.remise_percent, '' AS sref, l.qty as qty,";
575  $sql .= " p.ref, p.label, p.tobatch, p.fk_default_warehouse, p.barcode";
576  // Enable hooks to alter the SQL query (SELECT)
577  $parameters = array();
578  $reshook = $hookmanager->executeHooks(
579  'printFieldListSelect',
580  $parameters,
581  $object,
582  $action
583  );
584  if ($reshook < 0) {
585  setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
586  }
587  $sql .= $hookmanager->resPrint;
588 
589  $sql .= " FROM ".MAIN_DB_PREFIX."commandedet as l";
590  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product as p ON l.fk_product=p.rowid";
591  $sql .= " WHERE l.fk_commande = ".((int) $objectsrc->id);
592  if (!getDolGlobalString('STOCK_SUPPORTS_SERVICES')) {
593  $sql .= " AND l.product_type = 0";
594  }
595  // Enable hooks to alter the SQL query (WHERE)
596  $parameters = array();
597  $reshook = $hookmanager->executeHooks(
598  'printFieldListWhere',
599  $parameters,
600  $object,
601  $action
602  );
603  if ($reshook < 0) {
604  setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
605  }
606  $sql .= $hookmanager->resPrint;
607 
608  //$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
609  $sql .= " ORDER BY l.rang, p.ref, p.label";
610 
611  $resql = $db->query($sql);
612  if ($resql) {
613  $num = $db->num_rows($resql);
614  $i = 0;
615  $numline = 1;
616 
617  if ($num) {
618  print '<tr class="liste_titre">';
619 
620  print '<td>'.$langs->trans("Description").'</td>';
621  if (isModEnabled('productbatch')) {
622  print '<td class="dispatch_batch_number_title">'.$langs->trans("batch_number").'</td>';
623  if (!getDolGlobalString('PRODUCT_DISABLE_SELLBY')) {
624  print '<td class="dispatch_dlc_title">'.$langs->trans("SellByDate").'</td>';
625  }
626  if (!getDolGlobalString('PRODUCT_DISABLE_EATBY')) {
627  print '<td class="dispatch_dluo_title">'.$langs->trans("EatByDate").'</td>';
628  }
629  } else {
630  print '<td></td>';
631  print '<td></td>';
632  print '<td></td>';
633  }
634  print '<td class="right">'.$langs->trans("QtyOrdered").'</td>';
635  if ($object->status == Expedition::STATUS_DRAFT) {
636  print '<td class="right">'.$langs->trans("QtyToShip"); // Qty to dispatch (sum for all lines of batch detail if there is)
637  } else {
638  print '<td class="right">'.$langs->trans("QtyDispatchedShort").'</td>';
639  }
640  print '<td class="right">'.$langs->trans("Details");
641  print '<td width="32"></td>';
642 
643  if (getDolGlobalString('SUPPLIER_ORDER_CAN_UPDATE_BUYINGPRICE_DURING_RECEIPT')) {
644  if (!isModEnabled("multicurrency") && empty($conf->dynamicprices->enabled)) {
645  print '<td class="right">'.$langs->trans("Price").'</td>';
646  print '<td class="right">'.$langs->trans("ReductionShort").' (%)</td>';
647  print '<td class="right">'.$langs->trans("UpdatePrice").'</td>';
648  }
649  }
650 
651  print '<td align="right">'.$langs->trans("Warehouse");
652 
653  // Select warehouse to force it everywhere
654  if (count($listwarehouses) > 1) {
655  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);
656  } elseif (count($listwarehouses) == 1) {
657  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);
658  }
659 
660  print '</td>';
661 
662  // Enable hooks to append additional columns
663  $parameters = array();
664  $reshook = $hookmanager->executeHooks(
665  'printFieldListTitle',
666  $parameters,
667  $object,
668  $action
669  );
670  if ($reshook < 0) {
671  setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
672  }
673  print $hookmanager->resPrint;
674 
675  print "</tr>\n";
676  }
677 
678  $nbfreeproduct = 0; // Nb of lins of free products/services
679  $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)
680  // or nb of line that remain to dispatch if SUPPLIER_ORDER_DISABLE_STOCK_DISPATCH_WHEN_TOTAL_REACHED is on.
681 
682  $conf->cache['product'] = array();
683 
684  // Loop on each line of origin order
685  while ($i < $num) {
686  $objp = $db->fetch_object($resql);
687 
688  // On n'affiche pas les produits libres
689  if (!$objp->fk_product > 0) {
690  $nbfreeproduct++;
691  } else {
692  $alreadydispatched = isset($products_dispatched[$objp->rowid]) ? $products_dispatched[$objp->rowid] : 0;
693  $remaintodispatch = price2num($objp->qty, 5); // Calculation of dispatched
694  if ($remaintodispatch < 0 && !getDolGlobalString('SUPPLIER_ORDER_ALLOW_NEGATIVE_QTY_FOR_SUPPLIER_ORDER_RETURN')) {
695  $remaintodispatch = 0;
696  }
697 
698  if ($remaintodispatch || !getDolGlobalString('SUPPLIER_ORDER_DISABLE_STOCK_DISPATCH_WHEN_TOTAL_REACHED')) {
699  $nbproduct++;
700 
701  // To show detail cref and description value, we must make calculation by cref
702  // print ($objp->cref?' ('.$objp->cref.')':'');
703  // if ($objp->description) print '<br>'.nl2br($objp->description);
704  $suffix = '_0_'.$i;
705 
706  print "\n";
707  print '<!-- Line to dispatch '.$suffix.' -->'."\n";
708  // hidden fields for js function
709  print '<input id="qty_ordered'.$suffix.'" type="hidden" value="'.$objp->qty.'">';
710  print '<input id="qty_dispatched'.$suffix.'" type="hidden" data-dispatched="'.((float) $alreadydispatched).'" value="'.(float) $alreadydispatched.'">';
711  print '<tr class="oddeven">';
712 
713  if (empty($conf->cache['product'][$objp->fk_product])) {
714  $tmpproduct = new Product($db);
715  $tmpproduct->fetch($objp->fk_product);
716  $conf->cache['product'][$objp->fk_product] = $tmpproduct;
717  } else {
718  $tmpproduct = $conf->cache['product'][$objp->fk_product];
719  }
720 
721  $linktoprod = $tmpproduct->getNomUrl(1);
722  $linktoprod .= ' - '.$objp->label."\n";
723 
724  if (isModEnabled('productbatch')) {
725  if ($objp->tobatch) {
726  // Product
727  print '<td id="product_'.$i.'" data-idproduct="'.$objp->fk_product.'" data-barcode="'.$objp->barcode.'">';
728  print $linktoprod;
729  print "</td>";
730  print '<td class="dispatch_batch_number"></td>';
731  if (!getDolGlobalString('PRODUCT_DISABLE_SELLBY')) {
732  print '<td class="dispatch_dlc"></td>';
733  }
734  if (!getDolGlobalString('PRODUCT_DISABLE_EATBY')) {
735  print '<td class="dispatch_dluo"></td>';
736  }
737  } else {
738  // Product
739  print '<td id="product_'.$i.'" data-idproduct="'.$objp->fk_product.'" data-barcode="'.$objp->barcode.'">';
740  print $linktoprod;
741  print "</td>";
742  print '<td class="dispatch_batch_number">';
743  print '<span class="opacitymedium small">'.$langs->trans("ProductDoesNotUseBatchSerial").'</span>';
744  print '</td>';
745  if (!getDolGlobalString('PRODUCT_DISABLE_SELLBY')) {
746  print '<td class="dispatch_dlc"></td>';
747  }
748  if (!getDolGlobalString('PRODUCT_DISABLE_EATBY')) {
749  print '<td class="dispatch_dluo"></td>';
750  }
751  }
752  } else {
753  print '<td colspan="4">';
754  print $linktoprod;
755  print "</td>";
756  }
757 
758  // Define unit price for PMP calculation
759  $up_ht_disc = $objp->subprice;
760  if (!empty($objp->remise_percent) && !getDolGlobalString('STOCK_EXCLUDE_DISCOUNT_FOR_PMP')) {
761  $up_ht_disc = price2num($up_ht_disc * (100 - $objp->remise_percent) / 100, 'MU');
762  }
763 
764  // Qty ordered
765  print '<td class="right">'.$objp->qty.'</td>';
766 
767  // Already dispatched
768  print '<td class="right">'.$alreadydispatched.'</td>';
769 
770  print '<td class="right">';
771  print '</td>'; // Qty to dispatch
772  print '<td>';
773  print '</td>'; // Dispatch column
774  print '<td></td>'; // Warehouse column
775 
776  $sql = "SELECT ed.rowid, ed.qty, ed.fk_entrepot,";
777  $sql .= " eb.batch, eb.eatby, eb.sellby, cd.fk_product";
778  $sql .= " FROM ".MAIN_DB_PREFIX."expeditiondet as ed";
779  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."expeditiondet_batch as eb on ed.rowid = eb.fk_expeditiondet";
780  $sql .= " JOIN ".MAIN_DB_PREFIX."commandedet as cd on ed.fk_elementdet = cd.rowid";
781  $sql .= " WHERE ed.fk_elementdet =".(int) $objp->rowid;
782  $sql .= " AND ed.fk_expedition =".(int) $object->id;
783  $sql .= " ORDER BY ed.rowid, ed.fk_elementdet";
784 
785  $resultsql = $db->query($sql);
786  $j = 0;
787  if ($resultsql) {
788  $numd = $db->num_rows($resultsql);
789 
790  while ($j < $numd) {
791  $suffix = "_".$j."_".$i;
792  $objd = $db->fetch_object($resultsql);
793 
794  if (isModEnabled('productbatch') && (!empty($objd->batch) || (is_null($objd->batch) && $tmpproduct->status_batch > 0))) {
795  $type = 'batch';
796 
797  // Enable hooks to append additional columns
798  $parameters = array(
799  // allows hook to distinguish between the rows with information and the rows with dispatch form input
800  'is_information_row' => true,
801  'j' => $j,
802  'suffix' => $suffix,
803  'objd' => $objd,
804  );
805  $reshook = $hookmanager->executeHooks(
806  'printFieldListValue',
807  $parameters,
808  $object,
809  $action
810  );
811  if ($reshook < 0) {
812  setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
813  }
814  print $hookmanager->resPrint;
815 
816  print '</tr>';
817 
818  print '<!-- line for batch '.$numline.' -->';
819  print '<tr class="oddeven autoresettr" name="'.$type.$suffix.'" data-remove="clear">';
820  print '<td>';
821  print '<input id="fk_commandedet'.$suffix.'" name="fk_commandedet'.$suffix.'" type="hidden" value="'.$objp->rowid.'">';
822  print '<input id="idline'.$suffix.'" name="idline'.$suffix.'" type="hidden" value="'.$objd->rowid.'">';
823  print '<input name="product_batch'.$suffix.'" type="hidden" value="'.$objd->fk_product.'">';
824 
825  print '<!-- This is a U.P. (may include discount or not depending on STOCK_EXCLUDE_DISCOUNT_FOR_PMP. will be used for PMP calculation) -->';
826  print '<input class="maxwidth75" name="pu'.$suffix.'" type="hidden" value="'.price2num($up_ht_disc, 'MU').'">';
827 
828  print '</td>';
829 
830  print '<td>';
831  print '<input type="text" class="inputlotnumber quatrevingtquinzepercent" id="lot_number'.$suffix.'" name="lot_number'.$suffix.'" value="'.(GETPOSTISSET('lot_number'.$suffix) ? GETPOST('lot_number'.$suffix) : $objd->batch).'">';
832  //print '<input type="hidden" id="lot_number'.$suffix.'" name="lot_number'.$suffix.'" value="'.$objd->batch.'">';
833  print '</td>';
834  if (!getDolGlobalString('PRODUCT_DISABLE_SELLBY')) {
835  print '<td class="nowraponall">';
836  $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'));
837  print $form->selectDate($dlcdatesuffix, 'dlc'.$suffix, 0, 0, 1, '');
838  print '</td>';
839  }
840  if (!getDolGlobalString('PRODUCT_DISABLE_EATBY')) {
841  print '<td class="nowraponall">';
842  $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'));
843  print $form->selectDate($dluodatesuffix, 'dluo'.$suffix, 0, 0, 1, '');
844  print '</td>';
845  }
846  print '<td colspan="2">&nbsp;</td>'; // Supplier ref + Qty ordered + qty already dispatched
847  } else {
848  $type = 'dispatch';
849  $colspan = 6;
850  $colspan = (getDolGlobalString('PRODUCT_DISABLE_SELLBY')) ? --$colspan : $colspan;
851  $colspan = (getDolGlobalString('PRODUCT_DISABLE_EATBY')) ? --$colspan : $colspan;
852 
853  // Enable hooks to append additional columns
854  $parameters = array(
855  // allows hook to distinguish between the rows with information and the rows with dispatch form input
856  'is_information_row' => true,
857  'j' => $j,
858  'suffix' => $suffix,
859  'objd' => $objd,
860  );
861  $reshook = $hookmanager->executeHooks(
862  'printFieldListValue',
863  $parameters,
864  $object,
865  $action
866  );
867  if ($reshook < 0) {
868  setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
869  }
870  print $hookmanager->resPrint;
871 
872  print '</tr>';
873 
874  print '<!-- line no batch '.$numline.' -->';
875  print '<tr class="oddeven autoresettr" name="'.$type.$suffix.'" data-remove="clear">';
876  print '<td colspan="'.$colspan.'">';
877  print '<input id="fk_commandedet'.$suffix.'" name="fk_commandedet'.$suffix.'" type="hidden" value="'.$objp->rowid.'">';
878  print '<input id="idline'.$suffix.'" name="idline'.$suffix.'" type="hidden" value="'.$objd->rowid.'">';
879  print '<input name="product'.$suffix.'" type="hidden" value="'.$objd->fk_product.'">';
880  print '<!-- This is a up (may include discount or not depending on STOCK_EXCLUDE_DISCOUNT_FOR_PMP. will be used for PMP calculation) -->';
881  print '<input class="maxwidth75" name="pu'.$suffix.'" type="hidden" value="'.price2num($up_ht_disc, 'MU').'">';
882  print '</td>';
883  }
884  // Qty to dispatch
885  print '<td class="right nowraponall">';
886  print '<a href="" id="reset'.$suffix.'" class="resetline">'.img_picto($langs->trans("Reset"), 'eraser', 'class="pictofixedwidth opacitymedium"').'</a>';
887  $suggestedvalue = (GETPOSTISSET('qty'.$suffix) ? GETPOSTINT('qty'.$suffix) : $objd->qty);
888  //var_dump($suggestedvalue);exit;
889  print '<input id="qty'.$suffix.'" onchange="onChangeDispatchLineQty($(this))" name="qty'.$suffix.'" data-type="'.$type.'" data-index="'.$i.'" class="width50 right qtydispatchinput" value="'.$suggestedvalue.'" data-expected="'.$objd->qty.'">';
890  print '</td>';
891  print '<td>';
892  if (isModEnabled('productbatch') && $objp->tobatch > 0) {
893  $type = 'batch';
894  print img_picto($langs->trans('AddStockLocationLine'), 'split.png', 'class="splitbutton" '.($numd != $j + 1 ? 'style="display:none"' : '').' onClick="addDispatchLine('.$i.', \''.$type.'\')"');
895  } else {
896  $type = 'dispatch';
897  print img_picto($langs->trans('AddStockLocationLine'), 'split.png', 'class="splitbutton" '.($numd != $j + 1 ? 'style="display:none"' : '').' onClick="addDispatchLine('.$i.', \''.$type.'\')"');
898  }
899 
900  print '</td>';
901 
902  // Warehouse
903  print '<td class="right">';
904  if (count($listwarehouses) > 1) {
905  print $formproduct->selectWarehouses(GETPOST("entrepot".$suffix) ? GETPOST("entrepot".$suffix) : $objd->fk_entrepot, "entrepot".$suffix, '', 1, 0, $objp->fk_product, '', 1, 0, null, 'csswarehouse'.$suffix);
906  } elseif (count($listwarehouses) == 1) {
907  print $formproduct->selectWarehouses(GETPOST("entrepot".$suffix) ? GETPOST("entrepot".$suffix) : $objd->fk_entrepot, "entrepot".$suffix, '', 0, 0, $objp->fk_product, '', 1, 0, null, 'csswarehouse'.$suffix);
908  } else {
909  $langs->load("errors");
910  print $langs->trans("ErrorNoWarehouseDefined");
911  }
912  print "</td>\n";
913 
914  // Enable hooks to append additional columns
915  $parameters = array(
916  'is_information_row' => false, // this is a dispatch form row
917  'i' => $i,
918  'suffix' => $suffix,
919  'objp' => $objp,
920  );
921  $reshook = $hookmanager->executeHooks(
922  'printFieldListValue',
923  $parameters,
924  $object,
925  $action
926  );
927  if ($reshook < 0) {
928  setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
929  }
930  print $hookmanager->resPrint;
931 
932  print "</tr>\n";
933  $j++;
934 
935  $numline++;
936  }
937  $suffix = "_".$j."_".$i;
938  }
939 
940  if ($j == 0) {
941  if (isModEnabled('productbatch') && !empty($objp->tobatch)) {
942  $type = 'batch';
943 
944  // Enable hooks to append additional columns
945  $parameters = array(
946  // allows hook to distinguish between the rows with information and the rows with dispatch form input
947  'is_information_row' => true,
948  'j' => $j,
949  'suffix' => $suffix,
950  'objp' => $objp,
951  );
952  $reshook = $hookmanager->executeHooks(
953  'printFieldListValue',
954  $parameters,
955  $object,
956  $action
957  );
958  if ($reshook < 0) {
959  setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
960  }
961  print $hookmanager->resPrint;
962 
963  print '</tr>';
964 
965  print '<!-- line for batch '.$numline.' (not dispatched line yet for this order line) -->';
966  print '<tr class="oddeven autoresettr" name="'.$type.$suffix.'" data-remove="clear">';
967  print '<td>';
968  print '<input id="fk_commandedet'.$suffix.'" name="fk_commandedet'.$suffix.'" type="hidden" value="'.$objp->rowid.'">';
969  print '<input id="idline'.$suffix.'" name="idline'.$suffix.'" type="hidden" value="-1">';
970  print '<input name="product_batch'.$suffix.'" type="hidden" value="'.$objp->fk_product.'">';
971 
972  print '<!-- This is a up (may include discount or not depending on STOCK_EXCLUDE_DISCOUNT_FOR_PMP. will be used for PMP calculation) -->';
973  print '<input class="maxwidth75" name="pu'.$suffix.'" type="hidden" value="'.price2num($up_ht_disc, 'MU').'">';
974  print '</td>';
975 
976  print '<td>';
977  print '<input type="text" class="inputlotnumber quatrevingtquinzepercent" id="lot_number'.$suffix.'" name="lot_number'.$suffix.'" value="'.GETPOST('lot_number'.$suffix).'">';
978  print '</td>';
979  if (!getDolGlobalString('PRODUCT_DISABLE_SELLBY')) {
980  print '<td class="nowraponall">';
981  $dlcdatesuffix = dol_mktime(0, 0, 0, GETPOST('dlc'.$suffix.'month'), GETPOST('dlc'.$suffix.'day'), GETPOST('dlc'.$suffix.'year'));
982  print $form->selectDate($dlcdatesuffix, 'dlc'.$suffix, 0, 0, 1, '');
983  print '</td>';
984  }
985  if (!getDolGlobalString('PRODUCT_DISABLE_EATBY')) {
986  print '<td class="nowraponall">';
987  $dluodatesuffix = dol_mktime(0, 0, 0, GETPOST('dluo'.$suffix.'month'), GETPOST('dluo'.$suffix.'day'), GETPOST('dluo'.$suffix.'year'));
988  print $form->selectDate($dluodatesuffix, 'dluo'.$suffix, 0, 0, 1, '');
989  print '</td>';
990  }
991  print '<td colspan="2">&nbsp;</td>'; // Supplier ref + Qty ordered + qty already dispatched
992  } else {
993  $type = 'dispatch';
994  $colspan = 6;
995  $colspan = (getDolGlobalString('PRODUCT_DISABLE_SELLBY')) ? --$colspan : $colspan;
996  $colspan = (getDolGlobalString('PRODUCT_DISABLE_EATBY')) ? --$colspan : $colspan;
997 
998  // Enable hooks to append additional columns
999  $parameters = array(
1000  // allows hook to distinguish between the rows with information and the rows with dispatch form input
1001  'is_information_row' => true,
1002  'j' => $j,
1003  'suffix' => $suffix,
1004  'objp' => $objp,
1005  );
1006  $reshook = $hookmanager->executeHooks(
1007  'printFieldListValue',
1008  $parameters,
1009  $object,
1010  $action
1011  );
1012  if ($reshook < 0) {
1013  setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
1014  }
1015  print $hookmanager->resPrint;
1016 
1017  print '</tr>';
1018 
1019  print '<!-- line no batch '.$numline.' (not dispatched line yet for this order line) -->';
1020  print '<tr class="oddeven autoresettr" name="'.$type.$suffix.'" data-remove="clear">';
1021  print '<td colspan="'.$colspan.'">';
1022  print '<input id="fk_commandedet'.$suffix.'" name="fk_commandedet'.$suffix.'" type="hidden" value="'.$objp->rowid.'">';
1023  print '<input id="idline'.$suffix.'" name="idline'.$suffix.'" type="hidden" value="-1">';
1024  print '<input name="product'.$suffix.'" type="hidden" value="'.$objp->fk_product.'">';
1025 
1026  print '<!-- This is a up (may include discount or not depending on STOCK_EXCLUDE_DISCOUNT_FOR_PMP. will be used for PMP calculation) -->';
1027  print '<input class="maxwidth75" name="pu'.$suffix.'" type="hidden" value="'.price2num($up_ht_disc, 'MU').'">';
1028  print '</td>';
1029  }
1030  // Qty to dispatch
1031  print '<td class="right">';
1032  print '<a href="" id="reset'.$suffix.'" class="resetline">'.img_picto($langs->trans("Reset"), 'eraser', 'class="pictofixedwidth opacitymedium"').'</a>';
1033  $amounttosuggest = (GETPOSTISSET('qty'.$suffix) ? GETPOSTINT('qty'.$suffix) : (!getDolGlobalString('SUPPLIER_ORDER_DISPATCH_FORCE_QTY_INPUT_TO_ZERO') ? $remaintodispatch : 0));
1034  if (count($products_dispatched)) {
1035  // There is already existing lines into llx_expeditiondet, this means a plan for the shipment has already been started.
1036  // In such a case, we do not suggest new values, we suggest the value known.
1037  $amounttosuggest = (GETPOSTISSET('qty'.$suffix) ? GETPOSTINT('qty'.$suffix) : (isset($products_dispatched[$objp->rowid]) ? $products_dispatched[$objp->rowid] : ''));
1038  }
1039  print '<input id="qty'.$suffix.'" onchange="onChangeDispatchLineQty($(this))" name="qty'.$suffix.'" data-index="'.$i.'" data-type="text" class="width50 right qtydispatchinput" value="'.$amounttosuggest.'" data-expected="'.$amounttosuggest.'">';
1040  print '</td>';
1041  print '<td>';
1042  if (isModEnabled('productbatch') && $objp->tobatch > 0) {
1043  $type = 'batch';
1044  print img_picto($langs->trans('AddStockLocationLine'), 'split.png', 'class="splitbutton" onClick="addDispatchLine('.$i.', \''.$type.'\')"');
1045  } else {
1046  $type = 'dispatch';
1047  print img_picto($langs->trans('AddStockLocationLine'), 'split.png', 'class="splitbutton" onClick="addDispatchLine('.$i.', \''.$type.'\')"');
1048  }
1049 
1050  print '</td>';
1051 
1052  // Warehouse
1053  print '<td class="right">';
1054  if (count($listwarehouses) > 1) {
1055  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);
1056  } elseif (count($listwarehouses) == 1) {
1057  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);
1058  } else {
1059  $langs->load("errors");
1060  print $langs->trans("ErrorNoWarehouseDefined");
1061  }
1062  print "</td>\n";
1063 
1064  // Enable hooks to append additional columns
1065  $parameters = array(
1066  'is_information_row' => false, // this is a dispatch form row
1067  'i' => $i,
1068  'suffix' => $suffix,
1069  'objp' => $objp,
1070  );
1071  $reshook = $hookmanager->executeHooks(
1072  'printFieldListValue',
1073  $parameters,
1074  $object,
1075  $action
1076  );
1077  if ($reshook < 0) {
1078  setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
1079  }
1080  print $hookmanager->resPrint;
1081  print "</tr>\n";
1082  }
1083  }
1084  }
1085  $i++;
1086  }
1087  $db->free($resql);
1088  } else {
1089  dol_print_error($db);
1090  }
1091 
1092  print "</table>\n";
1093  print '</div>';
1094 
1095  if ($nbproduct) {
1096  //$checkboxlabel = $langs->trans("CloseReceivedSupplierOrdersAutomatically", $langs->transnoentitiesnoconv('StatusOrderReceivedAll'));
1097 
1098  print '<div class="center">';
1099  $parameters = array();
1100  $reshook = $hookmanager->executeHooks('addMoreActionsButtons', $parameters, $object, $action); // Note that $action and $object may have been
1101  // modified by hook
1102  if (empty($reshook)) {
1103  /*if (empty($conf->reception->enabled)) {
1104  print $langs->trans("Comment").' : ';
1105  print '<input type="text" class="minwidth400" maxlength="128" name="comment" value="';
1106  print GETPOSTISSET("comment") ? GETPOST("comment") : $langs->trans("DispatchSupplierOrder", $object->ref);
1107  // print ' / '.$object->ref_supplier; // Not yet available
1108  print '" class="flat"><br>';
1109 
1110  print '<input type="checkbox" checked="checked" name="closeopenorder"> '.$checkboxlabel;
1111  }
1112 
1113  $dispatchBt = empty($conf->reception->enabled) ? $langs->trans("Receive") : $langs->trans("CreateReception");
1114 
1115  print '<br>';
1116  */
1117 
1118  print '<input type="submit" id="submitform" class="button" name="dispatch" value="'.$langs->trans("Save").'"';
1119  $disabled = 0;
1120  if (!$usercancreate) {
1121  $disabled = 1;
1122  }
1123  if (count($listwarehouses) <= 0) {
1124  $disabled = 1;
1125  }
1126  if ($disabled) {
1127  print ' disabled';
1128  }
1129 
1130  print '>';
1131  }
1132  print '</div>';
1133  }
1134 
1135  // Message if nothing to dispatch
1136  if (!$nbproduct) {
1137  print "<br>\n";
1138  if (!getDolGlobalString('SUPPLIER_ORDER_DISABLE_STOCK_DISPATCH_WHEN_TOTAL_REACHED')) {
1139  print '<div class="opacitymedium">'.$langs->trans("NoPredefinedProductToDispatch").'</div>'; // No predefined line at all
1140  } else {
1141  print '<div class="opacitymedium">'.$langs->trans("NoMorePredefinedProductToDispatch").'</div>'; // No predefined line that remain to be dispatched.
1142  }
1143  }
1144 
1145  print '</form>';
1146  }
1147 
1148  print dol_get_fiche_end();
1149 
1150  // Popup for mass barcode scanning
1151  if ($action == 'updatebyscaning') {
1152  if ($permissiontoadd) {
1153  // Output the javascript to manage the scanner tool.
1154  print '<script>';
1155 
1156  print '
1157  var duplicatedbatchcode = [];
1158  var errortab1 = [];
1159  var errortab2 = [];
1160  var errortab3 = [];
1161  var errortab4 = [];
1162 
1163  function barcodescannerjs(){
1164  console.log("We catch inputs in scanner box");
1165  jQuery("#scantoolmessage").text();
1166 
1167  var selectaddorreplace = $("select[name=selectaddorreplace]").val();
1168  var barcodemode = $("input[name=barcodemode]:checked").val();
1169  var barcodeproductqty = $("input[name=barcodeproductqty]").val();
1170  var warehousetouse = $("select[name=warehousenew]").val();
1171  var textarea = $("textarea[name=barcodelist]").val();
1172  var textarray = textarea.split(/[\s,;]+/);
1173  var tabproduct = [];
1174  duplicatedbatchcode = [];
1175  errortab1 = [];
1176  errortab2 = [];
1177  errortab3 = [];
1178  errortab4 = [];
1179 
1180  textarray = textarray.filter(function(value){
1181  return value != "";
1182  });
1183  if(textarray.some((element) => element != "")){
1184  $(".qtydispatchinput").each(function(){
1185  id = $(this).attr(\'id\');
1186  idarray = id.split(\'_\');
1187  idproduct = idarray[2];
1188  id = idarray[1] + \'_\' + idarray[2];
1189  console.log("Analyze the line "+id+" in inventory, barcodemode="+barcodemode);
1190  warehouse = $("#entrepot_"+id).val();
1191  console.log(warehouse);
1192  productbarcode = $("#product_"+idproduct).attr(\'data-barcode\');
1193  console.log(productbarcode);
1194  productbatchcode = $("#lot_number_"+id).val();
1195  if(productbatchcode == undefined){
1196  productbatchcode = "";
1197  }
1198  console.log(productbatchcode);
1199 
1200  if (barcodemode != "barcodeforproduct") {
1201  tabproduct.forEach(product=>{
1202  console.log("product.Batch="+product.Batch+" productbatchcode="+productbatchcode);
1203  if(product.Batch != "" && product.Batch == productbatchcode){
1204  console.log("duplicate batch code found for batch code "+productbatchcode);
1205  duplicatedbatchcode.push(productbatchcode);
1206  }
1207  })
1208  }
1209  productinput = $("#qty_"+id).val();
1210  if(productinput == ""){
1211  productinput = 0
1212  }
1213  tabproduct.push({\'Id\':id,\'Warehouse\':warehouse,\'Barcode\':productbarcode,\'Batch\':productbatchcode,\'Qty\':productinput,\'fetched\':false});
1214  });
1215  console.log("Loop on each record entered in the textarea");
1216 
1217  textarray.forEach(function(element,index){
1218  console.log("Process record element="+element+" id="+id);
1219  var verify_batch = false;
1220  var verify_barcode = false;
1221  switch(barcodemode){
1222  case "barcodeforautodetect":
1223  verify_barcode = barcodeserialforproduct(tabproduct,index,element,barcodeproductqty,warehousetouse,selectaddorreplace,"barcode",true);
1224  verify_batch = barcodeserialforproduct(tabproduct,index,element,barcodeproductqty,warehousetouse,selectaddorreplace,"lotserial",true);
1225  break;
1226  case "barcodeforproduct":
1227  verify_barcode = barcodeserialforproduct(tabproduct,index,element,barcodeproductqty,warehousetouse,selectaddorreplace,"barcode");
1228  break;
1229  case "barcodeforlotserial":
1230  verify_batch = barcodeserialforproduct(tabproduct,index,element,barcodeproductqty,warehousetouse,selectaddorreplace,"lotserial");
1231  break;
1232  default:
1233  alert(\''.dol_escape_js($langs->trans("ErrorWrongBarcodemode")).' "\'+barcodemode+\'"\');
1234  throw \''.dol_escape_js($langs->trans('ErrorWrongBarcodemode')).' "\'+barcodemode+\'"\';
1235  }
1236 
1237  if (verify_batch == false && verify_barcode == false) { /* If the 2 flags are false, not found error */
1238  errortab2.push(element);
1239  } else if (verify_batch == true && verify_barcode == true) { /* If the 2 flags are true, error: we don t know which one to take */
1240  errortab3.push(element);
1241  } else if (verify_batch == true) {
1242  console.log("element="+element);
1243  console.log(duplicatedbatchcode);
1244  if (duplicatedbatchcode.includes(element)) {
1245  errortab1.push(element);
1246  }
1247  }
1248  });
1249 
1250  if (Object.keys(errortab1).length < 1 && Object.keys(errortab2).length < 1 && Object.keys(errortab3).length < 1) {
1251  tabproduct.forEach(product => {
1252  if(product.Qty!=0){
1253  if(product.hasOwnProperty("reelqty")){
1254  idprod = $("td[data-idproduct=\'"+product.fk_product+"\']").attr("id");
1255  idproduct = idprod.split("_")[1];
1256  console.log("We create a new line for product_"+idproduct);
1257  if(product.Barcode != null){
1258  modedispatch = "dispatch";
1259  } else {
1260  modedispatch = "batch";
1261  }
1262  addDispatchLine(idproduct,modedispatch);
1263  console.log($("tr[name^=\'"+modedispatch+"_\'][name$=\'_"+idproduct+"\']"));
1264  nbrTrs = $("tr[name^=\'"+modedispatch+"_\'][name$=\'_"+idproduct+"\']").length;
1265 
1266  $("#qty_"+(nbrTrs-1)+"_"+idproduct).val(product.Qty);
1267  $("#entrepot_"+(nbrTrs-1)+"_"+idproduct).val(product.Warehouse);
1268 
1269  if(modedispatch == "batch"){
1270  $("#lot_number_"+(nbrTrs-1)+"_"+idproduct).val(product.Batch);
1271  }
1272 
1273  } else {
1274  console.log("We change #qty_"+product.Id +" to match input in scanner box");
1275  $("#qty_"+product.Id).val(product.Qty);
1276  }
1277  }
1278  });
1279  jQuery("#scantoolmessage").text("'.dol_escape_js($langs->transnoentities("QtyWasAddedToTheScannedBarcode")).'\n");
1280  /* document.forms["formrecord"].submit(); */
1281  } else {
1282  let stringerror = "";
1283  if (Object.keys(errortab1).length > 0) {
1284  stringerror += "<br>'.dol_escape_js($langs->transnoentities('ErrorSameBatchNumber')).': ";
1285  errortab1.forEach(element => {
1286  stringerror += (element + ", ")
1287  });
1288  stringerror = stringerror.slice(0, -2); /* Remove last ", " */
1289  }
1290  if (Object.keys(errortab2).length > 0) {
1291  stringerror += "<br>'.dol_escape_js($langs->transnoentities('ErrorCantFindCodeInInventory')).': ";
1292  errortab2.forEach(element => {
1293  stringerror += (element + ", ")
1294  });
1295  stringerror = stringerror.slice(0, -2); /* Remove last ", " */
1296  }
1297  if (Object.keys(errortab3).length > 0) {
1298  stringerror += "<br>'.dol_escape_js($langs->transnoentities('ErrorCodeScannedIsBothProductAndSerial')).': ";
1299  errortab3.forEach(element => {
1300  stringerror += (element + ", ")
1301  });
1302  stringerror = stringerror.slice(0, -2); /* Remove last ", " */
1303  }
1304  if (Object.keys(errortab4).length > 0) {
1305  stringerror += "<br>'.dol_escape_js($langs->transnoentities('ErrorBarcodeNotFoundForProductWarehouse')).': ";
1306  errortab4.forEach(element => {
1307  stringerror += (element + ", ")
1308  });
1309  stringerror = stringerror.slice(0, -2); /* Remove last ", " */
1310  }
1311 
1312  jQuery("#scantoolmessage").html(\''.dol_escape_js($langs->transnoentities("ErrorOnElementsInventory")).'\' + stringerror);
1313  //alert("'.dol_escape_js($langs->trans("ErrorOnElementsInventory")).' :\n" + stringerror);
1314  }
1315  }
1316 
1317  }
1318 
1319  /* This methode is called by parent barcodescannerjs() */
1320  function barcodeserialforproduct(tabproduct,index,element,barcodeproductqty,warehousetouse,selectaddorreplace,mode,autodetect=false){
1321  BarcodeIsInProduct=0;
1322  newproductrow=0
1323  result=false;
1324  tabproduct.forEach(product => {
1325  $.ajax({ url: \''.DOL_URL_ROOT.'/expedition/ajax/searchfrombarcode.php\',
1326  data: { "token":"'.newToken().'", "action":"existbarcode","fk_entrepot": warehousetouse, "barcode":element, "mode":mode},
1327  type: \'POST\',
1328  async: false,
1329  success: function(response) {
1330  if (response.status == "success"){
1331  console.log(response.message);
1332  if(!newproductrow){
1333  newproductrow = response.object;
1334  }
1335  }else{
1336  if (mode!="lotserial" && autodetect==false && !errortab4.includes(element)){
1337  errortab4.push(element);
1338  console.error(response.message);
1339  }
1340  }
1341  },
1342  error : function(output) {
1343  console.error("Error on barcodeserialforproduct function");
1344  },
1345  });
1346  console.log("Product "+(index+=1)+": "+element);
1347  if(mode == "barcode"){
1348  testonproduct = product.Barcode
1349  }else if (mode == "lotserial"){
1350  testonproduct = product.Batch
1351  }
1352  testonwarehouse = product.Warehouse;
1353  if(testonproduct == element && testonwarehouse == warehousetouse){
1354  if(selectaddorreplace == "add"){
1355  productqty = parseInt(product.Qty,10);
1356  product.Qty = productqty + parseInt(barcodeproductqty,10);
1357  }else if(selectaddorreplace == "replace"){
1358  if(product.fetched == false){
1359  product.Qty = barcodeproductqty
1360  product.fetched=true
1361  }else{
1362  productqty = parseInt(product.Qty,10);
1363  product.Qty = productqty + parseInt(barcodeproductqty,10);
1364  }
1365  }
1366  BarcodeIsInProduct+=1;
1367  }
1368  })
1369  if(BarcodeIsInProduct==0 && newproductrow!=0){
1370  tabproduct.push({\'Id\':tabproduct.length-1,\'Warehouse\':newproductrow.fk_warehouse,\'Barcode\':mode=="barcode"?element:null,\'Batch\':mode=="lotserial"?element:null,\'Qty\':barcodeproductqty,\'fetched\':true,\'reelqty\':newproductrow.reelqty,\'fk_product\':newproductrow.fk_product,\'mode\':mode});
1371  result = true;
1372  }
1373  if(BarcodeIsInProduct > 0){
1374  result = true;
1375  }
1376  return result;
1377  }
1378  ';
1379  print '</script>';
1380  }
1381  include DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php';
1382  $formother = new FormOther($db);
1383  print $formother->getHTMLScannerForm("barcodescannerjs", 'all', 1);
1384  }
1385 
1386  // traitement entrepot par défaut
1387  print '<script type="text/javascript">
1388  $(document).ready(function () {
1389  $("select[name=fk_default_warehouse]").change(function() {
1390  console.log("warehouse is modified");
1391  var fk_default_warehouse = $("option:selected", this).val();
1392  $("select[name^=entrepot_]").val(fk_default_warehouse).change();
1393  });
1394 
1395  $("#autoreset").click(function() {
1396  console.log("we click on autoreset");
1397  $(".autoresettr").each(function(){
1398  id = $(this).attr("name");
1399  idtab = id.split("_");
1400  console.log("we process line "+id+" "+idtab);
1401  if ($(this).data("remove") == "clear") { /* data-remove=clear means that line qty must be cleared but line must not be removed */
1402  console.log("We clear the object to expected value")
1403  $("#qty_"+idtab[1]+"_"+idtab[2]).val("");
1404  /*
1405  qtyexpected = $("#qty_"+idtab[1]+"_"+idtab[2]).data("expected")
1406  console.log(qtyexpected);
1407  $("#qty_"+idtab[1]+"_"+idtab[2]).val(qtyexpected);
1408  qtydispatched = $("#qty_dispatched_0_"+idtab[2]).data("dispatched")
1409  $("#qty_dispatched_0_"+idtab[2]).val(qtydispatched);
1410  */
1411  } else { /* data-remove=remove means that line must be removed */
1412  console.log("We remove the object")
1413  $(this).remove();
1414  $("tr[name^=\'"+idtab[0]+"_\'][name$=\'_"+idtab[2]+"\']:last .splitbutton").show();
1415  }
1416  });
1417  return false;
1418  });
1419 
1420  $("#resetalltoexpected").click(function(){
1421  $(".qtydispatchinput").each(function(){
1422  console.log("We reset to expected "+$(this).attr("id")+" qty to dispatch");
1423  $(this).val($(this).data("expected"));
1424  });
1425  return false;
1426  });
1427 
1428  $(".resetline").on("click", function(event) {
1429  event.preventDefault();
1430  id = $(this).attr("id");
1431  id = id.split("reset_");
1432  console.log("Reset trigger for id = qty_"+id[1]);
1433  $("#qty_"+id[1]).val("");
1434  });
1435  });
1436  </script>';
1437 }
1438 
1439 // End of page
1440 llxFooter();
1441 $db->close();
if($user->socid > 0) if(! $user->hasRight('accounting', 'chartofaccount')) $object
Definition: card.php:58
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 customers orders.
Class to manage comment.
Class to manage warehouses.
Class to manage shipments.
const STATUS_DRAFT
Draft status.
Class to manage lines of shipment.
CRUD class for batch number management within shipment.
Class to manage generation of HTML components Only common components must be here.
Class permettant la generation de composants html autre Only common components are 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 proposals.
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:744
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:426
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 '.
currentToken()
Return the value of token currently saved into session with name 'token'.
dol_now($mode='auto')
Return date for now.
dol_escape_js($stringtoescape, $mode=0, $noescapebackslashn=0)
Returns text escaped for inclusion into javascript code.
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.
GETPOSTFLOAT($paramname, $rounding='')
Return the value of a $_GET or $_POST supervariable, converted into float.
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='', $noduplicate=0)
Set event messages in dol_events session object.
dol_print_error($db=null, $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
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:886
div float
Buy price without taxes.
Definition: style.css.php:959
$conf db name
Only used if Module[ID]Name translation string is not found.
Definition: repair.php:125
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.
shipping_prepare_head($object)
Prepare array with list of tabs.
print *****$script_file(".$version.") pid code
1: frais de port 2: ecotaxe 3: option line (when qty = 0)