dolibarr 20.0.0
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("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
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, 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
1440llxFooter();
1441$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:1991