dolibarr 21.0.0-alpha
card.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2003-2008 Rodolphe Quiedeville <rodolphe@quiedeville.org>
3 * Copyright (C) 2005-2016 Laurent Destailleur <eldy@users.sourceforge.net>
4 * Copyright (C) 2005 Simon TOSSER <simon@kornog-computing.com>
5 * Copyright (C) 2005-2012 Regis Houssin <regis.houssin@inodbox.com>
6 * Copyright (C) 2011-2017 Juanjo Menent <jmenent@2byte.es>
7 * Copyright (C) 2013 Florian Henry <florian.henry@open-concept.pro>
8 * Copyright (C) 2013 Marcos García <marcosgdf@gmail.com>
9 * Copyright (C) 2014 Cedric GROSS <c.gross@kreiz-it.fr>
10 * Copyright (C) 2014-2017 Francis Appels <francis.appels@yahoo.com>
11 * Copyright (C) 2015 Claudio Aschieri <c.aschieri@19.coop>
12 * Copyright (C) 2016-2018 Ferran Marcet <fmarcet@2byte.es>
13 * Copyright (C) 2016 Yasser Carreón <yacasia@gmail.com>
14 * Copyright (C) 2018-2024 Frédéric France <frederic.france@free.fr>
15 * Copyright (C) 2020 Lenin Rivas <lenin@leninrivas.com>
16 * Copyright (C) 2022 Josep Lluís Amador <joseplluis@lliuretic.cat>
17 * Copyright (C) 2024 MDW <mdeweerd@users.noreply.github.com>
18 *
19 * This program is free software; you can redistribute it and/or modify
20 * it under the terms of the GNU General Public License as published by
21 * the Free Software Foundation; either version 3 of the License, or
22 * (at your option) any later version.
23 *
24 * This program is distributed in the hope that it will be useful,
25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 * GNU General Public License for more details.
28 *
29 * You should have received a copy of the GNU General Public License
30 * along with this program. If not, see <https://www.gnu.org/licenses/>.
31 */
32
39// Load Dolibarr environment
40require '../main.inc.php';
41require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php';
42require_once DOL_DOCUMENT_ROOT.'/expedition/class/expedition.class.php';
43require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php';
44require_once DOL_DOCUMENT_ROOT.'/core/lib/product.lib.php';
45require_once DOL_DOCUMENT_ROOT.'/core/lib/sendings.lib.php';
46require_once DOL_DOCUMENT_ROOT.'/core/modules/expedition/modules_expedition.php';
47require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
48require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
49require_once DOL_DOCUMENT_ROOT.'/product/stock/class/entrepot.class.php';
50require_once DOL_DOCUMENT_ROOT.'/product/stock/class/productlot.class.php';
51require_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php';
52if (isModEnabled("product") || isModEnabled("service")) {
53 require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
54}
55if (isModEnabled("propal")) {
56 require_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php';
57}
58if (isModEnabled('productbatch')) {
59 require_once DOL_DOCUMENT_ROOT.'/product/class/productbatch.class.php';
60}
61if (isModEnabled('project')) {
62 require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
63 require_once DOL_DOCUMENT_ROOT.'/core/class/html.formprojet.class.php';
64}
65
66// Load translation files required by the page
67$langs->loadLangs(array("sendings", "companies", "bills", 'deliveries', 'orders', 'stocks', 'other', 'propal', 'productbatch'));
68
69if (isModEnabled('incoterm')) {
70 $langs->load('incoterm');
71}
72if (isModEnabled('productbatch')) {
73 $langs->load('productbatch');
74}
75
76$origin = GETPOST('origin', 'alpha') ? GETPOST('origin', 'alpha') : 'expedition'; // Example: commande, propal
77$origin_id = GETPOSTINT('id') ? GETPOSTINT('id') : '';
78$id = $origin_id;
79if (empty($origin_id)) {
80 $origin_id = GETPOSTINT('origin_id'); // Id of order or propal
81}
82if (empty($origin_id)) {
83 $origin_id = GETPOSTINT('object_id'); // Id of order or propal
84}
85$ref = GETPOST('ref', 'alpha');
86$line_id = GETPOSTINT('lineid');
87$facid = GETPOSTINT('facid');
88
89$action = GETPOST('action', 'alpha');
90$confirm = GETPOST('confirm', 'alpha');
91$cancel = GETPOST('cancel', 'alpha');
92
93//PDF
94$hidedetails = (GETPOSTINT('hidedetails') ? GETPOSTINT('hidedetails') : (getDolGlobalString('MAIN_GENERATE_DOCUMENTS_HIDE_DETAILS') ? 1 : 0));
95$hidedesc = (GETPOSTINT('hidedesc') ? GETPOSTINT('hidedesc') : (getDolGlobalString('MAIN_GENERATE_DOCUMENTS_HIDE_DESC') ? 1 : 0));
96$hideref = (GETPOSTINT('hideref') ? GETPOSTINT('hideref') : (getDolGlobalString('MAIN_GENERATE_DOCUMENTS_HIDE_REF') ? 1 : 0));
97
98$object = new Expedition($db);
99$objectorder = new Commande($db);
100$extrafields = new ExtraFields($db);
101
102// fetch optionals attributes and labels
103$extrafields->fetch_name_optionals_label($object->table_element);
104$extrafields->fetch_name_optionals_label($object->table_element_line);
105$extrafields->fetch_name_optionals_label($objectorder->table_element_line);
106
107// Load object. Make an object->fetch
108include DOL_DOCUMENT_ROOT.'/core/actions_fetchobject.inc.php'; // Must be 'include', not 'include_once'
109
110// Initialize a technical object to manage hooks of page. Note that conf->hooks_modules contains an array of hook context
111$hookmanager->initHooks(array('expeditioncard', 'globalcard'));
112
113$date_delivery = dol_mktime(GETPOSTINT('date_deliveryhour'), GETPOSTINT('date_deliverymin'), 0, GETPOSTINT('date_deliverymonth'), GETPOSTINT('date_deliveryday'), GETPOSTINT('date_deliveryyear'));
114
115if ($id > 0 || !empty($ref)) {
116 $object->fetch($id, $ref);
117 $object->fetch_thirdparty();
118}
119
120// Security check
121$socid = '';
122if ($user->socid) {
123 $socid = $user->socid;
124}
125
126$result = restrictedArea($user, 'expedition', $object->id, '');
127
128$permissiondellink = $user->hasRight('expedition', 'delivery', 'creer'); // Used by the include of actions_dellink.inc.php
129$permissiontoadd = $user->hasRight('expedition', 'creer');
130
131$editColspan = 0;
132$objectsrc = null;
133$typeobject = null;
134
135
136/*
137 * Actions
138 */
139
140$parameters = array();
141$reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
142if ($reshook < 0) {
143 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
144}
145
146if (empty($reshook)) {
147 if ($cancel) {
148 if ($origin && $origin_id > 0) {
149 if ($origin == 'commande') {
150 header("Location: ".DOL_URL_ROOT.'/expedition/shipment.php?id='.((int) $origin_id));
151 exit;
152 }
153 } else {
154 $action = '';
155 $object->fetch($id); // show shipment also after canceling modification
156 }
157 }
158
159 include DOL_DOCUMENT_ROOT.'/core/actions_dellink.inc.php'; // Must be 'include', not 'include_once'
160
161 // Actions to build doc
162 $upload_dir = $conf->expedition->dir_output.'/sending';
163 include DOL_DOCUMENT_ROOT.'/core/actions_builddoc.inc.php';
164
165 // Back to draft
166 if ($action == 'setdraft' && $permissiontoadd) {
167 $object->fetch($id);
168 $result = $object->setDraft($user, 0);
169 if ($result < 0) {
170 setEventMessages($object->error, $object->errors, 'errors');
171 } else {
172 header("Location: ".$_SERVER['PHP_SELF']."?id=".$object->id);
173 exit;
174 }
175 }
176 // Reopen
177 if ($action == 'reopen' && $permissiontoadd) {
178 $object->fetch($id);
179 $result = $object->reOpen();
180 if ($result < 0) {
181 setEventMessages($object->error, $object->errors, 'errors');
182 } else {
183 header("Location: ".$_SERVER['PHP_SELF']."?id=".$object->id);
184 exit;
185 }
186 }
187
188 // Set incoterm
189 if ($action == 'set_incoterms' && isModEnabled('incoterm') && $permissiontoadd) {
190 $result = $object->setIncoterms(GETPOSTINT('incoterm_id'), GETPOST('location_incoterms'));
191 }
192
193 if ($action == 'setref_customer' && $permissiontoadd) {
194 $result = $object->fetch($id);
195 if ($result < 0) {
196 setEventMessages($object->error, $object->errors, 'errors');
197 }
198
199 $result = $object->setValueFrom('ref_customer', GETPOST('ref_customer', 'alpha'), '', null, 'text', '', $user, 'SHIPMENT_MODIFY');
200 if ($result < 0) {
201 setEventMessages($object->error, $object->errors, 'errors');
202 $action = 'editref_customer';
203 } else {
204 header("Location: ".$_SERVER['PHP_SELF']."?id=".$object->id);
205 exit;
206 }
207 }
208
209 if ($action == 'update_extras' && $permissiontoadd) {
210 $object->oldcopy = dol_clone($object, 2);
211 $attribute_name = GETPOST('attribute', 'restricthtml');
212
213 // Fill array 'array_options' with data from update form
214 $ret = $extrafields->setOptionalsFromPost(null, $object, $attribute_name);
215 if ($ret < 0) {
216 $error++;
217 }
218
219 if (!$error) {
220 // Actions on extra fields
221 $result = $object->updateExtraField($attribute_name, 'SHIPMENT_MODIFY');
222 if ($result < 0) {
223 setEventMessages($object->error, $object->errors, 'errors');
224 $error++;
225 }
226 }
227
228 if ($error) {
229 $action = 'edit_extras';
230 }
231 }
232
233 // Create shipment
234 if ($action == 'add' && $permissiontoadd) {
235 $error = 0;
236
237 $db->begin();
238
239 $object->note = GETPOST('note', 'restricthtml');
240 $object->note_private = GETPOST('note', 'restricthtml');
241 $object->origin = $origin;
242 $object->origin_id = $origin_id;
243 $object->fk_project = GETPOSTINT('projectid');
244 $object->weight = GETPOSTINT('weight') == '' ? "NULL" : GETPOSTINT('weight');
245 $object->sizeH = GETPOSTINT('sizeH') == '' ? "NULL" : GETPOSTINT('sizeH');
246 $object->sizeW = GETPOSTINT('sizeW') == '' ? "NULL" : GETPOSTINT('sizeW');
247 $object->sizeS = GETPOSTINT('sizeS') == '' ? "NULL" : GETPOSTINT('sizeS');
248 $object->size_units = GETPOSTINT('size_units');
249 $object->weight_units = GETPOSTINT('weight_units');
250
251 $product = new Product($db);
252
253 // We will loop on each line of the original document to complete the shipping object with various info and quantity to deliver
254 $classname = ucfirst($object->origin);
255 $objectsrc = new $classname($db);
256 '@phan-var-force Facture|Commande $objectsrc';
257 $objectsrc->fetch($object->origin_id);
258
259 $object->socid = $objectsrc->socid;
260 $object->ref_customer = GETPOST('ref_customer', 'alpha');
261 $object->model_pdf = GETPOST('model');
262 $object->date_delivery = $date_delivery; // Date delivery planned
263 $object->fk_delivery_address = $objectsrc->fk_delivery_address;
264 $object->shipping_method_id = GETPOSTINT('shipping_method_id');
265 $object->tracking_number = GETPOST('tracking_number', 'alpha');
266 $object->note_private = GETPOST('note_private', 'restricthtml');
267 $object->note_public = GETPOST('note_public', 'restricthtml');
268 $object->fk_incoterms = GETPOSTINT('incoterm_id');
269 $object->location_incoterms = GETPOST('location_incoterms', 'alpha');
270
271 $batch_line = array();
272 $stockLine = array();
273 $array_options = array();
274
275 $num = count($objectsrc->lines);
276 $totalqty = 0;
277
278 $product_batch_used = array();
279
280 for ($i = 0; $i < $num; $i++) {
281 $idl = "idl".$i;
282
283 $sub_qty = array();
284 $subtotalqty = 0;
285
286 $j = 0;
287 $batch = "batchl".$i."_0";
288 $stockLocation = "ent1".$i."_0";
289 $qty = "qtyl".$i;
290
291 $is_batch_or_serial = 0;
292 if (!empty($objectsrc->lines[$i]->fk_product)) {
293 $resultFetch = $product->fetch($objectsrc->lines[$i]->fk_product, '', '', '', 1, 1, 1);
294 if ($resultFetch < 0) {
295 setEventMessages($product->error, $product->errors, 'errors');
296 }
297 $is_batch_or_serial = $product->status_batch;
298 }
299
300 // If product need a batch or serial number
301 if (isModEnabled('productbatch') && $objectsrc->lines[$i]->product_tobatch) {
302 if (GETPOSTISSET($batch)) {
303 //shipment line with batch-enable product
304 $qty .= '_'.$j;
305 while (GETPOSTISSET($batch)) {
306 // save line of detail into sub_qty
307 $sub_qty[$j]['q'] = price2num(GETPOST($qty, 'alpha'), 'MS'); // the qty we want to move for this stock record
308 $sub_qty[$j]['id_batch'] = GETPOSTINT($batch); // the id into llx_product_batch of stock record to move
309 $subtotalqty += $sub_qty[$j]['q'];
310
311 //var_dump($qty);
312 //var_dump($batch);
313 //var_dump($sub_qty[$j]['q']);
314 //var_dump($sub_qty[$j]['id_batch']);
315
316 //var_dump($qty);var_dump($batch);var_dump($sub_qty[$j]['q']);var_dump($sub_qty[$j]['id_batch']);
317 if ($is_batch_or_serial == 2 && ($sub_qty[$j]['q'] > 1 || ($sub_qty[$j]['q'] > 0 && in_array($sub_qty[$j]['id_batch'], $product_batch_used)))) {
318 setEventMessages($langs->trans("TooManyQtyForSerialNumber", $product->ref, ''), null, 'errors');
319 $totalqty = 0;
320 break 2;
321 }
322
323 if ($is_batch_or_serial == 2 && $sub_qty[$j]['q'] > 0) {
324 // we stock the batch id to test later if the same serial is shipped on another line for the same product
325 $product_batch_used[$j] = $sub_qty[$j]['id_batch'];
326 }
327
328 $j++;
329 $batch = "batchl".$i."_".$j;
330 $qty = "qtyl".$i.'_'.$j;
331 }
332
333 $batch_line[$i]['detail'] = $sub_qty; // array of details
334 $batch_line[$i]['qty'] = $subtotalqty;
335 $batch_line[$i]['ix_l'] = GETPOSTINT($idl);
336
337 $totalqty += $subtotalqty;
338 } else {
339 // No detail were provided for lots, so if a qty was provided, we can throw an error.
340 if (GETPOST($qty)) {
341 // We try to set an amount
342 // Case we don't use the list of available qty for each warehouse/lot
343 // GUI does not allow this yet
344 setEventMessages($langs->trans("StockIsRequiredToChooseWhichLotToUse").' ('.$langs->trans("Line").' '.GETPOSTINT($idl).')', null, 'errors');
345 $error++;
346 }
347 }
348 } elseif (GETPOSTISSET($stockLocation)) {
349 //shipment line from multiple stock locations
350 $qty .= '_'.$j;
351 while (GETPOSTISSET($stockLocation)) {
352 // save sub line of warehouse
353 $stockLine[$i][$j]['qty'] = price2num(GETPOST($qty, 'alpha'), 'MS');
354 $stockLine[$i][$j]['warehouse_id'] = GETPOSTINT($stockLocation);
355 $stockLine[$i][$j]['ix_l'] = GETPOSTINT($idl);
356
357 $totalqty += price2num(GETPOST($qty, 'alpha'), 'MS');
358 $subtotalqty += price2num(GETPOST($qty, 'alpha'), 'MS');
359
360 $j++;
361 $stockLocation = "ent1".$i."_".$j;
362 $qty = "qtyl".$i.'_'.$j;
363 }
364 } else {
365 //shipment line for product with no batch management and no multiple stock location
366 if (GETPOSTINT($qty) > 0) {
367 $totalqty += price2num(GETPOST($qty, 'alpha'), 'MS');
368 $subtotalqty = price2num(GETPOST($qty, 'alpha'), 'MS');
369 }
370 }
371
372 // check qty shipped not greater than ordered
373 if (getDolGlobalInt("MAIN_DONT_SHIP_MORE_THAN_ORDERED") && $subtotalqty > $objectsrc->lines[$i]->qty) {
374 setEventMessages($langs->trans("ErrorTooMuchShipped", $i + 1), null, 'errors');
375 $error++;
376 continue;
377 }
378
379 // Extrafields
380 $array_options[$i] = $extrafields->getOptionalsFromPost($object->table_element_line, $i);
381 // Unset extrafield
382 if (isset($extrafields->attributes[$object->table_element_line]['label']) && is_array($extrafields->attributes[$object->table_element_line]['label'])) {
383 // Get extra fields
384 foreach ($extrafields->attributes[$object->table_element_line]['label'] as $key => $value) {
385 unset($_POST["options_".$key]);
386 }
387 }
388 }
389
390 //var_dump($batch_line[2]);
391 if (($totalqty > 0 || getDolGlobalString('SHIPMENT_GETS_ALL_ORDER_PRODUCTS')) && !$error) { // There is at least one thing to ship and no error
392 for ($i = 0; $i < $num; $i++) {
393 $qty = "qtyl".$i;
394
395 if (!isset($batch_line[$i])) {
396 // not batch mode
397 if (isset($stockLine[$i])) {
398 //shipment from multiple stock locations
399 $nbstockline = count($stockLine[$i]);
400 for ($j = 0; $j < $nbstockline; $j++) {
401 if ($stockLine[$i][$j]['qty'] > 0 || ($stockLine[$i][$j]['qty'] == 0 && getDolGlobalString('SHIPMENT_GETS_ALL_ORDER_PRODUCTS'))) {
402 $ret = $object->addline($stockLine[$i][$j]['warehouse_id'], $stockLine[$i][$j]['ix_l'], $stockLine[$i][$j]['qty'], $array_options[$i]);
403 if ($ret < 0) {
404 setEventMessages($object->error, $object->errors, 'errors');
405 $error++;
406 }
407 }
408 }
409 } else {
410 if (GETPOSTINT($qty) > 0 || getDolGlobalString('SHIPMENT_GETS_ALL_ORDER_PRODUCTS')) {
411 $ent = "entl".$i;
412 $idl = "idl".$i;
413 $entrepot_id = is_numeric(GETPOSTINT($ent)) ? GETPOSTINT($ent) : GETPOSTINT('entrepot_id');
414 if ($entrepot_id < 0) {
415 $entrepot_id = '';
416 }
417 if (!($objectsrc->lines[$i]->fk_product > 0)) {
418 $entrepot_id = 0;
419 }
420
421 $ret = $object->addline($entrepot_id, GETPOSTINT($idl), price2num(GETPOSTINT($qty), 'MS'), $array_options[$i]);
422 if ($ret < 0) {
423 setEventMessages($object->error, $object->errors, 'errors');
424 $error++;
425 }
426 }
427 }
428 } else {
429 // batch mode
430 if ($batch_line[$i]['qty'] > 0 || ($batch_line[$i]['qty'] == 0 && getDolGlobalString('SHIPMENT_GETS_ALL_ORDER_PRODUCTS'))) {
431 $ret = $object->addline_batch($batch_line[$i], $array_options[$i]);
432 if ($ret < 0) {
433 setEventMessages($object->error, $object->errors, 'errors');
434 $error++;
435 }
436 }
437 }
438 }
439 // Fill array 'array_options' with data from add form
440 $ret = $extrafields->setOptionalsFromPost(null, $object);
441 if ($ret < 0) {
442 $error++;
443 }
444
445 if (!$error) {
446 $ret = $object->create($user); // This create shipment (like Odoo picking) and lines of shipments. Stock movement will be done when validating or closing shipment.
447 if ($ret <= 0) {
448 setEventMessages($object->error, $object->errors, 'errors');
449 $error++;
450 }
451 }
452 } elseif (!$error) {
453 $labelfieldmissing = $langs->transnoentitiesnoconv("QtyToShip");
454 if (isModEnabled('stock')) {
455 $labelfieldmissing .= '/'.$langs->transnoentitiesnoconv("Warehouse");
456 }
457 setEventMessages($langs->trans("ErrorFieldRequired", $labelfieldmissing), null, 'errors');
458 $error++;
459 }
460
461 if (!$error) {
462 $db->commit();
463 header("Location: card.php?id=".$object->id);
464 exit;
465 } else {
466 $db->rollback();
467 //$_GET["commande_id"] = GETPOSTINT('commande_id');
468 $action = 'create';
469 }
470 } elseif ($action == 'create_delivery' && getDolGlobalInt('MAIN_SUBMODULE_DELIVERY') && $user->hasRight('expedition', 'delivery', 'creer')) {
471 // Build a receiving receipt
472 $db->begin();
473
474 $result = $object->create_delivery($user);
475 if ($result > 0) {
476 $db->commit();
477
478 header("Location: ".DOL_URL_ROOT.'/delivery/card.php?action=create_delivery&token='.newToken().'&id='.$result);
479 exit;
480 } else {
481 $db->rollback();
482
483 setEventMessages($object->error, $object->errors, 'errors');
484 }
485 } elseif ($action == 'confirm_valid' && $confirm == 'yes' && ((!getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && $user->hasRight('expedition', 'creer'))
486 || (getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && $user->hasRight('expedition', 'shipping_advance', 'validate')))
487 ) {
488 $object->fetch_thirdparty();
489
490 $result = $object->valid($user);
491
492 if ($result < 0) {
493 setEventMessages($object->error, $object->errors, 'errors');
494 } else {
495 // Define output language
496 if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
497 $outputlangs = $langs;
498 $newlang = '';
499 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && GETPOST('lang_id', 'aZ09')) {
500 $newlang = GETPOST('lang_id', 'aZ09');
501 }
502 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
503 $newlang = $object->thirdparty->default_lang;
504 }
505 if (!empty($newlang)) {
506 $outputlangs = new Translate("", $conf);
507 $outputlangs->setDefaultLang($newlang);
508 }
509 $model = $object->model_pdf;
510 $ret = $object->fetch($id); // Reload to get new records
511
512 $result = $object->generateDocument($model, $outputlangs, $hidedetails, $hidedesc, $hideref);
513 if ($result < 0) {
514 dol_print_error($db, $object->error, $object->errors);
515 }
516 }
517 }
518 } elseif ($action == 'confirm_cancel' && $confirm == 'yes' && $user->hasRight('expedition', 'supprimer')) {
519 $also_update_stock = (GETPOST('alsoUpdateStock', 'alpha') ? 1 : 0);
520 $result = $object->cancel(0, $also_update_stock);
521 if ($result > 0) {
522 $result = $object->setStatut(-1);
523 } else {
524 setEventMessages($object->error, $object->errors, 'errors');
525 }
526 } elseif ($action == 'confirm_delete' && $confirm == 'yes' && $user->hasRight('expedition', 'supprimer')) {
527 $also_update_stock = (GETPOST('alsoUpdateStock', 'alpha') ? 1 : 0);
528 $result = $object->delete($user, 0, $also_update_stock);
529 if ($result > 0) {
530 header("Location: ".DOL_URL_ROOT.'/expedition/index.php');
531 exit;
532 } else {
533 setEventMessages($object->error, $object->errors, 'errors');
534 }
535 // TODO add alternative status
536 //} elseif ($action == 'reopen' && ($user->hasRight('expedition', 'creer') || $user->hasRight('expedition', 'shipping_advance', 'validate')))
537 //{
538 // $result = $object->setStatut(0);
539 // if ($result < 0)
540 // {
541 // setEventMessages($object->error, $object->errors, 'errors');
542 // }
543 //}
544 } elseif ($action == 'setdate_livraison' && $user->hasRight('expedition', 'creer')) {
545 $datedelivery = dol_mktime(GETPOSTINT('liv_hour'), GETPOSTINT('liv_min'), 0, GETPOSTINT('liv_month'), GETPOSTINT('liv_day'), GETPOSTINT('liv_year'));
546
547 $object->fetch($id);
548 $result = $object->setDeliveryDate($user, $datedelivery);
549 if ($result < 0) {
550 setEventMessages($object->error, $object->errors, 'errors');
551 }
552 } elseif (in_array($action, array('settracking_number', 'settracking_url', 'settrueWeight', 'settrueWidth', 'settrueHeight', 'settrueDepth', 'setshipping_method_id')) && $user->hasRight('expedition', 'creer')) {
553 // Action update
554 $error = 0;
555
556 if ($action == 'settracking_number') {
557 $object->tracking_number = trim(GETPOST('tracking_number', 'alpha'));
558 }
559 if ($action == 'settracking_url') {
560 $object->tracking_url = trim(GETPOST('tracking_url', 'restricthtml'));
561 }
562 if ($action == 'settrueWeight') {
563 $object->trueWeight = GETPOSTINT('trueWeight');
564 $object->weight_units = GETPOSTINT('weight_units');
565 }
566 if ($action == 'settrueWidth') {
567 $object->trueWidth = GETPOSTINT('trueWidth');
568 }
569 if ($action == 'settrueHeight') {
570 $object->trueHeight = GETPOSTINT('trueHeight');
571 $object->size_units = GETPOSTINT('size_units');
572 }
573 if ($action == 'settrueDepth') {
574 $object->trueDepth = GETPOSTINT('trueDepth');
575 }
576 if ($action == 'setshipping_method_id') {
577 $object->shipping_method_id = GETPOSTINT('shipping_method_id');
578 }
579
580 if (!$error) {
581 if ($object->update($user) >= 0) {
582 header("Location: card.php?id=".$object->id);
583 exit;
584 }
585 setEventMessages($object->error, $object->errors, 'errors');
586 }
587
588 $action = "";
589 } elseif ($action == 'classifybilled' && $permissiontoadd) {
590 $object->fetch($id);
591 $result = $object->setBilled();
592 if ($result >= 0) {
593 header('Location: '.$_SERVER["PHP_SELF"].'?id='.$object->id);
594 exit();
595 }
596 setEventMessages($object->error, $object->errors, 'errors');
597 } elseif ($action == 'classifyclosed' && $permissiontoadd) {
598 $object->fetch($id);
599 $result = $object->setClosed();
600 if ($result >= 0) {
601 header('Location: '.$_SERVER["PHP_SELF"].'?id='.$object->id);
602 exit();
603 }
604 setEventMessages($object->error, $object->errors, 'errors');
605 } elseif ($action == 'deleteline' && !empty($line_id) && $permissiontoadd) {
606 // delete a line
607 $object->fetch($id);
608 $lines = $object->lines;
609 $line = new ExpeditionLigne($db);
610 $line->fk_expedition = $object->id;
611
612 $num_prod = count($lines);
613 for ($i = 0; $i < $num_prod; $i++) {
614 if ($lines[$i]->id == $line_id) {
615 if (count($lines[$i]->details_entrepot) > 1) {
616 // delete multi warehouse lines
617 foreach ($lines[$i]->details_entrepot as $details_entrepot) {
618 $line->id = $details_entrepot->line_id;
619 if (!$error && $line->delete($user) < 0) {
620 $error++;
621 }
622 }
623 } else {
624 // delete single warehouse line
625 $line->id = $line_id;
626 if (!$error && $line->delete($user) < 0) {
627 $error++;
628 }
629 }
630 }
631 unset($_POST["lineid"]);
632 }
633
634 if (!$error) {
635 header('Location: '.$_SERVER["PHP_SELF"].'?id='.$object->id);
636 exit();
637 } else {
638 setEventMessages($line->error, $line->errors, 'errors');
639 }
640 } elseif ($action == 'updateline' && $permissiontoadd && GETPOST('save')) {
641 // Update a line
642 // Clean parameters
643 $qty = 0;
644 $entrepot_id = 0;
645 $batch_id = 0;
646
647 $lines = $object->lines;
648 $num_prod = count($lines);
649 for ($i = 0; $i < $num_prod; $i++) {
650 if ($lines[$i]->id == $line_id) { // we have found line to update
651 $update_done = false;
652 $line = new ExpeditionLigne($db);
653 $line->fk_expedition = $object->id;
654
655 // Extrafields Lines
656 $line->array_options = $extrafields->getOptionalsFromPost($object->table_element_line);
657 // Unset extrafield POST Data
658 if (is_array($extrafields->attributes[$object->table_element_line]['label'])) {
659 foreach ($extrafields->attributes[$object->table_element_line]['label'] as $key => $value) {
660 unset($_POST["options_".$key]);
661 }
662 }
663 $line->fk_product = $lines[$i]->fk_product;
664 if (is_array($lines[$i]->detail_batch) && count($lines[$i]->detail_batch) > 0) {
665 // line with lot
666 foreach ($lines[$i]->detail_batch as $detail_batch) {
667 $lotStock = new Productbatch($db);
668 $batch = "batchl".$detail_batch->fk_expeditiondet."_".$detail_batch->fk_origin_stock;
669 $qty = "qtyl".$detail_batch->fk_expeditiondet.'_'.$detail_batch->id;
670 $batch_id = GETPOSTINT($batch);
671 $batch_qty = GETPOSTINT($qty);
672 if (!empty($batch_id)) {
673 if ($lotStock->fetch($batch_id) > 0 && $line->fetch($detail_batch->fk_expeditiondet) > 0) { // $line is ExpeditionLine
674 if ($lines[$i]->entrepot_id != 0) {
675 // allow update line entrepot_id if not multi warehouse shipping
676 $line->entrepot_id = $lotStock->warehouseid;
677 }
678
679 // detail_batch can be an object with keys, or an array of ExpeditionLineBatch
680 if (empty($line->detail_batch)) {
681 $line->detail_batch = new stdClass();
682 }
683
684 $line->detail_batch->fk_origin_stock = $batch_id;
685 $line->detail_batch->batch = $lotStock->batch;
686 $line->detail_batch->id = $detail_batch->id;
687 $line->detail_batch->entrepot_id = $lotStock->warehouseid;
688 $line->detail_batch->qty = $batch_qty;
689 if ($line->update($user) < 0) {
690 setEventMessages($line->error, $line->errors, 'errors');
691 $error++;
692 } else {
693 $update_done = true;
694 }
695 } else {
696 setEventMessages($lotStock->error, $lotStock->errors, 'errors');
697 $error++;
698 }
699 }
700 unset($_POST[$batch]);
701 unset($_POST[$qty]);
702 }
703 // add new batch
704 $lotStock = new Productbatch($db);
705 $batch = "batchl".$line_id."_0";
706 $qty = "qtyl".$line_id."_0";
707 $batch_id = GETPOSTINT($batch);
708 $batch_qty = GETPOSTINT($qty);
709 $lineIdToAddLot = 0;
710 if ($batch_qty > 0 && !empty($batch_id)) {
711 if ($lotStock->fetch($batch_id) > 0) {
712 // check if lotStock warehouse id is same as line warehouse id
713 if ($lines[$i]->entrepot_id > 0) {
714 // single warehouse shipment line
715 if ($lines[$i]->entrepot_id == $lotStock->warehouseid) {
716 $lineIdToAddLot = $line_id;
717 }
718 } elseif (count($lines[$i]->details_entrepot) > 1) {
719 // multi warehouse shipment lines
720 foreach ($lines[$i]->details_entrepot as $detail_entrepot) {
721 if ($detail_entrepot->entrepot_id == $lotStock->warehouseid) {
722 $lineIdToAddLot = $detail_entrepot->line_id;
723 }
724 }
725 }
726 if ($lineIdToAddLot) {
727 // add lot to existing line
728 if ($line->fetch($lineIdToAddLot) > 0) {
729 $line->detail_batch->fk_origin_stock = $batch_id;
730 $line->detail_batch->batch = $lotStock->batch;
731 $line->detail_batch->entrepot_id = $lotStock->warehouseid;
732 $line->detail_batch->qty = $batch_qty;
733 if ($line->update($user) < 0) {
734 setEventMessages($line->error, $line->errors, 'errors');
735 $error++;
736 } else {
737 $update_done = true;
738 }
739 } else {
740 setEventMessages($line->error, $line->errors, 'errors');
741 $error++;
742 }
743 } else {
744 // create new line with new lot
745 $line->origin_line_id = $lines[$i]->origin_line_id;
746 $line->entrepot_id = $lotStock->warehouseid;
747 $line->detail_batch[0] = new ExpeditionLineBatch($db);
748 $line->detail_batch[0]->fk_origin_stock = $batch_id;
749 $line->detail_batch[0]->batch = $lotStock->batch;
750 $line->detail_batch[0]->entrepot_id = $lotStock->warehouseid;
751 $line->detail_batch[0]->qty = $batch_qty;
752 if ($object->create_line_batch($line, $line->array_options) < 0) {
753 setEventMessages($object->error, $object->errors, 'errors');
754 $error++;
755 } else {
756 $update_done = true;
757 }
758 }
759 } else {
760 setEventMessages($lotStock->error, $lotStock->errors, 'errors');
761 $error++;
762 }
763 }
764 } else {
765 if ($lines[$i]->fk_product > 0) {
766 // line without lot
767 if ($lines[$i]->entrepot_id == 0) {
768 // single warehouse shipment line or line in several warehouses context but with warehouse not defined
769 $stockLocation = "entl".$line_id;
770 $qty = "qtyl".$line_id;
771 $line->id = $line_id;
772 $line->entrepot_id = GETPOSTINT((string) $stockLocation);
773 $line->qty = GETPOSTFLOAT($qty);
774 if ($line->update($user) < 0) {
775 setEventMessages($line->error, $line->errors, 'errors');
776 $error++;
777 }
778 unset($_POST[$stockLocation]);
779 unset($_POST[$qty]);
780 } elseif ($lines[$i]->entrepot_id > 0) {
781 // single warehouse shipment line
782 $stockLocation = "entl".$line_id;
783 $qty = "qtyl".$line_id;
784 $line->id = $line_id;
785 $line->entrepot_id = GETPOSTINT($stockLocation);
786 $line->qty = GETPOSTFLOAT($qty);
787 if ($line->update($user) < 0) {
788 setEventMessages($line->error, $line->errors, 'errors');
789 $error++;
790 }
791 unset($_POST[$stockLocation]);
792 unset($_POST[$qty]);
793 } elseif (count($lines[$i]->details_entrepot) > 1) {
794 // multi warehouse shipment lines
795 foreach ($lines[$i]->details_entrepot as $detail_entrepot) {
796 if (!$error) {
797 $stockLocation = "entl".$detail_entrepot->line_id;
798 $qty = "qtyl".$detail_entrepot->line_id;
799 $warehouse = GETPOSTINT($stockLocation);
800 if (!empty($warehouse)) {
801 $line->id = $detail_entrepot->line_id;
802 $line->entrepot_id = $warehouse;
803 $line->qty = GETPOSTFLOAT($qty);
804 if ($line->update($user) < 0) {
805 setEventMessages($line->error, $line->errors, 'errors');
806 $error++;
807 } else {
808 $update_done = true;
809 }
810 }
811 unset($_POST[$stockLocation]);
812 unset($_POST[$qty]);
813 }
814 }
815 } elseif (!isModEnabled('stock') && empty($conf->productbatch->enabled)) { // both product batch and stock are not activated.
816 $qty = "qtyl".$line_id;
817 $line->id = $line_id;
818 $line->qty = GETPOSTFLOAT($qty);
819 $line->entrepot_id = 0;
820 if ($line->update($user) < 0) {
821 setEventMessages($line->error, $line->errors, 'errors');
822 $error++;
823 } else {
824 $update_done = true;
825 }
826 unset($_POST[$qty]);
827 }
828 } else {
829 // Product no predefined
830 $qty = "qtyl".$line_id;
831 $line->id = $line_id;
832 $line->qty = GETPOSTFLOAT($qty);
833 $line->entrepot_id = 0;
834 if ($line->update($user) < 0) {
835 setEventMessages($line->error, $line->errors, 'errors');
836 $error++;
837 } else {
838 $update_done = true;
839 }
840 unset($_POST[$qty]);
841 }
842 }
843
844 if (empty($update_done)) {
845 $line->id = $lines[$i]->id;
846 $line->insertExtraFields();
847 }
848 }
849 }
850
851 unset($_POST["lineid"]);
852
853 if (!$error) {
854 if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
855 // Define output language
856 $outputlangs = $langs;
857 $newlang = '';
858 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && GETPOST('lang_id', 'aZ09')) {
859 $newlang = GETPOST('lang_id', 'aZ09');
860 }
861 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
862 $newlang = $object->thirdparty->default_lang;
863 }
864 if (!empty($newlang)) {
865 $outputlangs = new Translate("", $conf);
866 $outputlangs->setDefaultLang($newlang);
867 }
868
869 $ret = $object->fetch($object->id); // Reload to get new records
870 $object->generateDocument($object->model_pdf, $outputlangs, $hidedetails, $hidedesc, $hideref);
871 }
872 } else {
873 header('Location: '.$_SERVER['PHP_SELF'].'?id='.$object->id); // To redisplay the form being edited
874 exit();
875 }
876 } elseif ($action == 'updateline' && $permissiontoadd && GETPOST('cancel', 'alpha') == $langs->trans("Cancel")) {
877 header('Location: '.$_SERVER['PHP_SELF'].'?id='.$object->id); // To redisplay the form being edited
878 exit();
879 }
880
881 include DOL_DOCUMENT_ROOT.'/core/actions_printing.inc.php';
882
883 // Actions to send emails
884 if (empty($id)) {
885 $id = $facid;
886 }
887 $triggersendname = 'SHIPPING_SENTBYMAIL';
888 $paramname = 'id';
889 $autocopy = 'MAIN_MAIL_AUTOCOPY_SHIPMENT_TO';
890 $mode = 'emailfromshipment';
891 $trackid = 'shi'.$object->id;
892 include DOL_DOCUMENT_ROOT.'/core/actions_sendmails.inc.php';
893}
894
895
896/*
897 * View
898 */
899
900$title = $object->ref.' - '.$langs->trans("Shipment");
901if ($action == 'create2') {
902 $title = $langs->trans("CreateShipment");
903}
904$help_url = 'EN:Module_Shipments|FR:Module_Expéditions|ES:M&oacute;dulo_Expediciones|DE:Modul_Lieferungen';
905
906llxHeader('', $title, $help_url, '', 0, 0, '', '', '', 'mod-expedition page-card');
907
908if (empty($action)) {
909 $action = 'view';
910}
911
912$form = new Form($db);
913$formfile = new FormFile($db);
914$formproduct = new FormProduct($db);
915if (isModEnabled('project')) {
916 $formproject = new FormProjets($db);
917} else {
918 $formproject = null;
919}
920
921$product_static = new Product($db);
922$shipment_static = new Expedition($db);
923$warehousestatic = new Entrepot($db);
924
925if ($action == 'create2') {
926 print load_fiche_titre($langs->trans("CreateShipment"), '', 'dolly');
927
928 print '<br>'.$langs->trans("ShipmentCreationIsDoneFromOrder");
929 $action = '';
930 $id = '';
931 $ref = '';
932}
933
934// Mode creation.
935if ($action == 'create') {
936 $expe = new Expedition($db);
937
938 print load_fiche_titre($langs->trans("CreateShipment"), '', 'dolly');
939
940 if (!$origin) {
941 setEventMessages($langs->trans("ErrorBadParameters"), null, 'errors');
942 }
943
944 if ($origin) {
945 $classname = ucfirst($origin);
946
947 $object = new $classname($db);
948 '@phan-var-force Commande|Facture $object';
949 if ($object->fetch($origin_id)) { // This include the fetch_lines
950 $soc = new Societe($db);
951 $soc->fetch($object->socid);
952
953 $author = new User($db);
954 $author->fetch($object->user_author_id);
955
956 if (isModEnabled('stock')) {
957 $entrepot = new Entrepot($db);
958 }
959
960 print '<form action="'.$_SERVER["PHP_SELF"].'" method="post">';
961 print '<input type="hidden" name="token" value="'.newToken().'">';
962 print '<input type="hidden" name="action" value="add">';
963 print '<input type="hidden" name="origin" value="'.$origin.'">';
964 print '<input type="hidden" name="origin_id" value="'.$object->id.'">';
965 if (GETPOSTINT('entrepot_id')) {
966 print '<input type="hidden" name="entrepot_id" value="'.GETPOSTINT('entrepot_id').'">';
967 }
968
969 print dol_get_fiche_head([]);
970
971 print '<table class="border centpercent">';
972
973 // Ref
974 print '<tr><td class="titlefieldcreate fieldrequired">';
975 if ($origin == 'commande' && isModEnabled('order')) {
976 print $langs->trans("RefOrder");
977 }
978 if ($origin == 'propal' && isModEnabled("propal")) {
979 print $langs->trans("RefProposal");
980 }
981 print '</td><td colspan="3">';
982 print $object->getNomUrl(1);
983 print '</td>';
984 print "</tr>\n";
985
986 // Ref client
987 print '<tr><td>';
988 if ($origin == 'commande') {
989 print $langs->trans('RefCustomerOrder');
990 } elseif ($origin == 'propal') {
991 print $langs->trans('RefCustomerOrder');
992 } else {
993 print $langs->trans('RefCustomer');
994 }
995 print '</td><td colspan="3">';
996 print '<input type="text" name="ref_customer" value="'.$object->ref_client.'" />';
997 print '</td>';
998 print '</tr>';
999
1000 // Tiers
1001 print '<tr><td class="titlefieldcreate fieldrequired">'.$langs->trans('Company').'</td>';
1002 print '<td colspan="3">'.$soc->getNomUrl(1).'</td>';
1003 print '</tr>';
1004
1005 // Project
1006 if (isModEnabled('project') && is_object($formproject)) {
1007 $projectid = GETPOSTINT('projectid') ? GETPOSTINT('projectid') : 0;
1008 if (empty($projectid) && !empty($object->fk_project)) {
1009 $projectid = $object->fk_project;
1010 }
1011 if ($origin == 'project') {
1012 $projectid = ($originid ? $originid : 0);
1013 }
1014
1015 $langs->load("projects");
1016 print '<tr>';
1017 print '<td>'.$langs->trans("Project").'</td><td colspan="2">';
1018 print img_picto('', 'project', 'class="pictofixedwidth"');
1019 $numprojet = $formproject->select_projects($soc->id, $projectid, 'projectid', 0);
1020 print ' <a class="paddingleft" href="'.DOL_URL_ROOT.'/projet/card.php?socid='.$soc->id.'&action=create&status=1&backtopage='.urlencode($_SERVER["PHP_SELF"].'?action=create&socid='.$soc->id).'"><span class="fa fa-plus-circle valignmiddle"></span></a>';
1021 print '</td>';
1022 print '</tr>';
1023 }
1024
1025 // Date delivery planned
1026 print '<tr><td>'.$langs->trans("DateDeliveryPlanned").'</td>';
1027 print '<td colspan="3">';
1028 print img_picto('', 'action', 'class="pictofixedwidth"');
1029 $date_delivery = ($date_delivery ? $date_delivery : $object->delivery_date); // $date_delivery comes from GETPOST
1030 print $form->selectDate($date_delivery ? $date_delivery : -1, 'date_delivery', 1, 1, 1);
1031 print "</td>\n";
1032 print '</tr>';
1033
1034 // Note Public
1035 print '<tr><td>'.$langs->trans("NotePublic").'</td>';
1036 print '<td colspan="3">';
1037 $doleditor = new DolEditor('note_public', $object->note_public, '', 60, 'dolibarr_notes', 'In', false, false, !getDolGlobalString('FCKEDITOR_ENABLE_NOTE_PUBLIC') ? 0 : 1, ROWS_3, '90%');
1038 print $doleditor->Create(1);
1039 print "</td></tr>";
1040
1041 // Note Private
1042 if ($object->note_private && !$user->socid) {
1043 print '<tr><td>'.$langs->trans("NotePrivate").'</td>';
1044 print '<td colspan="3">';
1045 $doleditor = new DolEditor('note_private', $object->note_private, '', 60, 'dolibarr_notes', 'In', false, false, !getDolGlobalString('FCKEDITOR_ENABLE_NOTE_PRIVATE') ? 0 : 1, ROWS_3, '90%');
1046 print $doleditor->Create(1);
1047 print "</td></tr>";
1048 }
1049
1050 // Weight
1051 print '<tr><td>';
1052 print $langs->trans("Weight");
1053 print '</td><td colspan="3">';
1054 print img_picto('', 'fa-balance-scale', 'class="pictofixedwidth"');
1055 print '<input name="weight" size="4" value="'.GETPOSTINT('weight').'"> ';
1056 $text = $formproduct->selectMeasuringUnits("weight_units", "weight", GETPOSTINT('weight_units'), 0, 2);
1057 $htmltext = $langs->trans("KeepEmptyForAutoCalculation");
1058 print $form->textwithpicto($text, $htmltext);
1059 print '</td></tr>';
1060 // Dim
1061 print '<tr><td>';
1062 print $langs->trans("Width").' x '.$langs->trans("Height").' x '.$langs->trans("Depth");
1063 print ' </td><td colspan="3">';
1064 print img_picto('', 'fa-ruler', 'class="pictofixedwidth"');
1065 print '<input name="sizeW" size="4" value="'.GETPOSTINT('sizeW').'">';
1066 print ' x <input name="sizeH" size="4" value="'.GETPOSTINT('sizeH').'">';
1067 print ' x <input name="sizeS" size="4" value="'.GETPOSTINT('sizeS').'">';
1068 print ' ';
1069 $text = $formproduct->selectMeasuringUnits("size_units", "size", GETPOSTINT('size_units'), 0, 2);
1070 $htmltext = $langs->trans("KeepEmptyForAutoCalculation");
1071 print $form->textwithpicto($text, $htmltext);
1072 print '</td></tr>';
1073
1074 // Delivery method
1075 print "<tr><td>".$langs->trans("DeliveryMethod")."</td>";
1076 print '<td colspan="3">';
1077 $expe->fetch_delivery_methods();
1078 print img_picto('', 'dolly', 'class="pictofixedwidth"');
1079 print $form->selectarray("shipping_method_id", $expe->meths, GETPOSTINT('shipping_method_id'), 1, 0, 0, "", 1);
1080 if ($user->admin) {
1081 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
1082 }
1083 print "</td></tr>\n";
1084
1085 // Tracking number
1086 print "<tr><td>".$langs->trans("TrackingNumber")."</td>";
1087 print '<td colspan="3">';
1088 print img_picto('', 'barcode', 'class="pictofixedwidth"');
1089 print '<input name="tracking_number" size="20" value="'.GETPOST('tracking_number', 'alpha').'">';
1090 print "</td></tr>\n";
1091
1092 // Other attributes
1093 $parameters = array('objectsrc' => isset($objectsrc) ? $objectsrc : '', 'colspan' => ' colspan="3"', 'cols' => '3', 'socid' => $socid);
1094 $reshook = $hookmanager->executeHooks('formObjectOptions', $parameters, $expe, $action); // Note that $action and $object may have been modified by hook
1095 print $hookmanager->resPrint;
1096
1097 if (empty($reshook)) {
1098 // copy from order
1099 if ($object->fetch_optionals() > 0) {
1100 $expe->array_options = array_merge($expe->array_options, $object->array_options);
1101 }
1102 print $expe->showOptionals($extrafields, 'edit', $parameters);
1103 }
1104
1105
1106 // Incoterms
1107 if (isModEnabled('incoterm')) {
1108 print '<tr>';
1109 print '<td><label for="incoterm_id">'.$form->textwithpicto($langs->trans("IncotermLabel"), $object->label_incoterms, 1).'</label></td>';
1110 print '<td colspan="3" class="maxwidthonsmartphone">';
1111 print img_picto('', 'incoterm', 'class="pictofixedwidth"');
1112 print $form->select_incoterms((!empty($object->fk_incoterms) ? $object->fk_incoterms : ''), (!empty($object->location_incoterms) ? $object->location_incoterms : ''));
1113 print '</td></tr>';
1114 }
1115
1116 // Document model
1117 include_once DOL_DOCUMENT_ROOT.'/core/modules/expedition/modules_expedition.php';
1119 if (is_countable($list) && count($list) > 1) {
1120 print "<tr><td>".$langs->trans("DefaultModel")."</td>";
1121 print '<td colspan="3">';
1122 print img_picto('', 'pdf', 'class="pictofixedwidth"');
1123 print $form->selectarray('model', $list, $conf->global->EXPEDITION_ADDON_PDF);
1124 print "</td></tr>\n";
1125 }
1126
1127 print "</table>";
1128
1129 print dol_get_fiche_end();
1130
1131
1132 // Shipment lines
1133
1134 $numAsked = count($object->lines);
1135
1136 print '<script type="text/javascript">'."\n";
1137 print 'jQuery(document).ready(function() {'."\n";
1138 print 'jQuery("#autofill").click(function() {';
1139 $i = 0;
1140 while ($i < $numAsked) {
1141 print 'jQuery("#qtyl'.$i.'").val(jQuery("#qtyasked'.$i.'").val() - jQuery("#qtydelivered'.$i.'").val());'."\n";
1142 if (isModEnabled('productbatch')) {
1143 print 'jQuery("#qtyl'.$i.'_'.$i.'").val(jQuery("#qtyasked'.$i.'").val() - jQuery("#qtydelivered'.$i.'").val());'."\n";
1144 }
1145 $i++;
1146 }
1147 print 'return false; });'."\n";
1148 print 'jQuery("#autoreset").click(function() { console.log("Reset values to 0"); jQuery(".qtyl").val(0);'."\n";
1149 print 'return false; });'."\n";
1150 print '});'."\n";
1151 print '</script>'."\n";
1152
1153 print '<br>';
1154
1155 print '<table class="noborder centpercent">';
1156
1157 // Load shipments already done for same order
1158 $object->loadExpeditions();
1159
1160
1161 $alreadyQtyBatchSetted = $alreadyQtySetted = array();
1162
1163 if ($numAsked) {
1164 print '<tr class="liste_titre">';
1165 print '<td>'.$langs->trans("Description").'</td>';
1166 print '<td class="center">'.$langs->trans("QtyOrdered").'</td>';
1167 print '<td class="center">'.$langs->trans("QtyShipped").'</td>';
1168 print '<td class="center">'.$langs->trans("QtyToShip");
1169 if (empty($conf->productbatch->enabled)) {
1170 print '<br><a href="#" id="autofill" class="opacitymedium link cursor cursorpointer">'.img_picto($langs->trans("Autofill"), 'autofill', 'class="paddingrightonly"').'</a>';
1171 print ' / ';
1172 } else {
1173 print '<br>';
1174 }
1175 print '<span id="autoreset" class="opacitymedium link cursor cursorpointer">'.img_picto($langs->trans("Reset"), 'eraser').'</span>';
1176 print '</td>';
1177 if (isModEnabled('stock')) {
1178 if (empty($conf->productbatch->enabled)) {
1179 print '<td class="left">'.$langs->trans("Warehouse").' ('.$langs->trans("Stock").')</td>';
1180 } else {
1181 print '<td class="left">'.$langs->trans("Warehouse").' / '.$langs->trans("Batch").' ('.$langs->trans("Stock").')</td>';
1182 }
1183 }
1184 if (getDolGlobalString('SHIPPING_DISPLAY_STOCK_ENTRY_DATE')) {
1185 print '<td class="left">'.$langs->trans('StockEntryDate').'</td>';
1186 }
1187 print "</tr>\n";
1188 }
1189
1190 $warehouse_id = GETPOSTINT('entrepot_id');
1191 $warehousePicking = array();
1192 // get all warehouse children for picking
1193 if ($warehouse_id > 0) {
1194 $warehousePicking[] = $warehouse_id;
1195 $warehouseObj = new Entrepot($db);
1196 $warehouseObj->get_children_warehouses($warehouse_id, $warehousePicking);
1197 }
1198
1199 $indiceAsked = 0;
1200 while ($indiceAsked < $numAsked) {
1201 $product = new Product($db);
1202
1203 $line = $object->lines[$indiceAsked];
1204
1205 $parameters = array('i' => $indiceAsked, 'line' => $line, 'num' => $numAsked);
1206 $reshook = $hookmanager->executeHooks('printObjectLine', $parameters, $object, $action);
1207 if ($reshook < 0) {
1208 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
1209 }
1210
1211 if (empty($reshook)) {
1212 // Show product and description
1213 $type = $line->product_type ? $line->product_type : $line->fk_product_type;
1214 // Try to enhance type detection using date_start and date_end for free lines where type
1215 // was not saved.
1216 if (!empty($line->date_start)) {
1217 $type = 1;
1218 }
1219 if (!empty($line->date_end)) {
1220 $type = 1;
1221 }
1222
1223 print '<!-- line for order line '.$line->id.' -->'."\n";
1224 print '<tr class="oddeven" id="row-'.$line->id.'">'."\n";
1225
1226 // Product label
1227 if ($line->fk_product > 0) { // If predefined product
1228 $res = $product->fetch($line->fk_product);
1229 if ($res < 0) {
1230 dol_print_error($db, $product->error, $product->errors);
1231 }
1232 $product->load_stock('warehouseopen'); // Load all $product->stock_warehouse[idwarehouse]->detail_batch
1233 //var_dump($product->stock_warehouse[1]);
1234
1235 print '<td>';
1236 print '<a name="'.$line->id.'"></a>'; // ancre pour retourner sur la ligne
1237
1238 // Show product and description
1239 $product_static->type = $line->fk_product_type;
1240 $product_static->id = $line->fk_product;
1241 $product_static->ref = $line->ref;
1242 $product_static->status = $line->product_tosell;
1243 $product_static->status_buy = $line->product_tobuy;
1244 $product_static->status_batch = $line->product_tobatch;
1245
1246 $showdescinproductdesc = getDolGlobalString('PRODUIT_DESC_IN_FORM_ACCORDING_TO_DEVICE');
1247
1248 $text = $product_static->getNomUrl(1);
1249 $text .= ' - '.(!empty($line->label) ? $line->label : $line->product_label);
1250 $description = ($showdescinproductdesc ? '' : dol_htmlentitiesbr($line->desc));
1251
1252 print $form->textwithtooltip($text, $description, 3, 0, '', $i);
1253
1254 // Show range
1255 print_date_range($db->jdate($line->date_start), $db->jdate($line->date_end));
1256
1257 // Add description in form
1258 if ($showdescinproductdesc) {
1259 print ($line->desc && $line->desc != $line->product_label) ? '<br>'.dol_htmlentitiesbr($line->desc) : '';
1260 }
1261
1262 print '</td>';
1263 } else {
1264 print "<td>";
1265 if ($type == 1) {
1266 $text = img_object($langs->trans('Service'), 'service');
1267 } else {
1268 $text = img_object($langs->trans('Product'), 'product');
1269 }
1270
1271 if (!empty($line->label)) {
1272 $text .= ' <strong>'.$line->label.'</strong>';
1273 print $form->textwithtooltip($text, $line->desc, 3, 0, '', $i);
1274 } else {
1275 print $text.' '.nl2br($line->desc);
1276 }
1277
1278 // Show range
1279 print_date_range($db->jdate($line->date_start), $db->jdate($line->date_end));
1280 print "</td>\n";
1281 }
1282
1283 // unit of order
1284 $unit_order = '';
1285 if (getDolGlobalString('PRODUCT_USE_UNITS')) {
1286 $unit_order = measuringUnitString($line->fk_unit);
1287 }
1288
1289 // Qty
1290 print '<td class="center">'.$line->qty;
1291 print '<input name="qtyasked'.$indiceAsked.'" id="qtyasked'.$indiceAsked.'" type="hidden" value="'.$line->qty.'">';
1292 print ''.$unit_order.'</td>';
1293 $qtyProdCom = $line->qty;
1294
1295 // Qty already shipped
1296 print '<td class="center">';
1297 $quantityDelivered = isset($object->expeditions[$line->id]) ? $object->expeditions[$line->id] : '';
1298 print $quantityDelivered;
1299 print '<input name="qtydelivered'.$indiceAsked.'" id="qtydelivered'.$indiceAsked.'" type="hidden" value="'.$quantityDelivered.'">';
1300 print ''.$unit_order.'</td>';
1301
1302 // Qty to ship
1303 $quantityAsked = $line->qty;
1304 if ($line->product_type == 1 && !getDolGlobalString('STOCK_SUPPORTS_SERVICES') && !getDolGlobalString('SHIPMENT_SUPPORTS_SERVICES')) {
1305 $quantityToBeDelivered = 0;
1306 } else {
1307 if (is_numeric($quantityDelivered)) {
1308 $quantityToBeDelivered = $quantityAsked - $quantityDelivered;
1309 } else {
1310 $quantityToBeDelivered = $quantityAsked;
1311 }
1312 }
1313
1314 $warehouseObject = null;
1315 if (count($warehousePicking) == 1 || !($line->fk_product > 0) || !isModEnabled('stock')) { // If warehouse was already selected or if product is not a predefined, we go into this part with no multiwarehouse selection
1316 print '<!-- Case warehouse already known or product not a predefined product -->';
1317 //ship from preselected location
1318 $stock = + (isset($product->stock_warehouse[$warehouse_id]->real) ? $product->stock_warehouse[$warehouse_id]->real : 0); // Convert to number
1319 if ($line->product_type == Product::TYPE_SERVICE && getDolGlobalString('SHIPMENT_SUPPORTS_SERVICES')) {
1320 $deliverableQty = $quantityToBeDelivered;
1321 } else {
1322 $deliverableQty = min($quantityToBeDelivered, $stock);
1323 }
1324 if ($deliverableQty < 0) {
1325 $deliverableQty = 0;
1326 }
1327 if (empty($conf->productbatch->enabled) || !$product->hasbatch()) {
1328 // Quantity to send
1329 print '<td class="center">';
1330 if ($line->product_type == Product::TYPE_PRODUCT || getDolGlobalString('STOCK_SUPPORTS_SERVICES') || ($line->product_type == Product::TYPE_SERVICE && getDolGlobalString('SHIPMENT_SUPPORTS_SERVICES'))) {
1331 if (GETPOSTINT('qtyl'.$indiceAsked)) {
1332 $deliverableQty = GETPOSTINT('qtyl'.$indiceAsked);
1333 }
1334 print '<input name="idl'.$indiceAsked.'" type="hidden" value="'.$line->id.'">';
1335 print '<input name="qtyl'.$indiceAsked.'" id="qtyl'.$indiceAsked.'" class="qtyl right" type="text" size="4" value="'.$deliverableQty.'">';
1336 } else {
1337 if (getDolGlobalString('SHIPMENT_GETS_ALL_ORDER_PRODUCTS')) {
1338 print '<input name="idl'.$indiceAsked.'" type="hidden" value="'.$line->id.'">';
1339 print '<input name="qtyl'.$indiceAsked.'" id="qtyl'.$indiceAsked.'" type="hidden" value="0">';
1340 }
1341
1342 print $langs->trans("NA");
1343 }
1344 print '</td>';
1345
1346 // Stock
1347 if (isModEnabled('stock')) {
1348 print '<td class="left">';
1349 if ($line->product_type == Product::TYPE_PRODUCT || getDolGlobalString('STOCK_SUPPORTS_SERVICES')) { // Type of product need stock change ?
1350 // Show warehouse combo list
1351 $ent = "entl".$indiceAsked;
1352 $idl = "idl".$indiceAsked;
1353 $tmpentrepot_id = is_numeric(GETPOST($ent)) ? GETPOSTINT($ent) : $warehouse_id;
1354 if ($line->fk_product > 0) {
1355 print '<!-- Show warehouse selection -->';
1356
1357 $stockMin = false;
1358 if (!getDolGlobalInt('STOCK_ALLOW_NEGATIVE_TRANSFER')) {
1359 $stockMin = 0;
1360 }
1361 print $formproduct->selectWarehouses($tmpentrepot_id, 'entl'.$indiceAsked, '', 1, 0, $line->fk_product, '', 1, 0, array(), 'minwidth200', array(), 1, $stockMin, 'stock DESC, e.ref');
1362
1363 if ($tmpentrepot_id > 0 && $tmpentrepot_id == $warehouse_id) {
1364 //print $stock.' '.$quantityToBeDelivered;
1365 if ($stock < $quantityToBeDelivered) {
1366 print ' '.img_warning($langs->trans("StockTooLow")); // Stock too low for this $warehouse_id but you can change warehouse
1367 }
1368 }
1369 }
1370 } else {
1371 print '<span class="opacitymedium">('.$langs->trans("Service").')</span><input name="entl'.$indiceAsked.'" id="entl'.$indiceAsked.'" type="hidden" value="0">';
1372 }
1373 print '</td>';
1374 }
1375 if (getDolGlobalString('SHIPPING_DISPLAY_STOCK_ENTRY_DATE')) {
1376 print '<td></td>';
1377 } //StockEntrydate
1378 print "</tr>\n";
1379
1380 // Show subproducts of product
1381 if (getDolGlobalString('PRODUIT_SOUSPRODUITS') && $line->fk_product > 0) {
1382 $product->get_sousproduits_arbo();
1383 $prods_arbo = $product->get_arbo_each_prod($qtyProdCom);
1384 if (count($prods_arbo) > 0) {
1385 foreach ($prods_arbo as $key => $value) {
1386 //print $value[0];
1387 $img = '';
1388 if ($value['stock'] < $value['stock_alert']) {
1389 $img = img_warning($langs->trans("StockTooLow"));
1390 }
1391 print "<tr class=\"oddeven\"><td>&nbsp; &nbsp; &nbsp; ->
1392 <a href=\"".DOL_URL_ROOT."/product/card.php?id=".$value['id']."\">".$value['fullpath']."
1393 </a> (".$value['nb'].")</td><td class=\"center\"> ".$value['nb_total']."</td><td>&nbsp;</td><td>&nbsp;</td>
1394 <td class=\"center\">".$value['stock']." ".$img."</td>";
1395 if (getDolGlobalString('SHIPPING_DISPLAY_STOCK_ENTRY_DATE')) {
1396 print '<td></td>';
1397 } //StockEntrydate
1398 print "</tr>";
1399 }
1400 }
1401 }
1402 } else {
1403 // Product need lot
1404 print '<td></td><td></td>';
1405 if (getDolGlobalString('SHIPPING_DISPLAY_STOCK_ENTRY_DATE')) {
1406 print '<td></td>';
1407 } //StockEntrydate
1408 print '</tr>'; // end line and start a new one for lot/serial
1409 print '<!-- Case product need lot -->';
1410
1411 $staticwarehouse = new Entrepot($db);
1412 if ($warehouse_id > 0) {
1413 $staticwarehouse->fetch($warehouse_id);
1414 }
1415
1416 $subj = 0;
1417 // Define nb of lines suggested for this order line
1418 $nbofsuggested = 0;
1419 if (is_object($product->stock_warehouse[$warehouse_id]) && count($product->stock_warehouse[$warehouse_id]->detail_batch)) {
1420 foreach ($product->stock_warehouse[$warehouse_id]->detail_batch as $dbatch) {
1421 $nbofsuggested++;
1422 }
1423 }
1424 print '<input name="idl'.$indiceAsked.'" type="hidden" value="'.$line->id.'">';
1425 if (is_object($product->stock_warehouse[$warehouse_id]) && count($product->stock_warehouse[$warehouse_id]->detail_batch)) {
1426 foreach ($product->stock_warehouse[$warehouse_id]->detail_batch as $dbatch) { // $dbatch is instance of Productbatch
1427 //var_dump($dbatch);
1428 $batchStock = + $dbatch->qty; // To get a numeric
1429 $deliverableQty = min($quantityToBeDelivered, $batchStock);
1430
1431 // Now we will check if we have to reduce the deliverableQty by taking into account the qty already suggested in previous line
1432 if (isset($alreadyQtyBatchSetted[$line->fk_product][$dbatch->batch][intval($warehouse_id)])) {
1433 $deliverableQty = min($quantityToBeDelivered, $batchStock - $alreadyQtyBatchSetted[$line->fk_product][$dbatch->batch][intval($warehouse_id)]);
1434 } else {
1435 if (!isset($alreadyQtyBatchSetted[$line->fk_product])) {
1436 $alreadyQtyBatchSetted[$line->fk_product] = array();
1437 }
1438
1439 if (!isset($alreadyQtyBatchSetted[$line->fk_product][$dbatch->batch])) {
1440 $alreadyQtyBatchSetted[$line->fk_product][$dbatch->batch] = array();
1441 }
1442
1443 $deliverableQty = min($quantityToBeDelivered, $batchStock);
1444 }
1445
1446 if ($deliverableQty < 0) {
1447 $deliverableQty = 0;
1448 }
1449
1450 $inputName = 'qtyl'.$indiceAsked.'_'.$subj;
1451 if (GETPOSTISSET($inputName)) {
1452 $deliverableQty = GETPOST($inputName, 'int');
1453 }
1454
1455 $tooltipClass = $tooltipTitle = '';
1456 if (!empty($alreadyQtyBatchSetted[$line->fk_product][$dbatch->batch][intval($warehouse_id)])) {
1457 $tooltipClass = ' classfortooltip';
1458 $tooltipTitle = $langs->trans('StockQuantitiesAlreadyAllocatedOnPreviousLines').' : '.$alreadyQtyBatchSetted[$line->fk_product][$dbatch->batch][intval($warehouse_id)];
1459 } else {
1460 $alreadyQtyBatchSetted[$line->fk_product][$dbatch->batch][intval($warehouse_id)] = 0 ;
1461 }
1462 $alreadyQtyBatchSetted[$line->fk_product][$dbatch->batch][intval($warehouse_id)] = $deliverableQty + $alreadyQtyBatchSetted[$line->fk_product][$dbatch->batch][intval($warehouse_id)];
1463
1464 print '<!-- subj='.$subj.'/'.$nbofsuggested.' --><tr '.((($subj + 1) == $nbofsuggested) ? 'oddeven' : '').'>';
1465 print '<td colspan="3" ></td><td class="center">';
1466 print '<input class="qtyl '.$tooltipClass.' right" title="'.$tooltipTitle.'" name="qtyl'.$indiceAsked.'_'.$subj.'" id="qtyl'.$indiceAsked.'_'.$subj.'" type="text" size="4" value="'.$deliverableQty.'">';
1467 print '</td>';
1468
1469 print '<!-- Show details of lot -->';
1470 print '<td class="left">';
1471
1472 print $staticwarehouse->getNomUrl(0).' / ';
1473
1474 print '<input name="batchl'.$indiceAsked.'_'.$subj.'" type="hidden" value="'.$dbatch->id.'">';
1475
1476 $detail = '';
1477 $detail .= $langs->trans("Batch").': '.$dbatch->batch;
1478 if (!getDolGlobalString('PRODUCT_DISABLE_SELLBY') && !empty($dbatch->sellby)) {
1479 $detail .= ' - '.$langs->trans("SellByDate").': '.dol_print_date($dbatch->sellby, "day");
1480 }
1481 if (!getDolGlobalString('PRODUCT_DISABLE_EATBY') && !empty($dbatch->eatby)) {
1482 $detail .= ' - '.$langs->trans("EatByDate").': '.dol_print_date($dbatch->eatby, "day");
1483 }
1484 $detail .= ' - '.$langs->trans("Qty").': '.$dbatch->qty;
1485 $detail .= '<br>';
1486 print $detail;
1487
1488 $quantityToBeDelivered -= $deliverableQty;
1489 if ($quantityToBeDelivered < 0) {
1490 $quantityToBeDelivered = 0;
1491 }
1492 $subj++;
1493 print '</td>';
1494 if (getDolGlobalInt('SHIPPING_DISPLAY_STOCK_ENTRY_DATE')) {
1495 print '<td>'.dol_print_date($dbatch->context['stock_entry_date'], 'day').'</td>'; //StockEntrydate
1496 }
1497 print '</tr>';
1498 }
1499 } else {
1500 print '<!-- Case there is no details of lot at all -->';
1501 print '<tr class="oddeven"><td colspan="3"></td><td class="center">';
1502 print '<input class="qtyl right" name="qtyl'.$indiceAsked.'_'.$subj.'" id="qtyl'.$indiceAsked.'_'.$subj.'" type="text" size="4" value="0" disabled="disabled"> ';
1503 print '</td>';
1504
1505 print '<td class="left">';
1506 print img_warning().' '.$langs->trans("NoProductToShipFoundIntoStock", $staticwarehouse->label);
1507 print '</td>';
1508 if (getDolGlobalInt('SHIPPING_DISPLAY_STOCK_ENTRY_DATE')) {
1509 print '<td></td>';
1510 } //StockEntrydate
1511 print '</tr>';
1512 }
1513 }
1514 } else {
1515 // ship from multiple locations
1516 if (empty($conf->productbatch->enabled) || !$product->hasbatch()) {
1517 print '<!-- Case warehouse not already known and product does not need lot -->';
1518 print '<td></td><td></td>';
1519 if (getDolGlobalString('SHIPPING_DISPLAY_STOCK_ENTRY_DATE')) {
1520 print '<td></td>';
1521 }//StockEntrydate
1522 print '</tr>'."\n"; // end line and start a new one for each warehouse
1523
1524 print '<input name="idl'.$indiceAsked.'" type="hidden" value="'.$line->id.'">';
1525 $subj = 0;
1526 // Define nb of lines suggested for this order line
1527 $nbofsuggested = 0;
1528
1529 foreach ($product->stock_warehouse as $warehouse_id => $stock_warehouse) {
1530 if ($stock_warehouse->real > 0 || !empty($conf->global->STOCK_ALLOW_NEGATIVE_TRANSFER)) {
1531 $nbofsuggested++;
1532 }
1533 }
1534 $tmpwarehouseObject = new Entrepot($db);
1535 foreach ($product->stock_warehouse as $warehouse_id => $stock_warehouse) { // $stock_warehouse is product_stock
1536 $var = $subj % 2;
1537 if (!empty($warehousePicking) && !in_array($warehouse_id, $warehousePicking)) {
1538 // if a warehouse was selected by user, picking is limited to this warehouse and his children
1539 continue;
1540 }
1541
1542 $tmpwarehouseObject->fetch($warehouse_id);
1543 if ($stock_warehouse->real > 0 || !empty($conf->global->STOCK_ALLOW_NEGATIVE_TRANSFER)) {
1544 $stock = + $stock_warehouse->real; // Convert it to number
1545 $deliverableQty = min($quantityToBeDelivered, $stock);
1546 $deliverableQty = max(0, $deliverableQty);
1547 // Quantity to send
1548 print '<!-- subj='.$subj.'/'.$nbofsuggested.' --><tr '.((($subj + 1) == $nbofsuggested) ? 'oddeven' : '').'>';
1549 print '<td colspan="3" ></td><td class="center"><!-- qty to ship (no lot management for product line indiceAsked='.$indiceAsked.') -->';
1550 if ($line->product_type == Product::TYPE_PRODUCT || getDolGlobalString('STOCK_SUPPORTS_SERVICES') || getDolGlobalString('SHIPMENT_SUPPORTS_SERVICES')) {
1551 if (isset($alreadyQtySetted[$line->fk_product][intval($warehouse_id)])) {
1552 $deliverableQty = min($quantityToBeDelivered, $stock - $alreadyQtySetted[$line->fk_product][intval($warehouse_id)]);
1553 } else {
1554 if (!isset($alreadyQtySetted[$line->fk_product])) {
1555 $alreadyQtySetted[$line->fk_product] = array();
1556 }
1557
1558 $deliverableQty = min($quantityToBeDelivered, $stock);
1559 }
1560
1561 if ($deliverableQty < 0) {
1562 $deliverableQty = 0;
1563 }
1564
1565 $tooltipClass = $tooltipTitle = '';
1566 if (!empty($alreadyQtySetted[$line->fk_product][intval($warehouse_id)])) {
1567 $tooltipClass = ' classfortooltip';
1568 $tooltipTitle = $langs->trans('StockQuantitiesAlreadyAllocatedOnPreviousLines').' : '.$alreadyQtySetted[$line->fk_product][intval($warehouse_id)];
1569 } else {
1570 $alreadyQtySetted[$line->fk_product][intval($warehouse_id)] = 0;
1571 }
1572
1573 $alreadyQtySetted[$line->fk_product][intval($warehouse_id)] = $deliverableQty + $alreadyQtySetted[$line->fk_product][intval($warehouse_id)];
1574
1575 $inputName = 'qtyl'.$indiceAsked.'_'.$subj;
1576 if (GETPOSTISSET($inputName)) {
1577 $deliverableQty = GETPOSTINT($inputName);
1578 }
1579
1580 print '<input class="qtyl'.$tooltipClass.' right" title="'.$tooltipTitle.'" name="qtyl'.$indiceAsked.'_'.$subj.'" id="qtyl'.$indiceAsked.'" type="text" size="4" value="'.$deliverableQty.'">';
1581 print '<input name="ent1'.$indiceAsked.'_'.$subj.'" type="hidden" value="'.$warehouse_id.'">';
1582 } else {
1583 if (getDolGlobalString('SHIPMENT_GETS_ALL_ORDER_PRODUCTS')) {
1584 print '<input name="qtyl'.$indiceAsked.'_'.$subj.'" id="qtyl'.$indiceAsked.'" type="hidden" value="0">';
1585 }
1586
1587 print $langs->trans("NA");
1588 }
1589 print '</td>';
1590
1591 // Stock
1592 if (isModEnabled('stock')) {
1593 print '<td class="left">';
1594 if ($line->product_type == Product::TYPE_PRODUCT || getDolGlobalString('STOCK_SUPPORTS_SERVICES')) {
1595 print $tmpwarehouseObject->getNomUrl(0).' ';
1596
1597 print '<!-- Show details of stock -->';
1598 print '('.$stock.')';
1599 } else {
1600 print '<span class="opacitymedium">('.$langs->trans("Service").')</span>';
1601 }
1602 print '</td>';
1603 }
1604 $quantityToBeDelivered -= $deliverableQty;
1605 if ($quantityToBeDelivered < 0) {
1606 $quantityToBeDelivered = 0;
1607 }
1608 $subj++;
1609 if (getDolGlobalString('SHIPPING_DISPLAY_STOCK_ENTRY_DATE')) {
1610 print '<td></td>';
1611 }//StockEntrydate
1612 print "</tr>\n";
1613 }
1614 }
1615 // Show subproducts of product (not recommended)
1616 if (getDolGlobalString('PRODUIT_SOUSPRODUITS') && $line->fk_product > 0) {
1617 $product->get_sousproduits_arbo();
1618 $prods_arbo = $product->get_arbo_each_prod($qtyProdCom);
1619 if (count($prods_arbo) > 0) {
1620 foreach ($prods_arbo as $key => $value) {
1621 //print $value[0];
1622 $img = '';
1623 if ($value['stock'] < $value['stock_alert']) {
1624 $img = img_warning($langs->trans("StockTooLow"));
1625 }
1626 print '<tr class"oddeven"><td>';
1627 print "&nbsp; &nbsp; &nbsp; ->
1628 <a href=\"".DOL_URL_ROOT."/product/card.php?id=".$value['id']."\">".$value['fullpath']."
1629 </a> (".$value['nb'].")</td><td class=\"center\"> ".$value['nb_total']."</td><td>&nbsp;</td><td>&nbsp;</td>
1630 <td class=\"center\">".$value['stock']." ".$img."</td>";
1631 if (getDolGlobalString('SHIPPING_DISPLAY_STOCK_ENTRY_DATE')) {
1632 print '<td></td>';
1633 }//StockEntrydate
1634 print "</tr>";
1635 }
1636 }
1637 }
1638 } else {
1639 print '<!-- Case warehouse not already known and product need lot -->';
1640 print '<td></td><td></td>';
1641 if (getDolGlobalString('SHIPPING_DISPLAY_STOCK_ENTRY_DATE')) {
1642 print '<td></td>';
1643 }//StockEntrydate
1644 print '</tr>'; // end line and start a new one for lot/serial
1645
1646 $subj = 0;
1647 print '<input name="idl'.$indiceAsked.'" type="hidden" value="'.$line->id.'">';
1648
1649 $tmpwarehouseObject = new Entrepot($db);
1650 $productlotObject = new Productlot($db);
1651
1652 // Define nb of lines suggested for this order line
1653 $nbofsuggested = 0;
1654 foreach ($product->stock_warehouse as $warehouse_id => $stock_warehouse) {
1655 if (($stock_warehouse->real > 0 || !empty($conf->global->STOCK_ALLOW_NEGATIVE_TRANSFER)) && (count($stock_warehouse->detail_batch))) {
1656 $nbofsuggested += count($stock_warehouse->detail_batch);
1657 }
1658 }
1659
1660 foreach ($product->stock_warehouse as $warehouse_id => $stock_warehouse) {
1661 $var = $subj % 2;
1662 if (!empty($warehousePicking) && !in_array($warehouse_id, $warehousePicking)) {
1663 // if a warehouse was selected by user, picking is limited to this warehouse and his children
1664 continue;
1665 }
1666
1667 $tmpwarehouseObject->fetch($warehouse_id);
1668 if (($stock_warehouse->real > 0 || !empty($conf->global->STOCK_ALLOW_NEGATIVE_TRANSFER)) && (count($stock_warehouse->detail_batch))) {
1669 foreach ($stock_warehouse->detail_batch as $dbatch) {
1670 $batchStock = + $dbatch->qty; // To get a numeric
1671 if (isset($alreadyQtyBatchSetted[$line->fk_product][$dbatch->batch][intval($warehouse_id)])) {
1672 $deliverableQty = min($quantityToBeDelivered, $batchStock - $alreadyQtyBatchSetted[$line->fk_product][$dbatch->batch][intval($warehouse_id)]);
1673 } else {
1674 if (!isset($alreadyQtyBatchSetted[$line->fk_product])) {
1675 $alreadyQtyBatchSetted[$line->fk_product] = array();
1676 }
1677
1678 if (!isset($alreadyQtyBatchSetted[$line->fk_product][$dbatch->batch])) {
1679 $alreadyQtyBatchSetted[$line->fk_product][$dbatch->batch] = array();
1680 }
1681
1682 $deliverableQty = min($quantityToBeDelivered, $batchStock);
1683 }
1684
1685 if ($deliverableQty < 0) {
1686 $deliverableQty = 0;
1687 }
1688
1689 $inputName = 'qtyl'.$indiceAsked.'_'.$subj;
1690 if (GETPOSTISSET($inputName)) {
1691 $deliverableQty = GETPOSTINT($inputName);
1692 }
1693
1694 $tooltipClass = $tooltipTitle = '';
1695 if (!empty($alreadyQtyBatchSetted[$line->fk_product][$dbatch->batch][intval($warehouse_id)])) {
1696 $tooltipClass = ' classfortooltip';
1697 $tooltipTitle = $langs->trans('StockQuantitiesAlreadyAllocatedOnPreviousLines').' : '.$alreadyQtyBatchSetted[$line->fk_product][$dbatch->batch][intval($warehouse_id)];
1698 } else {
1699 $alreadyQtyBatchSetted[$line->fk_product][$dbatch->batch][intval($warehouse_id)] = 0 ;
1700 }
1701 $alreadyQtyBatchSetted[$line->fk_product][$dbatch->batch][intval($warehouse_id)] = $deliverableQty + $alreadyQtyBatchSetted[$line->fk_product][$dbatch->batch][intval($warehouse_id)];
1702
1703 print '<!-- subj='.$subj.'/'.$nbofsuggested.' --><tr '.((($subj + 1) == $nbofsuggested) ? 'oddeven' : '').'><td colspan="3"></td><td class="center">';
1704 print '<input class="qtyl right '.$tooltipClass.'" title="'.$tooltipTitle.'" name="'.$inputName.'" id="'.$inputName.'" type="text" size="4" value="'.$deliverableQty.'">';
1705 print '</td>';
1706
1707 print '<td class="left">';
1708
1709 print $tmpwarehouseObject->getNomUrl(0).' / ';
1710
1711 print '<!-- Show details of lot -->';
1712 print '<input name="batchl'.$indiceAsked.'_'.$subj.'" type="hidden" value="'.$dbatch->id.'">';
1713
1714 //print '|'.$line->fk_product.'|'.$dbatch->batch.'|<br>';
1715 print $langs->trans("Batch").': ';
1716 $result = $productlotObject->fetch(0, $line->fk_product, $dbatch->batch);
1717 if ($result > 0) {
1718 print $productlotObject->getNomUrl(1);
1719 } else {
1720 print $langs->trans("TableLotIncompleteRunRepairWithParamStandardEqualConfirmed");
1721 }
1722 if (!getDolGlobalString('PRODUCT_DISABLE_SELLBY') && !empty($dbatch->sellby)) {
1723 print ' - '.$langs->trans("SellByDate").': '.dol_print_date($dbatch->sellby, "day");
1724 }
1725 if (!getDolGlobalString('PRODUCT_DISABLE_EATBY') && !empty($dbatch->eatby)) {
1726 print ' - '.$langs->trans("EatByDate").': '.dol_print_date($dbatch->eatby, "day");
1727 }
1728 print ' ('.$dbatch->qty.')';
1729 $quantityToBeDelivered -= $deliverableQty;
1730 if ($quantityToBeDelivered < 0) {
1731 $quantityToBeDelivered = 0;
1732 }
1733 //dol_syslog('deliverableQty = '.$deliverableQty.' batchStock = '.$batchStock);
1734 $subj++;
1735 print '</td>';
1736 if (getDolGlobalString('SHIPPING_DISPLAY_STOCK_ENTRY_DATE')) {
1737 print '<td class="left">'.dol_print_date($dbatch->context['stock_entry_date'], 'day').'</td>';
1738 }
1739 print '</tr>';
1740 }
1741 }
1742 }
1743 }
1744 if ($subj == 0) { // Line not shown yet, we show it
1745 $warehouse_selected_id = GETPOSTINT('entrepot_id');
1746
1747 print '<!-- line not shown yet, we show it -->';
1748 print '<tr class="oddeven"><td colspan="3"></td><td class="center">';
1749
1750 if ($line->product_type == Product::TYPE_PRODUCT || getDolGlobalString('STOCK_SUPPORTS_SERVICES')) {
1751 $disabled = '';
1752 if (isModEnabled('productbatch') && $product->hasbatch()) {
1753 $disabled = 'disabled="disabled"';
1754 }
1755 if ($warehouse_selected_id <= 0) { // We did not force a given warehouse, so we won't have no warehouse to change qty.
1756 $disabled = 'disabled="disabled"';
1757 }
1758 print '<input class="qtyl right" name="qtyl'.$indiceAsked.'_'.$subj.'" id="qtyl'.$indiceAsked.'_'.$subj.'" type="text" size="4" value="0"'.($disabled ? ' '.$disabled : '').'> ';
1759 if (empty($disabled) && getDolGlobalString('STOCK_ALLOW_NEGATIVE_TRANSFER')) {
1760 print '<input name="ent1' . $indiceAsked . '_' . $subj . '" type="hidden" value="' . $warehouse_selected_id . '">';
1761 }
1762 } elseif ($line->product_type == Product::TYPE_SERVICE && getDolGlobalString('SHIPMENT_SUPPORTS_SERVICES')) {
1763 $disabled = '';
1764 if (isModEnabled('productbatch') && $product->hasbatch()) {
1765 $disabled = 'disabled="disabled"';
1766 }
1767 if ($warehouse_selected_id <= 0) { // We did not force a given warehouse, so we won't have no warehouse to change qty.
1768 $disabled = 'disabled="disabled"';
1769 }
1770 print '<input class="qtyl right" name="qtyl'.$indiceAsked.'_'.$subj.'" id="qtyl'.$indiceAsked.'_'.$subj.'" type="text" size="4" value="'.$quantityToBeDelivered.'"'.($disabled ? ' '.$disabled : '').'> ';
1771 if (empty($disabled) && getDolGlobalString('STOCK_ALLOW_NEGATIVE_TRANSFER')) {
1772 print '<input name="ent1' . $indiceAsked . '_' . $subj . '" type="hidden" value="' . $warehouse_selected_id . '">';
1773 }
1774 } else {
1775 print $langs->trans("NA");
1776 }
1777 print '</td>';
1778
1779 print '<td class="left">';
1780 if ($line->product_type == Product::TYPE_PRODUCT || getDolGlobalString('STOCK_SUPPORTS_SERVICES')) {
1781 if ($warehouse_selected_id > 0) {
1782 $warehouseObject = new Entrepot($db);
1783 $warehouseObject->fetch($warehouse_selected_id);
1784 print img_warning().' '.$langs->trans("NoProductToShipFoundIntoStock", $warehouseObject->label);
1785 } else {
1786 if ($line->fk_product) {
1787 print img_warning().' '.$langs->trans("StockTooLow");
1788 } else {
1789 print '';
1790 }
1791 }
1792 } else {
1793 print '<span class="opacitymedium">('.$langs->trans("Service").')</span>';
1794 }
1795 print '</td>';
1796 if (getDolGlobalString('SHIPPING_DISPLAY_STOCK_ENTRY_DATE')) {
1797 print '<td></td>';
1798 }//StockEntrydate
1799 print '</tr>';
1800 }
1801 }
1802
1803 // Display lines for extrafields of the Shipment line
1804 // $line is a 'Order line'
1805 if (!empty($extrafields)) {
1806 //var_dump($line);
1807 $colspan = 5;
1808 $expLine = new ExpeditionLigne($db);
1809
1810 $srcLine = new OrderLine($db);
1811 $srcLine->id = $line->id;
1812 $srcLine->fetch_optionals(); // fetch extrafields also available in orderline
1813
1814 $expLine->array_options = array_merge($expLine->array_options, $srcLine->array_options);
1815
1816 print $expLine->showOptionals($extrafields, 'edit', array('style' => 'class="drag drop oddeven"', 'colspan' => $colspan), $indiceAsked, '', 1);
1817 }
1818 }
1819
1820 $indiceAsked++;
1821 }
1822
1823 print "</table>";
1824
1825 print '<br>';
1826
1827 print $form->buttonsSaveCancel("Create");
1828
1829 print '</form>';
1830
1831 print '<br>';
1832 } else {
1833 dol_print_error($db);
1834 }
1835 }
1836} elseif ($object->id > 0) {
1837 '@phan-var-force Expedition $object'; // Need to force it (type overridden earlier)
1838 /* *************************************************************************** */
1839 /* */
1840 /* Edit and view mode */
1841 /* */
1842 /* *************************************************************************** */
1843 $lines = $object->lines;
1844
1845 $num_prod = count($lines);
1846
1847 if (!empty($object->origin) && $object->origin_id > 0) {
1848 $typeobject = $object->origin;
1849 $origin = $object->origin;
1850 $origin_id = $object->origin_id;
1851
1852 $object->fetch_origin(); // Load property $object->origin_object (old $object->commande, $object->propal, ...)
1853 }
1854
1855 $soc = new Societe($db);
1856 $soc->fetch($object->socid);
1857
1858 $res = $object->fetch_optionals();
1859
1861 print dol_get_fiche_head($head, 'shipping', $langs->trans("Shipment"), -1, $object->picto);
1862
1863 $formconfirm = '';
1864
1865 // Confirm deletion
1866 if ($action == 'delete') {
1867 $formquestion = array();
1868 if ($object->status == Expedition::STATUS_CLOSED && getDolGlobalString('STOCK_CALCULATE_ON_SHIPMENT_CLOSE')) {
1869 $formquestion = array(
1870 array(
1871 'label' => $langs->trans('ShipmentIncrementStockOnDelete'),
1872 'name' => 'alsoUpdateStock',
1873 'type' => 'checkbox',
1874 'value' => 0
1875 ),
1876 );
1877 }
1878 $formconfirm = $form->formconfirm(
1879 $_SERVER['PHP_SELF'].'?id='.$object->id,
1880 $langs->trans('DeleteSending'),
1881 $langs->trans("ConfirmDeleteSending", $object->ref),
1882 'confirm_delete',
1883 $formquestion,
1884 0,
1885 1
1886 );
1887 }
1888
1889 // Confirmation validation
1890 if ($action == 'valid') {
1891 $objectref = substr($object->ref, 1, 4);
1892 if ($objectref == 'PROV') {
1893 $numref = $object->getNextNumRef($soc);
1894 } else {
1895 $numref = $object->ref;
1896 }
1897
1898 $text = $langs->trans("ConfirmValidateSending", $numref);
1899 if (getDolGlobalString('STOCK_CALCULATE_ON_SHIPMENT')) {
1900 $text .= '<br>'.img_picto('', 'movement', 'class="pictofixedwidth"').$langs->trans("StockMovementWillBeRecorded").'.';
1901 } elseif (getDolGlobalString('STOCK_CALCULATE_ON_SHIPMENT_CLOSE')) {
1902 $text .= '<br>'.img_picto('', 'movement', 'class="pictofixedwidth"').$langs->trans("StockMovementNotYetRecorded").'.';
1903 }
1904
1905 if (isModEnabled('notification')) {
1906 require_once DOL_DOCUMENT_ROOT.'/core/class/notify.class.php';
1907 $notify = new Notify($db);
1908 $text .= '<br>';
1909 $text .= $notify->confirmMessage('SHIPPING_VALIDATE', $object->socid, $object);
1910 }
1911
1912 $formconfirm = $form->formconfirm($_SERVER['PHP_SELF'].'?id='.$object->id, $langs->trans('ValidateSending'), $text, 'confirm_valid', '', 0, 1, 250);
1913 }
1914 // Confirm cancellation
1915 if ($action == 'cancel') {
1916 $formconfirm = $form->formconfirm($_SERVER['PHP_SELF'].'?id='.$object->id, $langs->trans('CancelSending'), $langs->trans("ConfirmCancelSending", $object->ref), 'confirm_cancel', '', 0, 1);
1917 }
1918
1919 // Call Hook formConfirm
1920 $parameters = array('formConfirm' => $formconfirm);
1921 $reshook = $hookmanager->executeHooks('formConfirm', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
1922 if (empty($reshook)) {
1923 $formconfirm .= $hookmanager->resPrint;
1924 } elseif ($reshook > 0) {
1925 $formconfirm = $hookmanager->resPrint;
1926 }
1927
1928 // Print form confirm
1929 print $formconfirm;
1930
1931 // Calculate totalWeight and totalVolume for all products
1932 // by adding weight and volume of each product line.
1933 $tmparray = $object->getTotalWeightVolume();
1934 $totalWeight = $tmparray['weight'];
1935 $totalVolume = $tmparray['volume'];
1936
1937 if (!empty($typeobject) && $typeobject === 'commande' && is_object($object->origin_object) && $object->origin_object->id && isModEnabled('order')) {
1938 $objectsrc = new Commande($db);
1939 $objectsrc->fetch($object->origin_object->id);
1940 }
1941 if (!empty($typeobject) && $typeobject === 'propal' && is_object($object->origin_object) && $object->origin_object->id && isModEnabled("propal")) {
1942 $objectsrc = new Propal($db);
1943 $objectsrc->fetch($object->origin_object->id);
1944 }
1945
1946 // Shipment card
1947 $linkback = '<a href="'.DOL_URL_ROOT.'/expedition/list.php?restore_lastsearch_values=1'.(!empty($socid) ? '&socid='.$socid : '').'">'.$langs->trans("BackToList").'</a>';
1948 $morehtmlref = '<div class="refidno">';
1949 // Ref customer shipment
1950 $morehtmlref .= $form->editfieldkey("RefCustomer", 'ref_customer', $object->ref_customer, $object, $user->hasRight('expedition', 'creer'), 'string', '', 0, 1);
1951 $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);
1952 // Thirdparty
1953 $morehtmlref .= '<br>'.$object->thirdparty->getNomUrl(1);
1954 // Project
1955 if (isModEnabled('project')) {
1956 $langs->load("projects");
1957 $morehtmlref .= '<br>';
1958 if (0) { // Do not change on shipment
1959 $morehtmlref .= img_picto($langs->trans("Project"), 'project', 'class="pictofixedwidth"');
1960 if ($action != 'classify') {
1961 $morehtmlref .= '<a class="editfielda" href="'.$_SERVER['PHP_SELF'].'?action=classify&token='.newToken().'&id='.$object->id.'">'.img_edit($langs->transnoentitiesnoconv('SetProject')).'</a> ';
1962 }
1963 $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'].'?id='.$object->id, $objectsrc->socid, $objectsrc->fk_project, ($action == 'classify' ? 'projectid' : 'none'), 0, 0, 0, 1, '', 'maxwidth300');
1964 } else {
1965 if (!empty($objectsrc) && !empty($objectsrc->fk_project)) {
1966 $proj = new Project($db);
1967 $proj->fetch($objectsrc->fk_project);
1968 $morehtmlref .= $proj->getNomUrl(1);
1969 if ($proj->title) {
1970 $morehtmlref .= '<span class="opacitymedium"> - '.dol_escape_htmltag($proj->title).'</span>';
1971 }
1972 }
1973 }
1974 }
1975 $morehtmlref .= '</div>';
1976
1977
1978 dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref);
1979
1980
1981 print '<div class="fichecenter">';
1982 print '<div class="fichehalfleft">';
1983 print '<div class="underbanner clearboth"></div>';
1984
1985 print '<table class="border tableforfield centpercent">';
1986
1987 // Linked documents
1988 if (!empty($typeobject) && $typeobject == 'commande' && $object->origin_object->id && isModEnabled('order')) {
1989 print '<tr><td>';
1990 print $langs->trans("RefOrder").'</td>';
1991 print '<td colspan="3">';
1992 print $objectsrc->getNomUrl(1, 'commande');
1993 print "</td>\n";
1994 print '</tr>';
1995 }
1996 if (!empty($typeobject) && $typeobject == 'propal' && $object->origin_object->id && isModEnabled("propal")) {
1997 print '<tr><td>';
1998 print $langs->trans("RefProposal").'</td>';
1999 print '<td colspan="3">';
2000 print $objectsrc->getNomUrl(1, 'expedition');
2001 print "</td>\n";
2002 print '</tr>';
2003 }
2004
2005 // Date creation
2006 print '<tr><td class="titlefield">'.$langs->trans("DateCreation").'</td>';
2007 print '<td colspan="3">'.dol_print_date($object->date_creation, "dayhour")."</td>\n";
2008 print '</tr>';
2009
2010 // Delivery date planned
2011 print '<tr><td height="10">';
2012 print '<table class="nobordernopadding centpercent"><tr><td>';
2013 print $langs->trans('DateDeliveryPlanned');
2014 print '</td>';
2015
2016 if ($action != 'editdate_livraison') {
2017 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>';
2018 }
2019 print '</tr></table>';
2020 print '</td><td colspan="2">';
2021 if ($action == 'editdate_livraison') {
2022 print '<form name="setdate_livraison" action="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'" method="post">';
2023 print '<input type="hidden" name="token" value="'.newToken().'">';
2024 print '<input type="hidden" name="action" value="setdate_livraison">';
2025 print $form->selectDate($object->date_delivery ? $object->date_delivery : -1, 'liv_', 1, 1, 0, "setdate_livraison", 1, 0);
2026 print '<input type="submit" class="button button-edit smallpaddingimp" value="'.$langs->trans('Modify').'">';
2027 print '</form>';
2028 } else {
2029 print $object->date_delivery ? dol_print_date($object->date_delivery, 'dayhour') : '&nbsp;';
2030 }
2031 print '</td>';
2032 print '</tr>';
2033
2034 // Weight
2035 print '<tr><td>';
2036 print $form->editfieldkey("Weight", 'trueWeight', $object->trueWeight, $object, $user->hasRight('expedition', 'creer'));
2037 print '</td><td colspan="3">';
2038
2039 if ($action == 'edittrueWeight') {
2040 print '<form name="settrueweight" action="'.$_SERVER["PHP_SELF"].'" method="post">';
2041 print '<input name="action" value="settrueWeight" type="hidden">';
2042 print '<input name="id" value="'.$object->id.'" type="hidden">';
2043 print '<input type="hidden" name="token" value="'.newToken().'">';
2044 print '<input id="trueWeight" name="trueWeight" value="'.$object->trueWeight.'" type="text" class="width50 valignmiddle">';
2045 print $formproduct->selectMeasuringUnits("weight_units", "weight", $object->weight_units, 0, 2, 'maxwidth125 valignmiddle');
2046 print ' <input class="button smallpaddingimp valignmiddle" name="modify" value="'.$langs->trans("Modify").'" type="submit">';
2047 print ' <input class="button button-cancel smallpaddingimp valignmiddle" name="cancel" value="'.$langs->trans("Cancel").'" type="submit">';
2048 print '</form>';
2049 } else {
2050 print $object->trueWeight;
2051 print ($object->trueWeight && $object->weight_units != '') ? ' '.measuringUnitString(0, "weight", $object->weight_units) : '';
2052 }
2053
2054 // Calculated
2055 if ($totalWeight > 0) {
2056 if (!empty($object->trueWeight)) {
2057 print ' ('.$langs->trans("SumOfProductWeights").': ';
2058 }
2059 print showDimensionInBestUnit($totalWeight, 0, "weight", $langs, getDolGlobalInt('MAIN_WEIGHT_DEFAULT_ROUND', -1), isset($conf->global->MAIN_WEIGHT_DEFAULT_UNIT) ? $conf->global->MAIN_WEIGHT_DEFAULT_UNIT : 'no');
2060 if (!empty($object->trueWeight)) {
2061 print ')';
2062 }
2063 }
2064 print '</td></tr>';
2065
2066 // Width
2067 print '<tr><td>'.$form->editfieldkey("Width", 'trueWidth', $object->trueWidth, $object, $user->hasRight('expedition', 'creer')).'</td><td colspan="3">';
2068 print $form->editfieldval("Width", 'trueWidth', $object->trueWidth, $object, $user->hasRight('expedition', 'creer'));
2069 print ($object->trueWidth && $object->width_units != '') ? ' '.measuringUnitString(0, "size", $object->width_units) : '';
2070 print '</td></tr>';
2071
2072 // Height
2073 print '<tr><td>'.$form->editfieldkey("Height", 'trueHeight', $object->trueHeight, $object, $user->hasRight('expedition', 'creer')).'</td><td colspan="3">';
2074 if ($action == 'edittrueHeight') {
2075 print '<form name="settrueHeight" action="'.$_SERVER["PHP_SELF"].'" method="post">';
2076 print '<input name="action" value="settrueHeight" type="hidden">';
2077 print '<input name="id" value="'.$object->id.'" type="hidden">';
2078 print '<input type="hidden" name="token" value="'.newToken().'">';
2079 print '<input id="trueHeight" name="trueHeight" value="'.$object->trueHeight.'" type="text" class="width50">';
2080 print $formproduct->selectMeasuringUnits("size_units", "size", $object->size_units, 0, 2);
2081 print ' <input class="button smallpaddingimp" name="modify" value="'.$langs->trans("Modify").'" type="submit">';
2082 print ' <input class="button button-cancel smallpaddingimp" name="cancel" value="'.$langs->trans("Cancel").'" type="submit">';
2083 print '</form>';
2084 } else {
2085 print $object->trueHeight;
2086 print ($object->trueHeight && $object->height_units != '') ? ' '.measuringUnitString(0, "size", $object->height_units) : '';
2087 }
2088
2089 print '</td></tr>';
2090
2091 // Depth
2092 print '<tr><td>'.$form->editfieldkey("Depth", 'trueDepth', $object->trueDepth, $object, $user->hasRight('expedition', 'creer')).'</td><td colspan="3">';
2093 print $form->editfieldval("Depth", 'trueDepth', $object->trueDepth, $object, $user->hasRight('expedition', 'creer'));
2094 print ($object->trueDepth && $object->depth_units != '') ? ' '.measuringUnitString(0, "size", $object->depth_units) : '';
2095 print '</td></tr>';
2096
2097 // Volume
2098 print '<tr><td>';
2099 print $langs->trans("Volume");
2100 print '</td>';
2101 print '<td colspan="3">';
2102 $calculatedVolume = 0;
2103 $volumeUnit = 0;
2104 if ($object->trueWidth && $object->trueHeight && $object->trueDepth) {
2105 $calculatedVolume = ($object->trueWidth * $object->trueHeight * $object->trueDepth);
2106 $volumeUnit = $object->size_units * 3;
2107 }
2108 // If sending volume not defined we use sum of products
2109 if ($calculatedVolume > 0) {
2110 if ($volumeUnit < 50) {
2111 print showDimensionInBestUnit($calculatedVolume, $volumeUnit, "volume", $langs, getDolGlobalInt('MAIN_VOLUME_DEFAULT_ROUND', -1), getDolGlobalString('MAIN_VOLUME_DEFAULT_UNIT', 'no'));
2112 } else {
2113 print $calculatedVolume.' '.measuringUnitString(0, "volume", (string) $volumeUnit);
2114 }
2115 }
2116 if ($totalVolume > 0) {
2117 if ($calculatedVolume) {
2118 print ' ('.$langs->trans("SumOfProductVolumes").': ';
2119 }
2120 print showDimensionInBestUnit($totalVolume, 0, "volume", $langs, getDolGlobalInt('MAIN_VOLUME_DEFAULT_ROUND', -1), getDolGlobalString('MAIN_VOLUME_DEFAULT_UNIT', 'no'));
2121 //if (empty($calculatedVolume)) print ' ('.$langs->trans("Calculated").')';
2122 if ($calculatedVolume) {
2123 print ')';
2124 }
2125 }
2126 print "</td>\n";
2127 print '</tr>';
2128
2129 // Other attributes
2130 $cols = 2;
2131 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_view.tpl.php';
2132
2133 print '</table>';
2134
2135 print '</div>';
2136 print '<div class="fichehalfright">';
2137 print '<div class="underbanner clearboth"></div>';
2138
2139 print '<table class="border centpercent tableforfield">';
2140
2141 // Sending method
2142 print '<tr><td height="10">';
2143 print '<table class="nobordernopadding centpercent"><tr><td>';
2144 print $langs->trans('SendingMethod');
2145 print '</td>';
2146
2147 if ($action != 'editshipping_method_id') {
2148 print '<td class="right"><a class="editfielda" href="'.$_SERVER["PHP_SELF"].'?action=editshipping_method_id&token='.newToken().'&id='.$object->id.'">'.img_edit($langs->trans('SetSendingMethod'), 1).'</a></td>';
2149 }
2150 print '</tr></table>';
2151 print '</td><td colspan="2">';
2152 if ($action == 'editshipping_method_id') {
2153 print '<form name="setshipping_method_id" action="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'" method="post">';
2154 print '<input type="hidden" name="token" value="'.newToken().'">';
2155 print '<input type="hidden" name="action" value="setshipping_method_id">';
2156 $object->fetch_delivery_methods();
2157 print $form->selectarray("shipping_method_id", $object->meths, $object->shipping_method_id, 1, 0, 0, "", 1);
2158 if ($user->admin) {
2159 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
2160 }
2161 print '<input type="submit" class="button button-edit smallpaddingimp" value="'.$langs->trans('Modify').'">';
2162 print '</form>';
2163 } else {
2164 if ($object->shipping_method_id > 0) {
2165 // Get code using getLabelFromKey
2166 $code = $langs->getLabelFromKey($db, $object->shipping_method_id, 'c_shipment_mode', 'rowid', 'code');
2167 print $langs->trans("SendingMethod".strtoupper($code));
2168 }
2169 }
2170 print '</td>';
2171 print '</tr>';
2172
2173 // Tracking Number
2174 print '<tr><td class="titlefield">'.$form->editfieldkey("TrackingNumber", 'tracking_number', $object->tracking_number, $object, $user->hasRight('expedition', 'creer')).'</td><td colspan="3">';
2175 print $form->editfieldval("TrackingNumber", 'tracking_number', $object->tracking_url, $object, $user->hasRight('expedition', 'creer'), 'safehtmlstring', $object->tracking_number);
2176 print '</td></tr>';
2177
2178 // Incoterms
2179 if (isModEnabled('incoterm')) {
2180 print '<tr><td>';
2181 print '<table width="100%" class="nobordernopadding"><tr><td>';
2182 print $langs->trans('IncotermLabel');
2183 print '<td><td class="right">';
2184 if ($user->hasRight('expedition', 'creer')) {
2185 print '<a class="editfielda" href="'.DOL_URL_ROOT.'/expedition/card.php?id='.$object->id.'&action=editincoterm&token='.newToken().'">'.img_edit().'</a>';
2186 } else {
2187 print '&nbsp;';
2188 }
2189 print '</td></tr></table>';
2190 print '</td>';
2191 print '<td colspan="3">';
2192 if ($action != 'editincoterm') {
2193 print $form->textwithpicto($object->display_incoterms(), $object->label_incoterms, 1);
2194 } else {
2195 print $form->select_incoterms((!empty($object->fk_incoterms) ? $object->fk_incoterms : ''), (!empty($object->location_incoterms) ? $object->location_incoterms : ''), $_SERVER['PHP_SELF'].'?id='.$object->id);
2196 }
2197 print '</td></tr>';
2198 }
2199
2200 // Other attributes
2201 $parameters = array('colspan' => ' colspan="3"', 'cols' => '3');
2202 $reshook = $hookmanager->executeHooks('formObjectOptions', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
2203 print $hookmanager->resPrint;
2204
2205 print "</table>";
2206
2207 print '</div>';
2208 print '</div>';
2209
2210 print '<div class="clearboth"></div>';
2211
2212
2213 // Lines of products
2214
2215 if ($action == 'editline') {
2216 print ' <form name="updateline" id="updateline" action="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&amp;lineid='.$line_id.'" method="POST">
2217 <input type="hidden" name="token" value="' . newToken().'">
2218 <input type="hidden" name="action" value="updateline">
2219 <input type="hidden" name="mode" value="">
2220 <input type="hidden" name="id" value="' . $object->id.'">
2221 ';
2222 }
2223 print '<br>';
2224
2225 print '<div class="div-table-responsive-no-min">';
2226 print '<table class="noborder" width="100%" id="tablelines" >';
2227 print '<thead>';
2228 print '<tr class="liste_titre">';
2229 // Adds a line numbering column
2230 if (getDolGlobalString('MAIN_VIEW_LINE_NUMBER')) {
2231 print '<td width="5" class="center linecolnum">&nbsp;</td>';
2232 }
2233 // Product/Service
2234 print '<td class="linecoldescription" >'.$langs->trans("Products").'</td>';
2235 // Qty
2236 print '<td class="center linecolqty">'.$langs->trans("QtyOrdered").'</td>';
2237 if ($origin && $origin_id > 0) {
2238 print '<td class="center linecolqtyinothershipments">'.$langs->trans("QtyInOtherShipments").'</td>';
2239 }
2240 if ($action == 'editline') {
2241 $editColspan = 3;
2242 if (!isModEnabled('stock')) {
2243 $editColspan--;
2244 }
2245 if (empty($conf->productbatch->enabled)) {
2246 $editColspan--;
2247 }
2248 print '<td class="center linecoleditlineotherinfo" colspan="'.$editColspan.'">';
2249 if ($object->status <= 1) {
2250 print $langs->trans("QtyToShip").' - ';
2251 } else {
2252 print $langs->trans("QtyShipped").' - ';
2253 }
2254 if (isModEnabled('stock')) {
2255 print $langs->trans("WarehouseSource").' - ';
2256 }
2257 if (isModEnabled('productbatch')) {
2258 print $langs->trans("Batch");
2259 }
2260 print '</td>';
2261 } else {
2262 if ($object->status <= 1) {
2263 print '<td class="center linecolqtytoship">'.$langs->trans("QtyToShip").'</td>';
2264 } else {
2265 print '<td class="center linecolqtyshipped">'.$langs->trans("QtyShipped").'</td>';
2266 }
2267 if (isModEnabled('stock')) {
2268 print '<td class="left linecolwarehousesource">'.$langs->trans("WarehouseSource").'</td>';
2269 }
2270
2271 if (isModEnabled('productbatch')) {
2272 print '<td class="left linecolbatch">'.$langs->trans("Batch").'</td>';
2273 }
2274 }
2275 print '<td class="center linecolweight">'.$langs->trans("CalculatedWeight").'</td>';
2276 print '<td class="center linecolvolume">'.$langs->trans("CalculatedVolume").'</td>';
2277 //print '<td class="center">'.$langs->trans("Size").'</td>';
2278 if ($object->status == 0) {
2279 print '<td class="linecoledit"></td>';
2280 print '<td class="linecoldelete" width="10"></td>';
2281 }
2282 print "</tr>\n";
2283 print '</thead>';
2284
2285 $outputlangs = $langs;
2286
2287 if (getDolGlobalInt('MAIN_MULTILANGS') && getDolGlobalString('PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE')) {
2288 $object->fetch_thirdparty();
2289 $newlang = '';
2290 if (empty($newlang) && GETPOST('lang_id', 'aZ09')) {
2291 $newlang = GETPOST('lang_id', 'aZ09');
2292 }
2293 if (empty($newlang)) {
2294 $newlang = $object->thirdparty->default_lang;
2295 }
2296 if (!empty($newlang)) {
2297 $outputlangs = new Translate("", $conf);
2298 $outputlangs->setDefaultLang($newlang);
2299 }
2300 }
2301
2302 // Get list of products already sent for same source object into $alreadysent
2303 $alreadysent = array();
2304 if ($origin && $origin_id > 0) {
2305 $sql = "SELECT obj.rowid, obj.fk_product, obj.label, obj.description, obj.product_type as fk_product_type, obj.qty as qty_asked, obj.fk_unit, obj.date_start, obj.date_end";
2306 $sql .= ", ed.rowid as shipmentline_id, ed.qty as qty_shipped, ed.fk_expedition as expedition_id, ed.fk_elementdet, ed.fk_entrepot";
2307 $sql .= ", e.rowid as shipment_id, e.ref as shipment_ref, e.date_creation, e.date_valid, e.date_delivery, e.date_expedition";
2308 //if (getDolGlobalInt('MAIN_SUBMODULE_DELIVERY')) $sql .= ", l.rowid as livraison_id, l.ref as livraison_ref, l.date_delivery, ld.qty as qty_received";
2309 $sql .= ', p.label as product_label, p.ref, p.fk_product_type, p.rowid as prodid, p.tosell as product_tosell, p.tobuy as product_tobuy, p.tobatch as product_tobatch';
2310 $sql .= ', p.description as product_desc';
2311 $sql .= " FROM ".MAIN_DB_PREFIX."expeditiondet as ed";
2312 $sql .= ", ".MAIN_DB_PREFIX."expedition as e";
2313 $sql .= ", ".MAIN_DB_PREFIX.$origin."det as obj";
2314 //if (getDolGlobalInt('MAIN_SUBMODULE_DELIVERY')) $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."delivery as l ON l.fk_expedition = e.rowid LEFT JOIN ".MAIN_DB_PREFIX."deliverydet as ld ON ld.fk_delivery = l.rowid AND obj.rowid = ld.fk_origin_line";
2315 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product as p ON obj.fk_product = p.rowid";
2316 $sql .= " WHERE e.entity IN (".getEntity('expedition').")";
2317 $sql .= " AND obj.fk_".$origin." = ".((int) $origin_id);
2318 $sql .= " AND obj.rowid = ed.fk_elementdet";
2319 $sql .= " AND ed.fk_expedition = e.rowid";
2320 //if ($filter) $sql.= $filter;
2321 $sql .= " ORDER BY obj.fk_product";
2322
2323 dol_syslog("expedition/card.php get list of shipment lines", LOG_DEBUG);
2324 $resql = $db->query($sql);
2325 if ($resql) {
2326 $num = $db->num_rows($resql);
2327 $i = 0;
2328
2329 while ($i < $num) {
2330 $obj = $db->fetch_object($resql);
2331 if ($obj) {
2332 // $obj->rowid is rowid in $origin."det" table
2333 $alreadysent[$obj->rowid][$obj->shipmentline_id] = array(
2334 'shipment_ref' => $obj->shipment_ref, 'shipment_id' => $obj->shipment_id, 'warehouse' => $obj->fk_entrepot, 'qty_shipped' => $obj->qty_shipped,
2335 'product_tosell' => $obj->product_tosell, 'product_tobuy' => $obj->product_tobuy, 'product_tobatch' => $obj->product_tobatch,
2336 'date_valid' => $db->jdate($obj->date_valid), 'date_delivery' => $db->jdate($obj->date_delivery));
2337 }
2338 $i++;
2339 }
2340 }
2341 //var_dump($alreadysent);
2342 }
2343
2344 print '<tbody>';
2345
2346 // Loop on each product to send/sent
2347 for ($i = 0; $i < $num_prod; $i++) {
2348 $parameters = array('i' => $i, 'line' => $lines[$i], 'line_id' => $line_id, 'num' => $num_prod, 'alreadysent' => $alreadysent, 'editColspan' => !empty($editColspan) ? $editColspan : 0, 'outputlangs' => $outputlangs);
2349 $reshook = $hookmanager->executeHooks('printObjectLine', $parameters, $object, $action);
2350 if ($reshook < 0) {
2351 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
2352 }
2353
2354 if (empty($reshook)) {
2355 print '<!-- origin line id = '.$lines[$i]->origin_line_id.' -->'; // id of order line
2356 print '<tr class="oddeven" id="row-'.$lines[$i]->id.'" data-id="'.$lines[$i]->id.'" data-element="'.$lines[$i]->element.'" >';
2357
2358 // #
2359 if (getDolGlobalString('MAIN_VIEW_LINE_NUMBER')) {
2360 print '<td class="center linecolnum">'.($i + 1).'</td>';
2361 }
2362
2363 // Predefined product or service
2364 if ($lines[$i]->fk_product > 0) {
2365 // Define output language
2366 if (getDolGlobalInt('MAIN_MULTILANGS') && getDolGlobalString('PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE')) {
2367 $prod = new Product($db);
2368 $prod->fetch($lines[$i]->fk_product);
2369 $label = (!empty($prod->multilangs[$outputlangs->defaultlang]["label"])) ? $prod->multilangs[$outputlangs->defaultlang]["label"] : $lines[$i]->product_label;
2370 } else {
2371 $label = (!empty($lines[$i]->label) ? $lines[$i]->label : $lines[$i]->product_label);
2372 }
2373
2374 print '<td class="linecoldescription">';
2375
2376 // Show product and description
2377 $product_static->type = $lines[$i]->fk_product_type;
2378 $product_static->id = $lines[$i]->fk_product;
2379 $product_static->ref = $lines[$i]->ref;
2380 $product_static->status = $lines[$i]->product_tosell;
2381 $product_static->status_buy = $lines[$i]->product_tobuy;
2382 $product_static->status_batch = $lines[$i]->product_tobatch;
2383
2384 $product_static->weight = $lines[$i]->weight;
2385 $product_static->weight_units = $lines[$i]->weight_units;
2386 $product_static->length = $lines[$i]->length;
2387 $product_static->length_units = $lines[$i]->length_units;
2388 $product_static->width = !empty($lines[$i]->width) ? $lines[$i]->width : 0;
2389 $product_static->width_units = !empty($lines[$i]->width_units) ? $lines[$i]->width_units : 0;
2390 $product_static->height = !empty($lines[$i]->height) ? $lines[$i]->height : 0;
2391 $product_static->height_units = !empty($lines[$i]->height_units) ? $lines[$i]->height_units : 0;
2392 $product_static->surface = $lines[$i]->surface;
2393 $product_static->surface_units = $lines[$i]->surface_units;
2394 $product_static->volume = $lines[$i]->volume;
2395 $product_static->volume_units = $lines[$i]->volume_units;
2396
2397 $text = $product_static->getNomUrl(1);
2398 $text .= ' - '.$label;
2399 $description = (getDolGlobalInt('PRODUIT_DESC_IN_FORM_ACCORDING_TO_DEVICE') ? '' : dol_htmlentitiesbr($lines[$i]->description));
2400 print $form->textwithtooltip($text, $description, 3, 0, '', $i);
2401 print_date_range(!empty($lines[$i]->date_start) ? $lines[$i]->date_start : '', !empty($lines[$i]->date_end) ? $lines[$i]->date_end : '');
2402 if (getDolGlobalInt('PRODUIT_DESC_IN_FORM_ACCORDING_TO_DEVICE')) {
2403 print (!empty($lines[$i]->description) && $lines[$i]->description != $lines[$i]->product) ? '<br>'.dol_htmlentitiesbr($lines[$i]->description) : '';
2404 }
2405 print "</td>\n";
2406 } else {
2407 print '<td class="linecoldescription" >';
2408 if ($lines[$i]->product_type == Product::TYPE_SERVICE) {
2409 $text = img_object($langs->trans('Service'), 'service');
2410 } else {
2411 $text = img_object($langs->trans('Product'), 'product');
2412 }
2413
2414 if (!empty($lines[$i]->label)) {
2415 $text .= ' <strong>'.$lines[$i]->label.'</strong>';
2416 print $form->textwithtooltip($text, $lines[$i]->description, 3, 0, '', $i);
2417 } else {
2418 print $text.' '.nl2br($lines[$i]->description);
2419 }
2420
2421 print_date_range($lines[$i]->date_start, $lines[$i]->date_end);
2422 print "</td>\n";
2423 }
2424
2425 $unit_order = '';
2426 if (getDolGlobalString('PRODUCT_USE_UNITS')) {
2427 $unit_order = measuringUnitString($lines[$i]->fk_unit);
2428 }
2429
2430 // Qty ordered
2431 print '<td class="center linecolqty">'.$lines[$i]->qty_asked.' '.$unit_order.'</td>';
2432
2433 // Qty in other shipments (with shipment and warehouse used)
2434 if ($origin && $origin_id > 0) {
2435 print '<td class="linecolqtyinothershipments center nowrap">';
2436 $htmltooltip = '';
2437 $qtyalreadysent = 0;
2438 foreach ($alreadysent as $key => $val) {
2439 if ($lines[$i]->fk_elementdet == $key) {
2440 $j = 0;
2441 foreach ($val as $shipmentline_id => $shipmentline_var) {
2442 if ($shipmentline_var['shipment_id'] == $lines[$i]->fk_expedition) {
2443 continue; // We want to show only "other shipments"
2444 }
2445
2446 $j++;
2447 if ($j > 1) {
2448 $htmltooltip .= '<br>';
2449 }
2450 $shipment_static->fetch($shipmentline_var['shipment_id']);
2451 $htmltooltip .= $shipment_static->getNomUrl(1, '', 0, 0, 1);
2452 $htmltooltip .= ' - '.$shipmentline_var['qty_shipped'];
2453 $htmltooltip .= ' - '.$langs->trans("DateValidation").' : '.(empty($shipmentline_var['date_valid']) ? $langs->trans("Draft") : dol_print_date($shipmentline_var['date_valid'], 'dayhour'));
2454 /*if (isModEnabled('stock') && $shipmentline_var['warehouse'] > 0) {
2455 $warehousestatic->fetch($shipmentline_var['warehouse']);
2456 $htmltext .= '<br>'.$langs->trans("FromLocation").' : '.$warehousestatic->getNomUrl(1, '', 0, 1);
2457 }*/
2458 //print ' '.$form->textwithpicto('', $htmltext, 1);
2459
2460 $qtyalreadysent += $shipmentline_var['qty_shipped'];
2461 }
2462 if ($j) {
2463 $htmltooltip = $langs->trans("QtyInOtherShipments").'...<br><br>'.$htmltooltip.'<br><input type="submit" name="dummyhiddenbuttontogetfocus" style="display:none" autofocus>';
2464 }
2465 }
2466 }
2467 print $form->textwithpicto($qtyalreadysent, $htmltooltip, 1, 'info', '', 0, 3, 'tooltip'.$lines[$i]->id);
2468 print '</td>';
2469 }
2470
2471 if ($action == 'editline' && $lines[$i]->id == $line_id) {
2472 // edit mode
2473 print '<td colspan="'.$editColspan.'" class="center"><table class="nobordernopadding centpercent">';
2474 if (is_array($lines[$i]->detail_batch) && count($lines[$i]->detail_batch) > 0) {
2475 print '<!-- case edit 1 -->';
2476 $line = new ExpeditionLigne($db);
2477 foreach ($lines[$i]->detail_batch as $detail_batch) {
2478 print '<tr>';
2479 // Qty to ship or shipped
2480 print '<td><input class="qtyl right" name="qtyl'.$detail_batch->fk_expeditiondet.'_'.$detail_batch->id.'" id="qtyl'.$line_id.'_'.$detail_batch->id.'" type="text" size="4" value="'.$detail_batch->qty.'"></td>';
2481 // Batch number management
2482 if ($lines[$i]->entrepot_id == 0) {
2483 // only show lot numbers from src warehouse when shipping from multiple warehouses
2484 $line->fetch($detail_batch->fk_expeditiondet);
2485 }
2486 $entrepot_id = !empty($detail_batch->entrepot_id) ? $detail_batch->entrepot_id : $lines[$i]->entrepot_id;
2487 print '<td>'.$formproduct->selectLotStock($detail_batch->fk_origin_stock, 'batchl'.$detail_batch->fk_expeditiondet.'_'.$detail_batch->fk_origin_stock, '', 1, 0, $lines[$i]->fk_product, $entrepot_id).'</td>';
2488 print '</tr>';
2489 }
2490 // add a 0 qty lot row to be able to add a lot
2491 print '<tr>';
2492 // Qty to ship or shipped
2493 print '<td><input class="qtyl" name="qtyl'.$line_id.'_0" id="qtyl'.$line_id.'_0" type="text" size="4" value="0"></td>';
2494 // Batch number management
2495 print '<td>'.$formproduct->selectLotStock('', 'batchl'.$line_id.'_0', '', 1, 0, $lines[$i]->fk_product).'</td>';
2496 print '</tr>';
2497 } elseif (isModEnabled('stock')) {
2498 if ($lines[$i]->fk_product > 0) {
2499 if ($lines[$i]->entrepot_id > 0) {
2500 print '<!-- case edit 2 -->';
2501 print '<tr>';
2502 // Qty to ship or shipped
2503 print '<td><input class="qtyl right" name="qtyl'.$line_id.'" id="qtyl'.$line_id.'" type="text" size="4" value="'.$lines[$i]->qty_shipped.'">'.$unit_order.'</td>';
2504 // Warehouse source
2505 print '<td>'.$formproduct->selectWarehouses($lines[$i]->entrepot_id, 'entl'.$line_id, '', 1, 0, $lines[$i]->fk_product, '', 1).'</td>';
2506 // Batch number management
2507 print '<td> - '.$langs->trans("NA").'</td>';
2508 print '</tr>';
2509 } elseif (count($lines[$i]->details_entrepot) > 1) {
2510 print '<!-- case edit 3 -->';
2511 foreach ($lines[$i]->details_entrepot as $detail_entrepot) {
2512 print '<tr>';
2513 // Qty to ship or shipped
2514 print '<td><input class="qtyl right" name="qtyl'.$detail_entrepot->line_id.'" id="qtyl'.$detail_entrepot->line_id.'" type="text" size="4" value="'.$detail_entrepot->qty_shipped.'">'.$unit_order.'</td>';
2515 // Warehouse source
2516 print '<td>'.$formproduct->selectWarehouses($detail_entrepot->entrepot_id, 'entl'.$detail_entrepot->line_id, '', 1, 0, $lines[$i]->fk_product, '', 1).'</td>';
2517 // Batch number management
2518 print '<td> - '.$langs->trans("NA").'</td>';
2519 print '</tr>';
2520 }
2521 } elseif ($lines[$i]->product_type == Product::TYPE_SERVICE && getDolGlobalString('SHIPMENT_SUPPORTS_SERVICES')) {
2522 print '<!-- case edit 4 -->';
2523 print '<tr>';
2524 // Qty to ship or shipped
2525 print '<td><input class="qtyl right" name="qtyl'.$line_id.'" id="qtyl'.$line_id.'" type="text" size="4" value="'.$lines[$i]->qty_shipped.'"></td>';
2526 print '<td><span class="opacitymedium">('.$langs->trans("Service").')</span></td>';
2527 print '<td></td>';
2528 print '</tr>';
2529 } else {
2530 print '<!-- case edit 5 -->';
2531 print '<tr><td colspan="3">'.$langs->trans("ErrorStockIsNotEnough").'</td></tr>';
2532 }
2533 } else {
2534 print '<!-- case edit 6 -->';
2535 print '<tr>';
2536 // Qty to ship or shipped
2537 print '<td><input class="qtyl right" name="qtyl'.$line_id.'" id="qtyl'.$line_id.'" type="text" size="4" value="'.$lines[$i]->qty_shipped.'">'.$unit_order.'</td>';
2538 // Warehouse source
2539 print '<td></td>';
2540 // Batch number management
2541 print '<td></td>';
2542 print '</tr>';
2543 }
2544 } elseif (!isModEnabled('stock') && empty($conf->productbatch->enabled)) { // both product batch and stock are not activated.
2545 print '<!-- case edit 7 -->';
2546 print '<tr>';
2547 // Qty to ship or shipped
2548 print '<td><input class="qtyl right" name="qtyl'.$line_id.'" id="qtyl'.$line_id.'" type="text" size="4" value="'.$lines[$i]->qty_shipped.'"></td>';
2549 // Warehouse source
2550 print '<td></td>';
2551 // Batch number management
2552 print '<td></td>';
2553 print '</tr>';
2554 }
2555
2556 print '</table></td>';
2557 } else {
2558 // Qty to ship or shipped
2559 print '<td class="linecolqtytoship center">'.$lines[$i]->qty_shipped.' '.$unit_order.'</td>';
2560
2561 // Warehouse source
2562 if (isModEnabled('stock')) {
2563 print '<td class="linecolwarehousesource tdoverflowmax200">';
2564 if ($lines[$i]->product_type == Product::TYPE_SERVICE && getDolGlobalString('SHIPMENT_SUPPORTS_SERVICES')) {
2565 print '<span class="opacitymedium">('.$langs->trans("Service").')</span>';
2566 } elseif ($lines[$i]->entrepot_id > 0) {
2567 $entrepot = new Entrepot($db);
2568 $entrepot->fetch($lines[$i]->entrepot_id);
2569 print $entrepot->getNomUrl(1);
2570 } elseif (count($lines[$i]->details_entrepot) > 1) {
2571 $detail = '';
2572 foreach ($lines[$i]->details_entrepot as $detail_entrepot) {
2573 if ($detail_entrepot->entrepot_id > 0) {
2574 $entrepot = new Entrepot($db);
2575 $entrepot->fetch($detail_entrepot->entrepot_id);
2576 $detail .= $langs->trans("DetailWarehouseFormat", $entrepot->label, $detail_entrepot->qty_shipped).'<br>';
2577 }
2578 }
2579 print $form->textwithtooltip(img_picto('', 'object_stock').' '.$langs->trans("DetailWarehouseNumber"), $detail);
2580 }
2581 print '</td>';
2582 }
2583
2584 // Batch number management
2585 if (isModEnabled('productbatch')) {
2586 if (isset($lines[$i]->detail_batch)) {
2587 print '<!-- Detail of lot -->';
2588 print '<td class="linecolbatch">';
2589 if ($lines[$i]->product_tobatch) {
2590 $detail = '';
2591 foreach ($lines[$i]->detail_batch as $dbatch) { // $dbatch is instance of ExpeditionLineBatch
2592 $detail .= $langs->trans("Batch").': '.$dbatch->batch;
2593 if (!getDolGlobalString('PRODUCT_DISABLE_SELLBY')) {
2594 $detail .= ' - '.$langs->trans("SellByDate").': '.dol_print_date($dbatch->sellby, "day");
2595 }
2596 if (!getDolGlobalString('PRODUCT_DISABLE_EATBY')) {
2597 $detail .= ' - '.$langs->trans("EatByDate").': '.dol_print_date($dbatch->eatby, "day");
2598 }
2599 $detail .= ' - '.$langs->trans("Qty").': '.$dbatch->qty;
2600 $detail .= '<br>';
2601 }
2602 print $form->textwithtooltip(img_picto('', 'object_barcode').' '.$langs->trans("DetailBatchNumber"), $detail);
2603 } else {
2604 print $langs->trans("NA");
2605 }
2606 print '</td>';
2607 } else {
2608 print '<td class="linecolbatch" ></td>';
2609 }
2610 }
2611 }
2612
2613 // Weight
2614 print '<td class="center linecolweight">';
2615 if ($lines[$i]->fk_product_type == Product::TYPE_PRODUCT) {
2616 print $lines[$i]->weight * $lines[$i]->qty_shipped.' '.measuringUnitString(0, "weight", $lines[$i]->weight_units);
2617 } else {
2618 print '&nbsp;';
2619 }
2620 print '</td>';
2621
2622 // Volume
2623 print '<td class="center linecolvolume">';
2624 if ($lines[$i]->fk_product_type == Product::TYPE_PRODUCT) {
2625 print $lines[$i]->volume * $lines[$i]->qty_shipped.' '.measuringUnitString(0, "volume", $lines[$i]->volume_units);
2626 } else {
2627 print '&nbsp;';
2628 }
2629 print '</td>';
2630
2631 // Size
2632 //print '<td class="center">'.$lines[$i]->volume*$lines[$i]->qty_shipped.' '.measuringUnitString(0, "volume", $lines[$i]->volume_units).'</td>';
2633
2634 if ($action == 'editline' && $lines[$i]->id == $line_id) {
2635 print '<td class="center" colspan="2" valign="middle">';
2636 print '<input type="submit" class="button button-save" id="savelinebutton marginbottomonly" name="save" value="'.$langs->trans("Save").'"><br>';
2637 print '<input type="submit" class="button button-cancel" id="cancellinebutton" name="cancel" value="'.$langs->trans("Cancel").'"><br>';
2638 print '</td>';
2639 } elseif ($object->status == Expedition::STATUS_DRAFT) {
2640 // edit-delete buttons
2641 print '<td class="linecoledit center">';
2642 print '<a class="editfielda reposition" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=editline&token='.newToken().'&lineid='.$lines[$i]->id.'">'.img_edit().'</a>';
2643 print '</td>';
2644 print '<td class="linecoldelete" width="10">';
2645 print '<a class="reposition" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=deleteline&token='.newToken().'&lineid='.$lines[$i]->id.'">'.img_delete().'</a>';
2646 print '</td>';
2647
2648 // Display lines extrafields
2649 if (!empty($rowExtrafieldsStart)) {
2650 print $rowExtrafieldsStart;
2651 print $rowExtrafieldsView;
2652 print $rowEnd;
2653 }
2654 }
2655 print "</tr>";
2656
2657 // Display lines extrafields.
2658 // $line is a line of shipment
2659 if (!empty($extrafields)) {
2660 $colspan = 6;
2661 if ($origin && $origin_id > 0) {
2662 $colspan++;
2663 }
2664 if (isModEnabled('productbatch')) {
2665 $colspan++;
2666 }
2667 if (isModEnabled('stock')) {
2668 $colspan++;
2669 }
2670
2671 $line = $lines[$i];
2672 $line->fetch_optionals();
2673
2674 // TODO Show all in same line by setting $display_type = 'line'
2675 if ($action == 'editline' && $line->id == $line_id) {
2676 print $lines[$i]->showOptionals($extrafields, 'edit', array('colspan' => $colspan), !empty($indiceAsked) ? $indiceAsked : '', '', 0, 'card');
2677 } else {
2678 print $lines[$i]->showOptionals($extrafields, 'view', array('colspan' => $colspan), !empty($indiceAsked) ? $indiceAsked : '', '', 0, 'card');
2679 }
2680 }
2681 }
2682 }
2683
2684 // TODO Show also lines ordered but not delivered
2685
2686 if (empty($num_prod)) {
2687 print '<tr><td colspan="8"><span class="opacitymedium">'.$langs->trans("NoLineGoOnTabToAddSome", $langs->transnoentitiesnoconv("ShipmentDistribution")).'</span></td></tr>';
2688 }
2689
2690 print "</table>\n";
2691 print '</tbody>';
2692 print '</div>';
2693
2694
2695 print dol_get_fiche_end();
2696
2697
2698 $object->fetchObjectLinked($object->id, $object->element);
2699
2700
2701 /*
2702 * Boutons actions
2703 */
2704
2705 if (($user->socid == 0) && ($action != 'presend')) {
2706 print '<div class="tabsAction">';
2707
2708 $parameters = array();
2709 $reshook = $hookmanager->executeHooks('addMoreActionsButtons', $parameters, $object, $action); // Note that $action and $object may have been
2710 // modified by hook
2711 if (empty($reshook)) {
2712 if ($object->status == Expedition::STATUS_DRAFT && $num_prod > 0) {
2713 if ((!getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && $user->hasRight('expedition', 'creer'))
2714 || (getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && $user->hasRight('expedition', 'shipping_advance', 'validate'))) {
2715 print dolGetButtonAction('', $langs->trans('Validate'), 'default', $_SERVER["PHP_SELF"].'?action=valid&token='.newToken().'&id='.$object->id, '');
2716 } else {
2717 print dolGetButtonAction($langs->trans('NotAllowed'), $langs->trans('Validate'), 'default', $_SERVER['PHP_SELF']. '#', '', false);
2718 }
2719 }
2720
2721 // 0=draft, 1=validated/delivered, 2=closed/delivered
2722 if ($object->status == Expedition::STATUS_VALIDATED && !getDolGlobalString('STOCK_CALCULATE_ON_SHIPMENT')) {
2723 if ($user->hasRight('expedition', 'creer')) {
2724 print dolGetButtonAction('', $langs->trans('SetToDraft'), 'default', $_SERVER["PHP_SELF"].'?action=setdraft&token='.newToken().'&id='.$object->id, '');
2725 }
2726 }
2727 if ($object->status == Expedition::STATUS_CLOSED) {
2728 if ($user->hasRight('expedition', 'creer')) {
2729 print dolGetButtonAction('', $langs->trans('ReOpen'), 'default', $_SERVER["PHP_SELF"].'?action=reopen&token='.newToken().'&id='.$object->id, '');
2730 }
2731 }
2732
2733 // Send
2734 if (empty($user->socid)) {
2735 if ($object->status > 0) {
2736 if (!getDolGlobalString('MAIN_USE_ADVANCED_PERMS') || $user->hasRight('expedition', 'shipping_advance', 'send')) {
2737 print dolGetButtonAction('', $langs->trans('SendMail'), 'default', $_SERVER["PHP_SELF"].'?action=presend&token='.newToken().'&id='.$object->id.'&mode=init#formmailbeforetitle', '');
2738 } else {
2739 print dolGetButtonAction('', $langs->trans('SendMail'), 'default', $_SERVER['PHP_SELF']. '#', '', false);
2740 }
2741 }
2742 }
2743
2744 // Create bill
2745 if (isModEnabled('invoice') && ($object->status == Expedition::STATUS_VALIDATED || $object->status == Expedition::STATUS_CLOSED)) {
2746 if ($user->hasRight('facture', 'creer')) {
2747 if (getDolGlobalString('WORKFLOW_BILL_ON_SHIPMENT') !== '0') {
2748 print dolGetButtonAction('', $langs->trans('CreateBill'), 'default', DOL_URL_ROOT.'/compta/facture/card.php?action=create&origin='.$object->element.'&originid='.$object->id.'&socid='.$object->socid, '');
2749 }
2750 }
2751 }
2752
2753 // This is just to generate a delivery receipt
2754 //var_dump($object->linkedObjectsIds['delivery']);
2755 if (getDolGlobalInt('MAIN_SUBMODULE_DELIVERY') && ($object->status == Expedition::STATUS_VALIDATED || $object->status == Expedition::STATUS_CLOSED) && $user->hasRight('expedition', 'delivery', 'creer') && empty($object->linkedObjectsIds['delivery'])) {
2756 print dolGetButtonAction('', $langs->trans('CreateDeliveryOrder'), 'default', $_SERVER["PHP_SELF"].'?action=create_delivery&token='.newToken().'&id='.$object->id, '');
2757 }
2758
2759 // Set Billed and Closed
2760 if ($object->status == Expedition::STATUS_VALIDATED) {
2761 if ($user->hasRight('expedition', 'creer') && $object->status > 0) {
2762 if (!$object->billed && getDolGlobalString('WORKFLOW_BILL_ON_SHIPMENT') !== '0') {
2763 print dolGetButtonAction('', $langs->trans('ClassifyBilled'), 'default', $_SERVER["PHP_SELF"].'?action=classifybilled&token='.newToken().'&id='.$object->id, '');
2764 }
2765 print dolGetButtonAction('', $langs->trans("Close"), 'default', $_SERVER["PHP_SELF"].'?action=classifyclosed&token='.newToken().'&id='.$object->id, '');
2766 }
2767 }
2768
2769 // Cancel
2770 if ($object->status == Expedition::STATUS_VALIDATED) {
2771 if ($user->hasRight('expedition', 'creer')) {
2772 print dolGetButtonAction('', $langs->trans('Cancel'), 'danger', $_SERVER["PHP_SELF"].'?action=cancel&token='.newToken().'&id='.$object->id.'&mode=init#formmailbeforetitle', '');
2773 }
2774 }
2775
2776 // Delete
2777 if ($user->hasRight('expedition', 'supprimer')) {
2778 print dolGetButtonAction('', $langs->trans('Delete'), 'delete', $_SERVER["PHP_SELF"].'?action=delete&token='.newToken().'&id='.$object->id, '');
2779 }
2780 }
2781
2782 print '</div>';
2783 }
2784
2785
2786 /*
2787 * Documents generated
2788 */
2789
2790 if ($action != 'presend' && $action != 'editline') {
2791 print '<div class="fichecenter"><div class="fichehalfleft">';
2792
2793 $objectref = dol_sanitizeFileName($object->ref);
2794 $filedir = $conf->expedition->dir_output."/sending/".$objectref;
2795
2796 $urlsource = $_SERVER["PHP_SELF"]."?id=".$object->id;
2797
2798 $genallowed = $user->hasRight('expedition', 'lire');
2799 $delallowed = $user->hasRight('expedition', 'creer');
2800
2801 print $formfile->showdocuments('expedition', $objectref, $filedir, $urlsource, $genallowed, $delallowed, $object->model_pdf, 1, 0, 0, 28, 0, '', '', '', $soc->default_lang);
2802
2803
2804 // Show links to link elements
2805 $tmparray = $form->showLinkToObjectBlock($object, array(), array('shipping'), 1);
2806 $linktoelem = $tmparray['linktoelem'];
2807 $htmltoenteralink = $tmparray['htmltoenteralink'];
2808 print $htmltoenteralink;
2809
2810 $somethingshown = $form->showLinkedObjectBlock($object, $linktoelem);
2811
2812 // Show online signature link
2813 $useonlinesignature = getDolGlobalInt('EXPEDITION_ALLOW_ONLINESIGN');
2814
2815 if ($object->statut != Expedition::STATUS_DRAFT && $useonlinesignature) {
2816 print '<br><!-- Link to sign -->';
2817 require_once DOL_DOCUMENT_ROOT.'/core/lib/signature.lib.php';
2818 print showOnlineSignatureUrl('expedition', $object->ref, $object).'<br>';
2819 }
2820
2821 print '</div><div class="fichehalfright">';
2822
2823 // List of actions on element
2824 include_once DOL_DOCUMENT_ROOT.'/core/class/html.formactions.class.php';
2825 $formactions = new FormActions($db);
2826 $somethingshown = $formactions->showactions($object, 'shipping', $socid, 1);
2827
2828 print '</div></div>';
2829 }
2830
2831
2832 /*
2833 * Action presend
2834 */
2835
2836 //Select mail models is same action as presend
2837 if (GETPOST('modelselected')) {
2838 $action = 'presend';
2839 }
2840
2841 // Presend form
2842 $modelmail = 'shipping_send';
2843 $defaulttopic = 'SendShippingRef';
2844 $diroutput = $conf->expedition->dir_output.'/sending';
2845 $trackid = 'shi'.$object->id;
2846
2847 include DOL_DOCUMENT_ROOT.'/core/tpl/card_presend.tpl.php';
2848}
2849
2850// End of page
2851llxFooter();
2852$db->close();
$id
Definition account.php:39
if( $user->socid > 0) if(! $user->hasRight('accounting', 'chartofaccount')) $object
Definition card.php:58
if(!defined('NOREQUIRESOC')) if(!defined( 'NOREQUIRETRAN')) if(!defined('NOTOKENRENEWAL')) if(!defined( 'NOREQUIREMENU')) if(!defined('NOREQUIREHTML')) if(!defined( 'NOREQUIREAJAX')) llxHeader($head='', $title='', $help_url='', $target='', $disablejs=0, $disablehead=0, $arrayofjs='', $arrayofcss='', $morequerystring='', $morecssonbody='', $replacemainareaby='', $disablenofollow=0, $disablenoindex=0)
Empty header.
Definition wrapper.php:70
Class to manage customers orders.
Class to manage a WYSIWYG editor.
Class to manage warehouses.
const STATUS_DRAFT
Draft status.
const STATUS_CLOSED
Closed status -> parcel was received by customer / end of process prev status : validated or shipment...
const STATUS_VALIDATED
Validated status -> parcel is ready to be sent prev status : draft next status : closed or shipment_i...
Class to manage lines of shipment.
CRUD class for batch number management within shipment.
Class to manage standard extra fields.
Class to manage building of HTML components.
Class to offer components to list and upload files.
Class to manage generation of HTML components Only common components must be here.
Class with static methods for building HTML components related to products Only components common to ...
Class to manage building of HTML components.
static liste_modeles($db, $maxfilenamelength=0)
Return list of active generation modules.
Class to manage the table of subscription to notifications.
Class to manage order lines.
Class to manage products or services.
const TYPE_PRODUCT
Regular product.
const TYPE_SERVICE
Service.
Manage record for batch number management.
Class with list of lots and properties.
Class to manage projects.
Class to manage proposals.
Class to manage third parties objects (customers, suppliers, prospects...)
Class to manage translations.
Class to manage Dolibarr users.
llxFooter()
Footer empty.
Definition document.php:107
print $script_file $mode $langs defaultlang(is_numeric($duration_value) ? " delay=". $duration_value :"").(is_numeric($duration_value2) ? " after cd cd cd description as description
Only used if Module[ID]Desc translation string is not found.
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...
load_fiche_titre($title, $morehtmlright='', $picto='generic', $pictoisfullpath=0, $id='', $morecssontable='', $morehtmlcenter='')
Load a title with picto.
img_object($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0)
Show a picto called object_picto (generic function)
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='', $noduplicate=0, $attop=0)
Set event messages in dol_events session object.
img_warning($titlealt='default', $moreatt='', $morecss='pictowarning')
Show warning logo.
img_delete($titlealt='default', $other='class="pictodelete"', $morecss='')
Show delete logo.
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2)
Show picto whatever it's its name (generic function)
GETPOSTINT($paramname, $method=0)
Return the value of a $_GET or $_POST supervariable, converted into integer.
dol_get_fiche_head($links=array(), $active='', $title='', $notab=0, $picto='', $pictoisfullpath=0, $morehtmlright='', $morecss='', $limittoshow=0, $moretabssuffix='', $dragdropfile=0)
Show tabs of a record.
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
dol_get_fiche_end($notab=0)
Return tab footer of a card.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
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).
showDimensionInBestUnit($dimension, $unit, $type, $outputlangs, $round=-1, $forceunitoutput='no', $use_short_label=0)
Output a dimension with best unit.
newToken()
Return the value of token currently saved into session with name 'newtoken'.
dol_clone($object, $native=0)
Create a clone of instance of object (new instance with same value for each properties) With native =...
dolGetButtonAction($label, $text='', $actionType='default', $url='', $id='', $userRight=1, $params=array())
Function dolGetButtonAction.
print_date_range($date_start, $date_end, $format='', $outputlangs=null)
Format output for start and end date.
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_sanitizeFileName($str, $newstr='_', $unaccent=1)
Clean a string to use it as a file name.
dol_print_error($db=null, $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
dol_htmlentitiesbr($stringtoencode, $nl2brmode=0, $pagecodefrom='UTF-8', $removelasteolbr=1)
This function is called to encode a string into a HTML string but differs from htmlentities because a...
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
info_admin($text, $infoonimgalt=0, $nodiv=0, $admin='1', $morecss='hideonsmartphone', $textfordropdown='', $picto='')
Show information in HTML for admin users or standard users.
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.
measuringUnitString($unit, $measuring_style='', $scale='', $use_short_label=0, $outputlangs=null)
Return translation label of a unit key.
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.
shipping_prepare_head($object)
Prepare array with list of tabs.