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