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