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