dolibarr 20.0.5
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
34require '../main.inc.php';
35require_once DOL_DOCUMENT_ROOT.'/core/modules/supplier_order/modules_commandefournisseur.php';
36require_once DOL_DOCUMENT_ROOT.'/product/stock/class/entrepot.class.php';
37require_once DOL_DOCUMENT_ROOT.'/core/lib/fourn.lib.php';
38require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.commande.class.php';
39require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.commande.dispatch.class.php';
40require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php';
41require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
42require_once DOL_DOCUMENT_ROOT.'/core/lib/sendings.lib.php';
43if (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
50if (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
66if ($user->socid) {
67 $socid = $user->socid;
68}
69
70$hookmanager->initHooks(array('expeditiondispatch'));
71
72// Recuperation de l'id de projet
73$projectid = 0;
74if (GETPOSTISSET("projectid")) {
75 $projectid = GETPOSTINT("projectid");
76}
77
78$object = new Expedition($db);
79$objectorder = new Commande($db);
80
81
82if ($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
102if (!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
116if ($reshook < 0) {
117 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
118}
119
120// Update a dispatched line
121if ($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("ShipmentUpdated"), 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
380llxHeader('', $title, $help_url, '', 0, 0, $morejs);
381
382if ($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
401 $head = shipping_prepare_head($object);
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";
777 $sql .= ", cd.fk_product";
778 $sql .= ", ".$db->ifsql('eb.rowid IS NULL', 'ed.qty', 'eb.qty')." as qty";
779 $sql .= ", ed.fk_entrepot";
780 $sql .= ", eb.batch, eb.eatby, eb.sellby";
781 $sql .= " FROM ".$db->prefix()."expeditiondet as ed";
782 $sql .= " LEFT JOIN ".$db->prefix()."expeditiondet_batch as eb on ed.rowid = eb.fk_expeditiondet";
783 $sql .= " INNER JOIN ".$db->prefix()."commandedet as cd on ed.fk_origin_line = cd.rowid";
784 $sql .= " WHERE ed.fk_origin_line = ".(int) $objp->rowid;
785 $sql .= " AND ed.fk_expedition = ".(int) $object->id;
786 $sql .= " ORDER BY ed.rowid, ed.fk_elementdet";
787
788 $resultsql = $db->query($sql);
789 $j = 0;
790 if ($resultsql) {
791 $numd = $db->num_rows($resultsql);
792
793 while ($j < $numd) {
794 $suffix = "_".$j."_".$i;
795 $objd = $db->fetch_object($resultsql);
796
797 if (isModEnabled('productbatch') && (!empty($objd->batch) || (is_null($objd->batch) && $tmpproduct->status_batch > 0))) {
798 $type = 'batch';
799
800 // Enable hooks to append additional columns
801 $parameters = array(
802 // allows hook to distinguish between the rows with information and the rows with dispatch form input
803 'is_information_row' => true,
804 'j' => $j,
805 'suffix' => $suffix,
806 'objd' => $objd,
807 );
808 $reshook = $hookmanager->executeHooks(
809 'printFieldListValue',
810 $parameters,
811 $object,
812 $action
813 );
814 if ($reshook < 0) {
815 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
816 }
817 print $hookmanager->resPrint;
818
819 print '</tr>';
820
821 print '<!-- line for batch '.$numline.' -->';
822 print '<tr class="oddeven autoresettr" name="'.$type.$suffix.'" data-remove="clear">';
823 print '<td>';
824 print '<input id="fk_commandedet'.$suffix.'" name="fk_commandedet'.$suffix.'" type="hidden" value="'.$objp->rowid.'">';
825 print '<input id="idline'.$suffix.'" name="idline'.$suffix.'" type="hidden" value="'.$objd->rowid.'">';
826 print '<input name="product_batch'.$suffix.'" type="hidden" value="'.$objd->fk_product.'">';
827
828 print '<!-- This is a U.P. (may include discount or not depending on STOCK_EXCLUDE_DISCOUNT_FOR_PMP. will be used for PMP calculation) -->';
829 print '<input class="maxwidth75" name="pu'.$suffix.'" type="hidden" value="'.price2num($up_ht_disc, 'MU').'">';
830
831 print '</td>';
832
833 print '<td>';
834 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).'">';
835 //print '<input type="hidden" id="lot_number'.$suffix.'" name="lot_number'.$suffix.'" value="'.$objd->batch.'">';
836 print '</td>';
837 if (!getDolGlobalString('PRODUCT_DISABLE_SELLBY')) {
838 print '<td class="nowraponall">';
839 $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'));
840 print $form->selectDate($dlcdatesuffix, 'dlc'.$suffix, 0, 0, 1, '');
841 print '</td>';
842 }
843 if (!getDolGlobalString('PRODUCT_DISABLE_EATBY')) {
844 print '<td class="nowraponall">';
845 $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'));
846 print $form->selectDate($dluodatesuffix, 'dluo'.$suffix, 0, 0, 1, '');
847 print '</td>';
848 }
849 print '<td colspan="2">&nbsp;</td>'; // Supplier ref + Qty ordered + qty already dispatched
850 } else {
851 $type = 'dispatch';
852 $colspan = 6;
853 $colspan = (getDolGlobalString('PRODUCT_DISABLE_SELLBY')) ? --$colspan : $colspan;
854 $colspan = (getDolGlobalString('PRODUCT_DISABLE_EATBY')) ? --$colspan : $colspan;
855
856 // Enable hooks to append additional columns
857 $parameters = array(
858 // allows hook to distinguish between the rows with information and the rows with dispatch form input
859 'is_information_row' => true,
860 'j' => $j,
861 'suffix' => $suffix,
862 'objd' => $objd,
863 );
864 $reshook = $hookmanager->executeHooks(
865 'printFieldListValue',
866 $parameters,
867 $object,
868 $action
869 );
870 if ($reshook < 0) {
871 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
872 }
873 print $hookmanager->resPrint;
874
875 print '</tr>';
876
877 print '<!-- line no batch '.$numline.' -->';
878 print '<tr class="oddeven autoresettr" name="'.$type.$suffix.'" data-remove="clear">';
879 print '<td colspan="'.$colspan.'">';
880 print '<input id="fk_commandedet'.$suffix.'" name="fk_commandedet'.$suffix.'" type="hidden" value="'.$objp->rowid.'">';
881 print '<input id="idline'.$suffix.'" name="idline'.$suffix.'" type="hidden" value="'.$objd->rowid.'">';
882 print '<input name="product'.$suffix.'" type="hidden" value="'.$objd->fk_product.'">';
883 print '<!-- This is a up (may include discount or not depending on STOCK_EXCLUDE_DISCOUNT_FOR_PMP. will be used for PMP calculation) -->';
884 print '<input class="maxwidth75" name="pu'.$suffix.'" type="hidden" value="'.price2num($up_ht_disc, 'MU').'">';
885 print '</td>';
886 }
887 // Qty to dispatch
888 print '<td class="right nowraponall">';
889 print '<a href="" id="reset'.$suffix.'" class="resetline">'.img_picto($langs->trans("Reset"), 'eraser', 'class="pictofixedwidth opacitymedium"').'</a>';
890 $suggestedvalue = (GETPOSTISSET('qty'.$suffix) ? GETPOSTINT('qty'.$suffix) : $objd->qty);
891 //var_dump($suggestedvalue);exit;
892 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.'">';
893 print '</td>';
894 print '<td>';
895 if (isModEnabled('productbatch') && $objp->tobatch > 0) {
896 $type = 'batch';
897 print img_picto($langs->trans('AddStockLocationLine'), 'split.png', 'class="splitbutton" '.($numd != $j + 1 ? 'style="display:none"' : '').' onClick="addDispatchLine('.$i.', \''.$type.'\')"');
898 } else {
899 $type = 'dispatch';
900 print img_picto($langs->trans('AddStockLocationLine'), 'split.png', 'class="splitbutton" '.($numd != $j + 1 ? 'style="display:none"' : '').' onClick="addDispatchLine('.$i.', \''.$type.'\')"');
901 }
902
903 print '</td>';
904
905 // Warehouse
906 print '<td class="right">';
907 if (count($listwarehouses) > 1) {
908 print $formproduct->selectWarehouses(GETPOST("entrepot".$suffix) ? GETPOST("entrepot".$suffix) : $objd->fk_entrepot, "entrepot".$suffix, '', 1, 0, $objp->fk_product, '', 1, 0, null, 'csswarehouse'.$suffix);
909 } elseif (count($listwarehouses) == 1) {
910 print $formproduct->selectWarehouses(GETPOST("entrepot".$suffix) ? GETPOST("entrepot".$suffix) : $objd->fk_entrepot, "entrepot".$suffix, '', 0, 0, $objp->fk_product, '', 1, 0, null, 'csswarehouse'.$suffix);
911 } else {
912 $langs->load("errors");
913 print $langs->trans("ErrorNoWarehouseDefined");
914 }
915 print "</td>\n";
916
917 // Enable hooks to append additional columns
918 $parameters = array(
919 'is_information_row' => false, // this is a dispatch form row
920 'i' => $i,
921 'suffix' => $suffix,
922 'objp' => $objp,
923 );
924 $reshook = $hookmanager->executeHooks(
925 'printFieldListValue',
926 $parameters,
927 $object,
928 $action
929 );
930 if ($reshook < 0) {
931 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
932 }
933 print $hookmanager->resPrint;
934
935 print "</tr>\n";
936 $j++;
937
938 $numline++;
939 }
940 $suffix = "_".$j."_".$i;
941 }
942
943 if ($j == 0) {
944 if (isModEnabled('productbatch') && !empty($objp->tobatch)) {
945 $type = 'batch';
946
947 // Enable hooks to append additional columns
948 $parameters = array(
949 // allows hook to distinguish between the rows with information and the rows with dispatch form input
950 'is_information_row' => true,
951 'j' => $j,
952 'suffix' => $suffix,
953 'objp' => $objp,
954 );
955 $reshook = $hookmanager->executeHooks(
956 'printFieldListValue',
957 $parameters,
958 $object,
959 $action
960 );
961 if ($reshook < 0) {
962 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
963 }
964 print $hookmanager->resPrint;
965
966 print '</tr>';
967
968 print '<!-- line for batch '.$numline.' (not dispatched line yet for this order line) -->';
969 print '<tr class="oddeven autoresettr" name="'.$type.$suffix.'" data-remove="clear">';
970 print '<td>';
971 print '<input id="fk_commandedet'.$suffix.'" name="fk_commandedet'.$suffix.'" type="hidden" value="'.$objp->rowid.'">';
972 print '<input id="idline'.$suffix.'" name="idline'.$suffix.'" type="hidden" value="-1">';
973 print '<input name="product_batch'.$suffix.'" type="hidden" value="'.$objp->fk_product.'">';
974
975 print '<!-- This is a up (may include discount or not depending on STOCK_EXCLUDE_DISCOUNT_FOR_PMP. will be used for PMP calculation) -->';
976 print '<input class="maxwidth75" name="pu'.$suffix.'" type="hidden" value="'.price2num($up_ht_disc, 'MU').'">';
977 print '</td>';
978
979 print '<td>';
980 print '<input type="text" class="inputlotnumber quatrevingtquinzepercent" id="lot_number'.$suffix.'" name="lot_number'.$suffix.'" value="'.GETPOST('lot_number'.$suffix).'">';
981 print '</td>';
982 if (!getDolGlobalString('PRODUCT_DISABLE_SELLBY')) {
983 print '<td class="nowraponall">';
984 $dlcdatesuffix = dol_mktime(0, 0, 0, GETPOST('dlc'.$suffix.'month'), GETPOST('dlc'.$suffix.'day'), GETPOST('dlc'.$suffix.'year'));
985 print $form->selectDate($dlcdatesuffix, 'dlc'.$suffix, 0, 0, 1, '');
986 print '</td>';
987 }
988 if (!getDolGlobalString('PRODUCT_DISABLE_EATBY')) {
989 print '<td class="nowraponall">';
990 $dluodatesuffix = dol_mktime(0, 0, 0, GETPOST('dluo'.$suffix.'month'), GETPOST('dluo'.$suffix.'day'), GETPOST('dluo'.$suffix.'year'));
991 print $form->selectDate($dluodatesuffix, 'dluo'.$suffix, 0, 0, 1, '');
992 print '</td>';
993 }
994 print '<td colspan="2">&nbsp;</td>'; // Supplier ref + Qty ordered + qty already dispatched
995 } else {
996 $type = 'dispatch';
997 $colspan = 6;
998 $colspan = (getDolGlobalString('PRODUCT_DISABLE_SELLBY')) ? --$colspan : $colspan;
999 $colspan = (getDolGlobalString('PRODUCT_DISABLE_EATBY')) ? --$colspan : $colspan;
1000
1001 // Enable hooks to append additional columns
1002 $parameters = array(
1003 // allows hook to distinguish between the rows with information and the rows with dispatch form input
1004 'is_information_row' => true,
1005 'j' => $j,
1006 'suffix' => $suffix,
1007 'objp' => $objp,
1008 );
1009 $reshook = $hookmanager->executeHooks(
1010 'printFieldListValue',
1011 $parameters,
1012 $object,
1013 $action
1014 );
1015 if ($reshook < 0) {
1016 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
1017 }
1018 print $hookmanager->resPrint;
1019
1020 print '</tr>';
1021
1022 print '<!-- line no batch '.$numline.' (not dispatched line yet for this order line) -->';
1023 print '<tr class="oddeven autoresettr" name="'.$type.$suffix.'" data-remove="clear">';
1024 print '<td colspan="'.$colspan.'">';
1025 print '<input id="fk_commandedet'.$suffix.'" name="fk_commandedet'.$suffix.'" type="hidden" value="'.$objp->rowid.'">';
1026 print '<input id="idline'.$suffix.'" name="idline'.$suffix.'" type="hidden" value="-1">';
1027 print '<input name="product'.$suffix.'" type="hidden" value="'.$objp->fk_product.'">';
1028
1029 print '<!-- This is a up (may include discount or not depending on STOCK_EXCLUDE_DISCOUNT_FOR_PMP. will be used for PMP calculation) -->';
1030 print '<input class="maxwidth75" name="pu'.$suffix.'" type="hidden" value="'.price2num($up_ht_disc, 'MU').'">';
1031 print '</td>';
1032 }
1033 // Qty to dispatch
1034 print '<td class="right">';
1035 print '<a href="" id="reset'.$suffix.'" class="resetline">'.img_picto($langs->trans("Reset"), 'eraser', 'class="pictofixedwidth opacitymedium"').'</a>';
1036 $amounttosuggest = (GETPOSTISSET('qty'.$suffix) ? GETPOSTINT('qty'.$suffix) : (!getDolGlobalString('SUPPLIER_ORDER_DISPATCH_FORCE_QTY_INPUT_TO_ZERO') ? $remaintodispatch : 0));
1037 if (count($products_dispatched)) {
1038 // There is already existing lines into llx_expeditiondet, this means a plan for the shipment has already been started.
1039 // In such a case, we do not suggest new values, we suggest the value known.
1040 $amounttosuggest = (GETPOSTISSET('qty'.$suffix) ? GETPOSTINT('qty'.$suffix) : (isset($products_dispatched[$objp->rowid]) ? $products_dispatched[$objp->rowid] : ''));
1041 }
1042 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.'">';
1043 print '</td>';
1044 print '<td>';
1045 if (isModEnabled('productbatch') && $objp->tobatch > 0) {
1046 $type = 'batch';
1047 print img_picto($langs->trans('AddStockLocationLine'), 'split.png', 'class="splitbutton" onClick="addDispatchLine('.$i.', \''.$type.'\')"');
1048 } else {
1049 $type = 'dispatch';
1050 print img_picto($langs->trans('AddStockLocationLine'), 'split.png', 'class="splitbutton" onClick="addDispatchLine('.$i.', \''.$type.'\')"');
1051 }
1052
1053 print '</td>';
1054
1055 // Warehouse
1056 print '<td class="right">';
1057 if (count($listwarehouses) > 1) {
1058 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);
1059 } elseif (count($listwarehouses) == 1) {
1060 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);
1061 } else {
1062 $langs->load("errors");
1063 print $langs->trans("ErrorNoWarehouseDefined");
1064 }
1065 print "</td>\n";
1066
1067 // Enable hooks to append additional columns
1068 $parameters = array(
1069 'is_information_row' => false, // this is a dispatch form row
1070 'i' => $i,
1071 'suffix' => $suffix,
1072 'objp' => $objp,
1073 );
1074 $reshook = $hookmanager->executeHooks(
1075 'printFieldListValue',
1076 $parameters,
1077 $object,
1078 $action
1079 );
1080 if ($reshook < 0) {
1081 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
1082 }
1083 print $hookmanager->resPrint;
1084 print "</tr>\n";
1085 }
1086 }
1087 }
1088 $i++;
1089 }
1090 $db->free($resql);
1091 } else {
1092 dol_print_error($db);
1093 }
1094
1095 print "</table>\n";
1096 print '</div>';
1097
1098 if ($nbproduct) {
1099 //$checkboxlabel = $langs->trans("CloseReceivedSupplierOrdersAutomatically", $langs->transnoentitiesnoconv('StatusOrderReceivedAll'));
1100
1101 print '<div class="center">';
1102 $parameters = array();
1103 $reshook = $hookmanager->executeHooks('addMoreActionsButtons', $parameters, $object, $action); // Note that $action and $object may have been
1104 // modified by hook
1105 if (empty($reshook)) {
1106 /*if (empty($conf->reception->enabled)) {
1107 print $langs->trans("Comment").' : ';
1108 print '<input type="text" class="minwidth400" maxlength="128" name="comment" value="';
1109 print GETPOSTISSET("comment") ? GETPOST("comment") : $langs->trans("DispatchSupplierOrder", $object->ref);
1110 // print ' / '.$object->ref_supplier; // Not yet available
1111 print '" class="flat"><br>';
1112
1113 print '<input type="checkbox" checked="checked" name="closeopenorder"> '.$checkboxlabel;
1114 }
1115
1116 $dispatchBt = empty($conf->reception->enabled) ? $langs->trans("Receive") : $langs->trans("CreateReception");
1117
1118 print '<br>';
1119 */
1120
1121 print '<input type="submit" id="submitform" class="button" name="dispatch" value="'.$langs->trans("Save").'"';
1122 $disabled = 0;
1123 if (!$usercancreate) {
1124 $disabled = 1;
1125 }
1126 if (count($listwarehouses) <= 0) {
1127 $disabled = 1;
1128 }
1129 if ($disabled) {
1130 print ' disabled';
1131 }
1132
1133 print '>';
1134 }
1135 print '</div>';
1136 }
1137
1138 // Message if nothing to dispatch
1139 if (!$nbproduct) {
1140 print "<br>\n";
1141 if (!getDolGlobalString('SUPPLIER_ORDER_DISABLE_STOCK_DISPATCH_WHEN_TOTAL_REACHED')) {
1142 print '<div class="opacitymedium">'.$langs->trans("NoPredefinedProductToDispatch").'</div>'; // No predefined line at all
1143 } else {
1144 print '<div class="opacitymedium">'.$langs->trans("NoMorePredefinedProductToDispatch").'</div>'; // No predefined line that remain to be dispatched.
1145 }
1146 }
1147
1148 print '</form>';
1149 }
1150
1151 print dol_get_fiche_end();
1152
1153 // Popup for mass barcode scanning
1154 if ($action == 'updatebyscaning') {
1155 if ($permissiontoadd) {
1156 // Output the javascript to manage the scanner tool.
1157 print '<script>';
1158
1159 print '
1160 var duplicatedbatchcode = [];
1161 var errortab1 = [];
1162 var errortab2 = [];
1163 var errortab3 = [];
1164 var errortab4 = [];
1165
1166 function barcodescannerjs(){
1167 console.log("We catch inputs in scanner box");
1168 jQuery("#scantoolmessage").text();
1169
1170 var selectaddorreplace = $("select[name=selectaddorreplace]").val();
1171 var barcodemode = $("input[name=barcodemode]:checked").val();
1172 var barcodeproductqty = $("input[name=barcodeproductqty]").val();
1173 var warehousetouse = $("select[name=warehousenew]").val();
1174 var textarea = $("textarea[name=barcodelist]").val();
1175 var textarray = textarea.split(/[\s,;]+/);
1176 var tabproduct = [];
1177 duplicatedbatchcode = [];
1178 errortab1 = [];
1179 errortab2 = [];
1180 errortab3 = [];
1181 errortab4 = [];
1182
1183 textarray = textarray.filter(function(value){
1184 return value != "";
1185 });
1186 if(textarray.some((element) => element != "")){
1187 $(".qtydispatchinput").each(function(){
1188 id = $(this).attr(\'id\');
1189 idarray = id.split(\'_\');
1190 idproduct = idarray[2];
1191 id = idarray[1] + \'_\' + idarray[2];
1192 console.log("Analyze the line "+id+" in inventory, barcodemode="+barcodemode);
1193 warehouse = $("#entrepot_"+id).val();
1194 console.log(warehouse);
1195 productbarcode = $("#product_"+idproduct).attr(\'data-barcode\');
1196 console.log(productbarcode);
1197 productbatchcode = $("#lot_number_"+id).val();
1198 if(productbatchcode == undefined){
1199 productbatchcode = "";
1200 }
1201 console.log(productbatchcode);
1202
1203 if (barcodemode != "barcodeforproduct") {
1204 tabproduct.forEach(product=>{
1205 console.log("product.Batch="+product.Batch+" productbatchcode="+productbatchcode);
1206 if(product.Batch != "" && product.Batch == productbatchcode){
1207 console.log("duplicate batch code found for batch code "+productbatchcode);
1208 duplicatedbatchcode.push(productbatchcode);
1209 }
1210 })
1211 }
1212 productinput = $("#qty_"+id).val();
1213 if(productinput == ""){
1214 productinput = 0
1215 }
1216 tabproduct.push({\'Id\':id,\'Warehouse\':warehouse,\'Barcode\':productbarcode,\'Batch\':productbatchcode,\'Qty\':productinput,\'fetched\':false});
1217 });
1218 console.log("Loop on each record entered in the textarea");
1219
1220 textarray.forEach(function(element,index){
1221 console.log("Process record element="+element+" id="+id);
1222 var verify_batch = false;
1223 var verify_barcode = false;
1224 switch(barcodemode){
1225 case "barcodeforautodetect":
1226 verify_barcode = barcodeserialforproduct(tabproduct,index,element,barcodeproductqty,warehousetouse,selectaddorreplace,"barcode",true);
1227 verify_batch = barcodeserialforproduct(tabproduct,index,element,barcodeproductqty,warehousetouse,selectaddorreplace,"lotserial",true);
1228 break;
1229 case "barcodeforproduct":
1230 verify_barcode = barcodeserialforproduct(tabproduct,index,element,barcodeproductqty,warehousetouse,selectaddorreplace,"barcode");
1231 break;
1232 case "barcodeforlotserial":
1233 verify_batch = barcodeserialforproduct(tabproduct,index,element,barcodeproductqty,warehousetouse,selectaddorreplace,"lotserial");
1234 break;
1235 default:
1236 alert(\''.dol_escape_js($langs->trans("ErrorWrongBarcodemode")).' "\'+barcodemode+\'"\');
1237 throw \''.dol_escape_js($langs->trans('ErrorWrongBarcodemode')).' "\'+barcodemode+\'"\';
1238 }
1239
1240 if (verify_batch == false && verify_barcode == false) { /* If the 2 flags are false, not found error */
1241 errortab2.push(element);
1242 } else if (verify_batch == true && verify_barcode == true) { /* If the 2 flags are true, error: we don t know which one to take */
1243 errortab3.push(element);
1244 } else if (verify_batch == true) {
1245 console.log("element="+element);
1246 console.log(duplicatedbatchcode);
1247 if (duplicatedbatchcode.includes(element)) {
1248 errortab1.push(element);
1249 }
1250 }
1251 });
1252
1253 if (Object.keys(errortab1).length < 1 && Object.keys(errortab2).length < 1 && Object.keys(errortab3).length < 1) {
1254 tabproduct.forEach(product => {
1255 if(product.Qty!=0){
1256 if(product.hasOwnProperty("reelqty")){
1257 idprod = $("td[data-idproduct=\'"+product.fk_product+"\']").attr("id");
1258 idproduct = idprod.split("_")[1];
1259 console.log("We create a new line for product_"+idproduct);
1260 if(product.Barcode != null){
1261 modedispatch = "dispatch";
1262 } else {
1263 modedispatch = "batch";
1264 }
1265 addDispatchLine(idproduct,modedispatch);
1266 console.log($("tr[name^=\'"+modedispatch+"_\'][name$=\'_"+idproduct+"\']"));
1267 nbrTrs = $("tr[name^=\'"+modedispatch+"_\'][name$=\'_"+idproduct+"\']").length;
1268
1269 $("#qty_"+(nbrTrs-1)+"_"+idproduct).val(product.Qty);
1270 $("#entrepot_"+(nbrTrs-1)+"_"+idproduct).val(product.Warehouse);
1271
1272 if(modedispatch == "batch"){
1273 $("#lot_number_"+(nbrTrs-1)+"_"+idproduct).val(product.Batch);
1274 }
1275
1276 } else {
1277 console.log("We change #qty_"+product.Id +" to match input in scanner box");
1278 $("#qty_"+product.Id).val(product.Qty);
1279 }
1280 }
1281 });
1282 jQuery("#scantoolmessage").text("'.dol_escape_js($langs->transnoentities("QtyWasAddedToTheScannedBarcode")).'\n");
1283 /* document.forms["formrecord"].submit(); */
1284 } else {
1285 let stringerror = "";
1286 if (Object.keys(errortab1).length > 0) {
1287 stringerror += "<br>'.dol_escape_js($langs->transnoentities('ErrorSameBatchNumber')).': ";
1288 errortab1.forEach(element => {
1289 stringerror += (element + ", ")
1290 });
1291 stringerror = stringerror.slice(0, -2); /* Remove last ", " */
1292 }
1293 if (Object.keys(errortab2).length > 0) {
1294 stringerror += "<br>'.dol_escape_js($langs->transnoentities('ErrorCantFindCodeInInventory')).': ";
1295 errortab2.forEach(element => {
1296 stringerror += (element + ", ")
1297 });
1298 stringerror = stringerror.slice(0, -2); /* Remove last ", " */
1299 }
1300 if (Object.keys(errortab3).length > 0) {
1301 stringerror += "<br>'.dol_escape_js($langs->transnoentities('ErrorCodeScannedIsBothProductAndSerial')).': ";
1302 errortab3.forEach(element => {
1303 stringerror += (element + ", ")
1304 });
1305 stringerror = stringerror.slice(0, -2); /* Remove last ", " */
1306 }
1307 if (Object.keys(errortab4).length > 0) {
1308 stringerror += "<br>'.dol_escape_js($langs->transnoentities('ErrorBarcodeNotFoundForProductWarehouse')).': ";
1309 errortab4.forEach(element => {
1310 stringerror += (element + ", ")
1311 });
1312 stringerror = stringerror.slice(0, -2); /* Remove last ", " */
1313 }
1314
1315 jQuery("#scantoolmessage").html(\''.dol_escape_js($langs->transnoentities("ErrorOnElementsInventory")).'\' + stringerror);
1316 //alert("'.dol_escape_js($langs->trans("ErrorOnElementsInventory")).' :\n" + stringerror);
1317 }
1318 }
1319
1320 }
1321
1322 /* This methode is called by parent barcodescannerjs() */
1323 function barcodeserialforproduct(tabproduct,index,element,barcodeproductqty,warehousetouse,selectaddorreplace,mode,autodetect=false){
1324 BarcodeIsInProduct=0;
1325 newproductrow=0
1326 result=false;
1327 tabproduct.forEach(product => {
1328 $.ajax({ url: \''.DOL_URL_ROOT.'/expedition/ajax/searchfrombarcode.php\',
1329 data: { "token":"'.newToken().'", "action":"existbarcode","fk_entrepot": warehousetouse, "barcode":element, "mode":mode},
1330 type: \'POST\',
1331 async: false,
1332 success: function(response) {
1333 if (response.status == "success"){
1334 console.log(response.message);
1335 if(!newproductrow){
1336 newproductrow = response.object;
1337 }
1338 }else{
1339 if (mode!="lotserial" && autodetect==false && !errortab4.includes(element)){
1340 errortab4.push(element);
1341 console.error(response.message);
1342 }
1343 }
1344 },
1345 error : function(output) {
1346 console.error("Error on barcodeserialforproduct function");
1347 },
1348 });
1349 console.log("Product "+(index+=1)+": "+element);
1350 if(mode == "barcode"){
1351 testonproduct = product.Barcode
1352 }else if (mode == "lotserial"){
1353 testonproduct = product.Batch
1354 }
1355 testonwarehouse = product.Warehouse;
1356 if(testonproduct == element && testonwarehouse == warehousetouse){
1357 if(selectaddorreplace == "add"){
1358 productqty = parseInt(product.Qty,10);
1359 product.Qty = productqty + parseInt(barcodeproductqty,10);
1360 }else if(selectaddorreplace == "replace"){
1361 if(product.fetched == false){
1362 product.Qty = barcodeproductqty
1363 product.fetched=true
1364 }else{
1365 productqty = parseInt(product.Qty,10);
1366 product.Qty = productqty + parseInt(barcodeproductqty,10);
1367 }
1368 }
1369 BarcodeIsInProduct+=1;
1370 }
1371 })
1372 if(BarcodeIsInProduct==0 && newproductrow!=0){
1373 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});
1374 result = true;
1375 }
1376 if(BarcodeIsInProduct > 0){
1377 result = true;
1378 }
1379 return result;
1380 }
1381 ';
1382 print '</script>';
1383 }
1384 include DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php';
1385 $formother = new FormOther($db);
1386 print $formother->getHTMLScannerForm("barcodescannerjs", 'all', 1);
1387 }
1388
1389 // traitement entrepot par défaut
1390 print '<script type="text/javascript">
1391 $(document).ready(function () {
1392 $("select[name=fk_default_warehouse]").change(function() {
1393 console.log("warehouse is modified");
1394 var fk_default_warehouse = $("option:selected", this).val();
1395 $("select[name^=entrepot_]").val(fk_default_warehouse).change();
1396 });
1397
1398 $("#autoreset").click(function() {
1399 console.log("we click on autoreset");
1400 $(".autoresettr").each(function(){
1401 id = $(this).attr("name");
1402 idtab = id.split("_");
1403 console.log("we process line "+id+" "+idtab);
1404 if ($(this).data("remove") == "clear") { /* data-remove=clear means that line qty must be cleared but line must not be removed */
1405 console.log("We clear the object to expected value")
1406 $("#qty_"+idtab[1]+"_"+idtab[2]).val("");
1407 /*
1408 qtyexpected = $("#qty_"+idtab[1]+"_"+idtab[2]).data("expected")
1409 console.log(qtyexpected);
1410 $("#qty_"+idtab[1]+"_"+idtab[2]).val(qtyexpected);
1411 qtydispatched = $("#qty_dispatched_0_"+idtab[2]).data("dispatched")
1412 $("#qty_dispatched_0_"+idtab[2]).val(qtydispatched);
1413 */
1414 } else { /* data-remove=remove means that line must be removed */
1415 console.log("We remove the object")
1416 $(this).remove();
1417 $("tr[name^=\'"+idtab[0]+"_\'][name$=\'_"+idtab[2]+"\']:last .splitbutton").show();
1418 }
1419 });
1420 return false;
1421 });
1422
1423 $("#resetalltoexpected").click(function(){
1424 $(".qtydispatchinput").each(function(){
1425 console.log("We reset to expected "+$(this).attr("id")+" qty to dispatch");
1426 $(this).val($(this).data("expected"));
1427 });
1428 return false;
1429 });
1430
1431 $(".resetline").on("click", function(event) {
1432 event.preventDefault();
1433 id = $(this).attr("id");
1434 id = id.split("reset_");
1435 console.log("Reset trigger for id = qty_"+id[1]);
1436 $("#qty_"+id[1]).val("");
1437 });
1438 });
1439 </script>';
1440}
1441
1442// End of page
1443llxFooter();
1444$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 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.
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 '.
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...
getDolGlobalString($key, $default='')
Return dolibarr global constant string value.
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.
ui state ui widget content ui state ui widget header ui state a ui button
0 = Do not include form tag and submit button -1 = Do not include form tag but include submit button
$conf db name
Only used if Module[ID]Name translation string is not found.
Definition repair.php:140
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.
publicphonebutton2 phonegreen basiclayout basiclayout TotalHT VATCode TotalVAT TotalLT1 TotalLT2 TotalTTC TotalHT clearboth nowraponall TAKEPOS_SHOW_SUBPRICE right right right takeposterminal SELECT e rowid
Definition invoice.php:2010