dolibarr 23.0.3
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-2025 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-2025 MDW <mdeweerd@users.noreply.github.com>
18 * Copyright (C) 2025 Nick Fragoulis
19 * Copyright (C) 2025 Charlene Benke <charlene@patas-monkey.com>
20 *
21 * This program is free software; you can redistribute it and/or modify
22 * it under the terms of the GNU General Public License as published by
23 * the Free Software Foundation; either version 3 of the License, or
24 * (at your option) any later version.
25 *
26 * This program is distributed in the hope that it will be useful,
27 * but WITHOUT ANY WARRANTY; without even the implied warranty of
28 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29 * GNU General Public License for more details.
30 *
31 * You should have received a copy of the GNU General Public License
32 * along with this program. If not, see <https://www.gnu.org/licenses/>.
33 */
34
41// Load Dolibarr environment
42require '../main.inc.php';
52require_once DOL_DOCUMENT_ROOT . '/core/class/html.formfile.class.php';
53require_once DOL_DOCUMENT_ROOT . '/expedition/class/expedition.class.php';
54require_once DOL_DOCUMENT_ROOT . '/product/class/html.formproduct.class.php';
55require_once DOL_DOCUMENT_ROOT . '/core/lib/product.lib.php';
56require_once DOL_DOCUMENT_ROOT . '/core/lib/sendings.lib.php';
57require_once DOL_DOCUMENT_ROOT . '/core/modules/expedition/modules_expedition.php';
58require_once DOL_DOCUMENT_ROOT . '/core/class/doleditor.class.php';
59require_once DOL_DOCUMENT_ROOT . '/core/class/extrafields.class.php';
60require_once DOL_DOCUMENT_ROOT . '/product/stock/class/entrepot.class.php';
61require_once DOL_DOCUMENT_ROOT . '/product/stock/class/productlot.class.php';
62require_once DOL_DOCUMENT_ROOT . '/commande/class/commande.class.php';
63if (isModEnabled("product") || isModEnabled("service")) {
64 require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
65}
66if (isModEnabled("propal")) {
67 require_once DOL_DOCUMENT_ROOT . '/comm/propal/class/propal.class.php';
68}
69if (isModEnabled('productbatch')) {
70 require_once DOL_DOCUMENT_ROOT . '/product/class/productbatch.class.php';
71}
72if (isModEnabled('project')) {
73 require_once DOL_DOCUMENT_ROOT . '/projet/class/project.class.php';
74 require_once DOL_DOCUMENT_ROOT . '/core/class/html.formprojet.class.php';
75}
76
77// Load translation files required by the page
78$langs->loadLangs(array("sendings", "companies", "bills", 'orders', 'stocks', 'other', 'propal', 'productbatch'));
79
80if (isModEnabled('incoterm')) {
81 $langs->load('incoterm');
82}
83if (isModEnabled('productbatch')) {
84 $langs->load('productbatch');
85}
86
87
88$origin = GETPOST('origin', 'alpha'); // Example: commande, propal
89$origin_id = GETPOSTINT('origin_id') ? GETPOSTINT('id') : '';
90$id = GETPOSTINT('id');
91
92
93if (empty($origin_id) && !empty($origin)) {
94 $origin_id = GETPOSTINT('origin_id'); // Id of order or propal
95}
96if (empty($origin_id) && !empty($origin)) {
97 $origin_id = GETPOSTINT('object_id'); // Id of order or propal
98}
99$socid = GETPOSTINT('socid');
100$ref = GETPOST('ref', 'alpha');
101$line_id = GETPOSTINT('lineid');
102$facid = GETPOSTINT('facid');
103$contactid = GETPOSTINT('contactid');
104$projectid = GETPOSTINT('projectid');
105$action = GETPOST('action', 'alpha');
106$confirm = GETPOST('confirm', 'alpha');
107$cancel = GETPOST('cancel', 'alpha');
108$rank = (GETPOSTINT('rank') > 0) ? GETPOSTINT('rank') : -1;
109$lineid = GETPOSTINT('lineid');
110$backtopage = GETPOST('backtopage', 'alpha');
111
112//PDF
113$hidedetails = (GETPOSTINT('hidedetails') ? GETPOSTINT('hidedetails') : (getDolGlobalString('MAIN_GENERATE_DOCUMENTS_HIDE_DETAILS') ? 1 : 0));
114$hidedesc = (GETPOSTINT('hidedesc') ? GETPOSTINT('hidedesc') : (getDolGlobalString('MAIN_GENERATE_DOCUMENTS_HIDE_DESC') ? 1 : 0));
115$hideref = (GETPOSTINT('hideref') ? GETPOSTINT('hideref') : (getDolGlobalString('MAIN_GENERATE_DOCUMENTS_HIDE_REF') ? 1 : 0));
116
117$object = new Expedition($db);
118$objectorder = new Commande($db);
119$extrafields = new ExtraFields($db);
120
121// fetch optionals attributes and labels
122$extrafields->fetch_name_optionals_label($object->table_element);
123$extrafields->fetch_name_optionals_label($object->table_element_line);
124$extrafields->fetch_name_optionals_label($objectorder->table_element_line);
125
126// Load object. Make an object->fetch
127include DOL_DOCUMENT_ROOT . '/core/actions_fetchobject.inc.php'; // Must be 'include', not 'include_once'
128
129// Permissions / Rights
130$usercanread = $user->hasRight("expedition", "lire");
131$usercancreate = $user->hasRight("expedition", "creer");
132$usercandelete = $user->hasRight("expedition", "supprimer");
133
134// Initialize a technical object to manage hooks of page. Note that conf->hooks_modules contains an array of hook context
135$hookmanager->initHooks(array('expeditioncard', 'globalcard'));
136
137$date_delivery = dol_mktime(GETPOSTINT('date_deliveryhour'), GETPOSTINT('date_deliverymin'), 0, GETPOSTINT('date_deliverymonth'), GETPOSTINT('date_deliveryday'), GETPOSTINT('date_deliveryyear'));
138
139$date_shipping = dol_mktime(GETPOSTINT('date_shippinghour'), GETPOSTINT('date_shippingmin'), 0, GETPOSTINT('date_shippingmonth'), GETPOSTINT('date_shippingday'), GETPOSTINT('date_shippingyear'));
140
141
142
143// Security check
144
145if ($user->socid) {
146 $socid = $user->socid;
147}
148
149$result = restrictedArea($user, 'expedition', $object->id, '');
150
151$permissiondellink = $user->hasRight('expedition', 'delivery', 'creer'); // Used by the include of actions_dellink.inc.php
152$permissiontoadd = $user->hasRight('expedition', 'creer');
153$permissiontoedit = $usercancreate; // Used by the include of actions_lineupdown.inc.php
154$permissiontoeditextra = $permissiontoadd;
155if (GETPOST('attribute', 'aZ09') && isset($extrafields->attributes[$object->table_element]['perms'][GETPOST('attribute', 'aZ09')])) {
156 // For action 'update_extras', is there a specific permission set for the attribute to update
157 $permissiontoeditextra = dol_eval((string) $extrafields->attributes[$object->table_element]['perms'][GETPOST('attribute', 'aZ09')]);
158}
159
160$upload_dir = $conf->expedition->dir_output . '/sending';
161
162$editColspan = 0;
163$objectsrc = null;
164$typeobject = null;
165$ref_customer = null;
166$shipping_method_id = null;
167$warehouse_id = null;
168$note_public = null;
169$note_private = null;
170
171/*
172 * Actions
173 */
174
175$error = 0;
176$parameters = array();
177$reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
178if ($reshook < 0) {
179 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
180}
181
182if (empty($reshook)) {
183 $backurlforlist = DOL_URL_ROOT.'/expedition/list.php';
184
185 if (empty($backtopage) || ($cancel && empty($id))) {
186 if (empty($backtopage) || ($cancel && strpos($backtopage, '__ID__'))) {
187 if (empty($id) && (($action != 'add' && $action != 'create') || $cancel)) {
188 $backtopage = $backurlforlist;
189 } else {
190 $backtopage = DOL_URL_ROOT.'/expedition/card.php?id='.((!empty($id) && $id > 0) ? $id : '__ID__');
191 }
192 }
193 }
194
195 if ($cancel) {
196 if (!empty($backtopageforcancel)) {
197 header("Location: ".$backtopageforcancel);
198 exit;
199 } elseif (!empty($backtopage)) {
200 header("Location: ".$backtopage);
201 exit;
202 }
203 $action = '';
204 }
205
206
207 if ($cancel) {
208 if ($origin_id > 0) {
209 if ($origin == 'commande') {
210 header("Location: " . DOL_URL_ROOT . '/expedition/shipment.php?id=' . ((int) $origin_id));
211 exit;
212 }
213 } else {
214 $action = '';
215 $object->fetch($object->id); // show shipment also after canceling modification
216 }
217 }
218
219 include DOL_DOCUMENT_ROOT . '/core/actions_dellink.inc.php'; // Must be 'include', not 'include_once'
220
221 // Actions to build doc
222 include DOL_DOCUMENT_ROOT . '/core/actions_builddoc.inc.php';
223
224 // Back to draft
225 if ($action == 'setdraft' && $permissiontoadd) {
226 $object->fetch($id);
227 $result = $object->setDraft($user, 0);
228 if ($result < 0) {
229 setEventMessages($object->error, $object->errors, 'errors');
230 } else {
231 header("Location: " . $_SERVER['PHP_SELF'] . "?id=" . $object->id);
232 exit;
233 }
234 }
235 // Reopen
236 if ($action == 'reopen' && $permissiontoadd) {
237 $object->fetch($id);
238 $result = $object->reOpen();
239 if ($result < 0) {
240 setEventMessages($object->error, $object->errors, 'errors');
241 } else {
242 header("Location: " . $_SERVER['PHP_SELF'] . "?id=" . $object->id);
243 exit;
244 }
245 }
246
247 // Set incoterm
248 if ($action == 'set_incoterms' && isModEnabled('incoterm') && $permissiontoadd) {
249 $result = $object->setIncoterms(GETPOSTINT('incoterm_id'), GETPOST('location_incoterms'));
250 }
251
252 if ($action == 'setref_customer' && $permissiontoadd) {
253 $result = $object->fetch($id);
254 if ($result < 0) {
255 setEventMessages($object->error, $object->errors, 'errors');
256 }
257
258 $result = $object->setValueFrom('ref_customer', GETPOST('ref_customer', 'alpha'), '', null, 'text', '', $user, 'SHIPPING_MODIFY');
259 if ($result < 0) {
260 setEventMessages($object->error, $object->errors, 'errors');
261 $action = 'editref_customer';
262 } else {
263 header("Location: " . $_SERVER['PHP_SELF'] . "?id=" . $object->id);
264 exit;
265 }
266 }
267
268 if ($action == 'update_extras' && $permissiontoeditextra) {
269 $object->oldcopy = dol_clone($object, 2);
270
271 $attribute_name = GETPOST('attribute', 'aZ09');
272
273 // Fill array 'array_options' with data from update form
274 $ret = $extrafields->setOptionalsFromPost(null, $object, $attribute_name);
275 if ($ret < 0) {
276 $error++;
277 }
278
279 if (!$error) {
280 // Actions on extra fields
281 $result = $object->updateExtraField($attribute_name, 'SHIPPING_MODIFY');
282 if ($result < 0) {
283 setEventMessages($object->error, $object->errors, 'errors');
284 $error++;
285 }
286 }
287
288 if ($error) {
289 $action = 'edit_extras';
290 }
291 }
292
293 // Create shipment
294 if ($action == 'add' && $permissiontoadd) {
295 $db->begin();
296
297 if ($origin && $origin_id > 0) {
298 // We will loop on each line of the original document to complete the shipping object with various info and quantity to deliver
299 $classname = ucfirst($origin);
300 $objectsrc = new $classname($db);
301 '@phan-var-force Facture|Commande $objectsrc';
302 $objectsrc->fetch($origin_id);
303 $object->socid = $objectsrc->socid;
304 }
305
306 if (GETPOSTINT('socid') < 1 && $object->socid < 1) {
307 $error++;
308 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("ThirdParty")), null, 'errors');
309 $action = 'create';
310 }
311
312 if (!$origin && getDolGlobalString('SHIPMENT_STANDALONE')) {
313 $object->socid = GETPOSTINT('socid');
314 $object->fetch_thirdparty();
315
316 $object->origin = $origin; // deprecated
317 $object->origin_type = $origin;
318 $object->origin_id = $origin_id;
319 $object->fk_project = GETPOSTINT('projectid');
320 $object->weight = GETPOST('weight') == '' ? '' : GETPOSTFLOAT('weight');
321 $object->sizeH = GETPOST('sizeH') == '' ? '' : GETPOSTFLOAT('sizeH');
322 $object->sizeW = GETPOST('sizeW') == '' ? '' : GETPOSTFLOAT('sizeW');
323 $object->sizeS = GETPOST('sizeS') == '' ? '' : GETPOSTFLOAT('sizeS');
324 $object->size_units = GETPOSTINT('size_units');
325 $object->weight_units = GETPOSTINT('weight_units');
326 $object->ref_customer = GETPOST('ref_customer', 'alpha');
327 $object->model_pdf = GETPOST('model');
328 $object->date_delivery = $date_delivery; // Date delivery planned
329 $object->date_shipping = $date_shipping; // Sending date
330 $object->shipping_method_id = GETPOSTINT('shipping_method_id');
331 $object->tracking_number = GETPOST('tracking_number', 'alpha');
332 $object->note = GETPOST('note_private', 'restricthtml'); // deprecated
333 $object->note_private = GETPOST('note_private', 'restricthtml');
334 $object->note_public = GETPOST('note_public', 'restricthtml');
335 $object->fk_incoterms = GETPOSTINT('incoterm_id');
336 $object->location_incoterms = GETPOST('location_incoterms', 'alpha');
337
338 $product = new Product($db);
339
340 // Fill array 'array_options' with data from add form
341 $ret = $extrafields->setOptionalsFromPost(null, $object);
342 if ($ret < 0) {
343 $error++;
344 }
345
346 if (!$error) {
347 $ret = $object->create($user);
348 if ($ret <= 0) {
349 setEventMessages($object->error, $object->errors, 'errors');
350 $error++;
351 }
352 }
353 }
354
355 if ($origin && $origin_id > 0) {
356 $object->origin = $origin; // deprecated
357 $object->origin_type = $origin;
358 $object->origin_id = $origin_id;
359 $object->fk_project = GETPOSTINT('projectid');
360 $object->weight = GETPOST('weight') == '' ? '' : GETPOSTFLOAT('weight');
361 $object->sizeH = GETPOST('sizeH') == '' ? '' : GETPOSTFLOAT('sizeH');
362 $object->sizeW = GETPOST('sizeW') == '' ? '' : GETPOSTFLOAT('sizeW');
363 $object->sizeS = GETPOST('sizeS') == '' ? '' : GETPOSTFLOAT('sizeS');
364 $object->size_units = GETPOSTINT('size_units');
365 $object->weight_units = GETPOSTINT('weight_units');
366 $object->ref_customer = GETPOST('ref_customer', 'alpha');
367 $object->model_pdf = GETPOST('model');
368 $object->date_delivery = $date_delivery; // Date delivery planned
369 $object->date_shipping = $date_shipping; // Sending date
370 $object->shipping_method_id = GETPOSTINT('shipping_method_id');
371 $object->tracking_number = GETPOST('tracking_number', 'alpha');
372 $object->note = GETPOST('note_private', 'restricthtml'); // deprecated
373 $object->note_private = GETPOST('note_private', 'restricthtml');
374 $object->note_public = GETPOST('note_public', 'restricthtml');
375 $object->fk_incoterms = GETPOSTINT('incoterm_id');
376 $object->location_incoterms = GETPOST('location_incoterms', 'alpha');
377
378 // We will loop on each line of the original document to complete the shipping object with various info and quantity to deliver
379 $classname = ucfirst($object->origin_type);
380 $objectsrc = new $classname($db);
381 '@phan-var-force Facture|Commande $objectsrc';
382 $objectsrc->fetch($object->origin_id);
383
384 $object->socid = $objectsrc->socid;
385 $object->fk_delivery_address = $objectsrc->fk_delivery_address;
386
387 $product = new Product($db);
388
389 $batch_line = array();
390 $stockLine = array();
391 $array_options = array();
392
393 $num = count($objectsrc->lines);
394 $totalqty = 0;
395
396 $product_batch_used = array();
397
398 for ($i = 0; $i < $num; $i++) {
399 $idl = "idl" . $i;
400
401 $sub_qty = array();
402 $subtotalqty = 0;
403
404 $j = 0;
405
406 $batch = "batchl" . $i . "_0";
407 $stockLocation = "ent1" . $i . "_0";
408 $qty = "qtyl" . $i;
409
410 $is_batch_or_serial = 0;
411 if (!empty($objectsrc->lines[$i]->fk_product)) {
412 $resultFetch = $product->fetch($objectsrc->lines[$i]->fk_product, '', '', '', 1, 1, 1);
413 if ($resultFetch < 0) {
414 setEventMessages($product->error, $product->errors, 'errors');
415 }
416 $is_batch_or_serial = $product->status_batch;
417 }
418
419 // If product need a batch or serial number
420 if (isModEnabled('productbatch') && $objectsrc->lines[$i]->product_tobatch) {
421 if (GETPOSTISSET($batch)) {
422 //shipment line with batch-enable product
423 $qty .= '_' . $j;
424 while (GETPOSTISSET($batch)) {
425 // save line of detail into sub_qty
426 $sub_qty[$j]['q'] = price2num(GETPOST($qty, 'alpha'), 'MS'); // the qty we want to move for this stock record
427 $sub_qty[$j]['id_batch'] = GETPOSTINT($batch); // the id into llx_product_batch of stock record to move
428 $subtotalqty += $sub_qty[$j]['q'];
429
430 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)))) {
431 setEventMessages($langs->trans("TooManyQtyForSerialNumber", $product->ref, ''), null, 'errors');
432 $totalqty = 0;
433 break 2;
434 }
435
436 if ($is_batch_or_serial == 2 && $sub_qty[$j]['q'] > 0) {
437 // we stock the batch id to test later if the same serial is shipped on another line for the same product
438 $product_batch_used[$j] = $sub_qty[$j]['id_batch'];
439 }
440
441 $j++;
442 $batch = "batchl" . $i . "_" . $j;
443 $qty = "qtyl" . $i . '_' . $j;
444 }
445
446 $batch_line[$i]['detail'] = $sub_qty; // array of details
447 $batch_line[$i]['qty'] = $subtotalqty;
448 $batch_line[$i]['ix_l'] = GETPOSTINT($idl);
449
450 $totalqty += $subtotalqty;
451 } else {
452 // No detail were provided for lots, so if a qty was provided, we can throw an error.
453 if (GETPOST($qty)) {
454 // We try to set an amount
455 // Case we don't use the list of available qty for each warehouse/lot
456 // GUI does not allow this yet
457 setEventMessages($langs->trans("StockIsRequiredToChooseWhichLotToUse") . ' (' . $langs->trans("Line") . ' ' . GETPOSTINT($idl) . ')', null, 'errors');
458 $error++;
459 }
460 }
461 } elseif (GETPOSTISSET($stockLocation)) {
462 //shipment line from multiple stock locations
463 $qty .= '_' . $j;
464 while (GETPOSTISSET($stockLocation)) {
465 // save sub line of warehouse
466 $stockLine[$i][$j]['qty'] = price2num(GETPOST($qty, 'alpha'), 'MS');
467 $stockLine[$i][$j]['warehouse_id'] = GETPOSTINT($stockLocation);
468 $stockLine[$i][$j]['ix_l'] = GETPOSTINT($idl);
469
470 $totalqty += price2num(GETPOST($qty, 'alpha'), 'MS');
471 $subtotalqty += price2num(GETPOST($qty, 'alpha'), 'MS');
472
473 $j++;
474 $stockLocation = "ent1" . $i . "_" . $j;
475 $qty = "qtyl" . $i . '_' . $j;
476 }
477 } else {
478 //shipment line for product with no batch management and no multiple stock location
479 if (GETPOSTFLOAT($qty) > 0) {
480 $totalqty += price2num(GETPOST($qty, 'alpha'), 'MS');
481 $subtotalqty = price2num(GETPOST($qty, 'alpha'), 'MS');
482 }
483 }
484
485 // check qty shipped not greater than ordered
486 if (getDolGlobalInt("MAIN_DONT_SHIP_MORE_THAN_ORDERED") && $subtotalqty > $objectsrc->lines[$i]->qty) {
487 setEventMessages($langs->trans("ErrorTooMuchShipped", $i + 1), null, 'errors');
488 $error++;
489 continue;
490 }
491
492 // Extrafields
493 $array_options[$i] = $extrafields->getOptionalsFromPost($object->table_element_line, (string) $i);
494 // Unset extrafield
495 if (isset($extrafields->attributes[$object->table_element_line]['label']) && is_array($extrafields->attributes[$object->table_element_line]['label'])) {
496 // Get extra fields
497 foreach ($extrafields->attributes[$object->table_element_line]['label'] as $key => $value) {
498 unset($_POST["options_" . $key]);
499 }
500 }
501 }
502
503 if (($totalqty > 0 || getDolGlobalString('SHIPMENT_GETS_ALL_ORDER_PRODUCTS')) && !$error) { // There is at least one thing to ship and no error
504 $selected_subtotal_lines = GETPOST('subtotal_toselect', 'array:int');
505 for ($i = 0; $i < $num; $i++) {
506 $qty = "qtyl" . $i;
507
508 if (!isset($batch_line[$i])) {
509 // not batch mode
510 if (isset($stockLine[$i])) {
511 //shipment from multiple stock locations
512 $nbstockline = count($stockLine[$i]);
513 for ($j = 0; $j < $nbstockline; $j++) {
514 if ($stockLine[$i][$j]['qty'] > 0 || ($stockLine[$i][$j]['qty'] == 0 && getDolGlobalString('SHIPMENT_GETS_ALL_ORDER_PRODUCTS'))) {
515 $ret = $object->addline($stockLine[$i][$j]['warehouse_id'], $stockLine[$i][$j]['ix_l'], (float) $stockLine[$i][$j]['qty'], $array_options[$i]);
516 if ($ret < 0) {
517 setEventMessages($object->error, $object->errors, 'errors');
518 $error++;
519 }
520 }
521 }
522 } else {
523 if (GETPOSTFLOAT($qty) > 0 || getDolGlobalString('SHIPMENT_GETS_ALL_ORDER_PRODUCTS')) {
524 $ent = "entl" . $i;
525 $idl = "idl" . $i;
526 $entrepot_id = is_numeric(GETPOSTINT($ent)) ? GETPOSTINT($ent) : GETPOSTINT('entrepot_id');
527 if ($entrepot_id < 0) {
528 $entrepot_id = '';
529 }
530 if (!($objectsrc->lines[$i]->fk_product > 0)) {
531 $entrepot_id = 0;
532 }
533
534
535 $ret = $object->addline($entrepot_id, GETPOSTINT($idl), (float) price2num(GETPOSTFLOAT($qty), 'MS'), $array_options[$i]);
536 if ($ret < 0) {
537 setEventMessages($object->error, $object->errors, 'errors');
538 $error++;
539 }
540 }
541 if (isModEnabled('subtotals') && $objectsrc->lines[$i]->special_code == SUBTOTALS_SPECIAL_CODE && in_array($objectsrc->lines[$i]->id, $selected_subtotal_lines)) {
542 $object->addSubtotalLine($langs, $objectsrc->lines[$i]->desc, (int) $objectsrc->lines[$i]->qty, $objectsrc->lines[$i]->extraparams, $objectsrc->lines[$i]->id);
543 }
544 }
545 } else {
546 // batch mode
547 if ($batch_line[$i]['qty'] > 0 || ($batch_line[$i]['qty'] == 0 && getDolGlobalString('SHIPMENT_GETS_ALL_ORDER_PRODUCTS'))) {
548 $origin_line_id = (int) $batch_line[$i]['ix_l'];
549 $origin_line = new OrderLine($db);
550 $res = $origin_line->fetch($origin_line_id);
551 if ($res <= 0) {
552 $error++;
553 setEventMessages($origin_line->error, $origin_line->errors, 'errors');
554 }
555 $ret = $object->addline_batch($batch_line[$i], $array_options[$i], $origin_line);
556 if ($ret < 0) {
557 setEventMessages($object->error, $object->errors, 'errors');
558 $error++;
559 }
560 }
561 }
562 }
563 // Fill array 'array_options' with data from add form
564 $ret = $extrafields->setOptionalsFromPost(null, $object);
565 if ($ret < 0) {
566 $error++;
567 }
568
569 if (!$error) {
570 $ret = $object->create($user); // This create shipment (like Odoo picking) and lines of shipments. Stock movement will be done when validating or closing shipment.
571 if ($ret <= 0) {
572 setEventMessages($object->error, $object->errors, 'errors');
573 $error++;
574 }
575 }
576 } elseif (!$error) {
577 $labelfieldmissing = $langs->transnoentitiesnoconv("QtyToShip");
578 if (isModEnabled('stock')) {
579 $labelfieldmissing .= '/' . $langs->transnoentitiesnoconv("Warehouse");
580 }
581 setEventMessages($langs->trans("ErrorFieldRequired", $labelfieldmissing), null, 'errors');
582 $error++;
583 }
584 }
585 if (!$error) {
586 $db->commit();
587 $object->fetch_lines();
588 foreach ($object->lines as $line) {
589 $objectsrc_line = new $objectsrc->class_element_line($db);
590 '@phan-var-force CommonObjectLine $objectsrc_line';
591 $objectsrc_line->fetch($line->origin_line_id);
592 $line->extraparams = $objectsrc_line->extraparams;
593 $line->setExtraParameters();
594 }
595 header("Location: card.php?id=" . $object->id);
596 exit;
597 } else {
598 $db->rollback();
599 //$_GET["commande_id"] = GETPOSTINT('commande_id');
600 $action = 'create';
601 }
602 } elseif ($action == 'create_delivery' && getDolGlobalInt('MAIN_SUBMODULE_DELIVERY') && $user->hasRight('expedition', 'delivery', 'creer')) {
603 // Build a receiving receipt
604 $db->begin();
605
606 $result = $object->create_delivery($user);
607 if ($result > 0) {
608 $db->commit();
609
610 header("Location: " . DOL_URL_ROOT . '/delivery/card.php?action=create_delivery&token=' . newToken() . '&id=' . $result);
611 exit;
612 } else {
613 $db->rollback();
614
615 setEventMessages($object->error, $object->errors, 'errors');
616 }
617 } elseif (
618 $action == 'confirm_valid' && $confirm == 'yes' && ((!getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && $user->hasRight('expedition', 'creer'))
619 || (getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && $user->hasRight('expedition', 'shipping_advance', 'validate')))
620 ) {
621 $object->fetch_thirdparty();
622
623 $result = $object->valid($user);
624
625 if ($result < 0) {
626 setEventMessages($object->error, $object->errors, 'errors');
627 } else {
628 // Define output language
629 if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
630 $outputlangs = $langs;
631 $newlang = '';
632 if (getDolGlobalInt('MAIN_MULTILANGS') /* && empty($newlang) */ && GETPOST('lang_id', 'aZ09')) {
633 $newlang = GETPOST('lang_id', 'aZ09');
634 }
635 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
636 $newlang = $object->thirdparty->default_lang;
637 }
638 if (!empty($newlang)) {
639 $outputlangs = new Translate("", $conf);
640 $outputlangs->setDefaultLang($newlang);
641 }
642 $model = $object->model_pdf;
643 $ret = $object->fetch($id); // Reload to get new records
644
645 $result = $object->generateDocument($model, $outputlangs, $hidedetails, $hidedesc, $hideref);
646 if ($result < 0) {
647 dol_print_error($db, $object->error, $object->errors);
648 }
649 }
650 }
651 } elseif ($action == 'confirm_cancel' && $confirm == 'yes' && $user->hasRight('expedition', 'creer')) {
652 $also_update_stock = (GETPOST('alsoUpdateStock', 'alpha') ? 1 : 0);
653 $result = $object->cancel($user, 0, (bool) $also_update_stock);
654 if ($result > 0) {
655 $result = $object->setStatut(-1);
656 } else {
657 setEventMessages($object->error, $object->errors, 'errors');
658 }
659 } elseif ($action == 'confirm_delete' && $confirm == 'yes' && $user->hasRight('expedition', 'supprimer')) {
660 $also_update_stock = (GETPOST('alsoUpdateStock', 'alpha') ? 1 : 0);
661 $result = $object->delete($user, 0, (bool) $also_update_stock);
662 if ($result > 0) {
663 header("Location: " . DOL_URL_ROOT . '/expedition/index.php');
664 exit;
665 } else {
666 setEventMessages($object->error, $object->errors, 'errors');
667 }
668 // TODO add alternative status
669 //} elseif ($action == 'reopen' && ($user->hasRight('expedition', 'creer') || $user->hasRight('expedition', 'shipping_advance', 'validate')))
670 //{
671 // $result = $object->setStatut(0);
672 // if ($result < 0)
673 // {
674 // setEventMessages($object->error, $object->errors, 'errors');
675 // }
676 //}
677 } elseif ($action == 'confirm_delete_subtotalline' && $confirm == 'yes' && $permissiontoadd) {
678 $result = $object->deleteSubtotalLine($langs, GETPOSTINT('lineid'), (bool) GETPOST('deletecorrespondingsubtotalline'), $user);
679 if ($result > 0) {
680 // reorder lines
681 $object->line_order(true, 'ASC', false);
682 // Define output language
683 $outputlangs = $langs;
684 $newlang = '';
685 if (getDolGlobalInt('MAIN_MULTILANGS') /* && empty($newlang) */ && GETPOST('lang_id', 'aZ09')) {
686 $newlang = GETPOST('lang_id', 'aZ09');
687 }
688 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
689 $newlang = $object->thirdparty->default_lang;
690 }
691 if (!empty($newlang)) {
692 $outputlangs = new Translate("", $conf);
693 $outputlangs->setDefaultLang($newlang);
694 }
695 if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
696 $ret = $object->fetch($object->id); // Reload to get new records
697 $object->generateDocument($object->model_pdf, $outputlangs, $hidedetails, $hidedesc, $hideref);
698 }
699
700 header('Location: ' . $_SERVER["PHP_SELF"] . '?id=' . $object->id);
701 exit;
702 } else {
703 setEventMessages($object->error, $object->errors, 'errors');
704 }
705 } elseif ($action == 'confirm_deleteline' && $confirm == 'yes' && $usercancreate) {
706 // Remove a product line
707 $result = $object->deleteLine($user, $lineid);
708 if ($result > 0) {
709 // reorder lines
710 $object->line_order(true);
711 // Define output language
712 $outputlangs = $langs;
713 $newlang = '';
714 if (getDolGlobalInt('MAIN_MULTILANGS') /* && empty($newlang) */ && GETPOST('lang_id', 'aZ09')) {
715 $newlang = GETPOST('lang_id', 'aZ09');
716 }
717 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
718 $newlang = $object->thirdparty->default_lang;
719 }
720 if (!empty($newlang)) {
721 $outputlangs = new Translate("", $conf);
722 $outputlangs->setDefaultLang($newlang);
723 }
724 if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
725 $ret = $object->fetch($object->id); // Reload to get new records
726 $object->generateDocument($object->model_pdf, $outputlangs, $hidedetails, $hidedesc, $hideref);
727 }
728
729 header('Location: ' . $_SERVER["PHP_SELF"] . '?id=' . $object->id);
730 exit;
731 } else {
732 setEventMessages($object->error, $object->errors, 'errors');
733 }
734 } elseif ($action == 'confirm_sign' && $confirm == 'yes' && $user->hasRight('expedition', 'creer')) {
735 $result = $object->setSignedStatus($user, GETPOSTINT('signed_status'), 0, 'SHIPPING_MODIFY');
736 if ($result >= 0) {
737 header('Location: ' . $_SERVER["PHP_SELF"] . '?id=' . $object->id);
738 exit;
739 } else {
740 setEventMessages($object->error, $object->errors, 'errors');
741 }
742 } elseif ($action == 'confirm_unsign' && $confirm == 'yes' && $user->hasRight('expedition', 'creer')) {
743 $result = $object->setSignedStatus($user, Expedition::$SIGNED_STATUSES['STATUS_NO_SIGNATURE'], 0, 'SHIPPING_MODIFY');
744 if ($result >= 0) {
745 header('Location: ' . $_SERVER["PHP_SELF"] . '?id=' . $object->id);
746 exit;
747 } else {
748 setEventMessages($object->error, $object->errors, 'errors');
749 }
750 } elseif ($action == 'setdate_livraison' && $user->hasRight('expedition', 'creer')) {
751 $datedelivery = dol_mktime(GETPOSTINT('liv_hour'), GETPOSTINT('liv_min'), 0, GETPOSTINT('liv_month'), GETPOSTINT('liv_day'), GETPOSTINT('liv_year'));
752
753 $object->fetch($id);
754 $result = $object->setDeliveryDate($user, $datedelivery); // Set the planned delivery date
755 if ($result < 0) {
756 setEventMessages($object->error, $object->errors, 'errors');
757 }
758 } elseif ($action == 'setdate_shipping' && $user->hasRight('expedition', 'creer')) {
759 $dateshipping = dol_mktime(GETPOSTINT('ship_hour'), GETPOSTINT('ship_min'), 0, GETPOSTINT('ship_month'), GETPOSTINT('ship_day'), GETPOSTINT('ship_year'));
760
761 $object->fetch($id);
762 $result = $object->setShippingDate($user, $dateshipping);
763 if ($result < 0) {
764 setEventMessages($object->error, $object->errors, 'errors');
765 }
766 } elseif (in_array($action, array('settracking_number', 'settracking_url', 'settrueWeight', 'settrueWidth', 'settrueHeight', 'settrueDepth', 'setshipping_method_id')) && $user->hasRight('expedition', 'creer')) {
767 // Action update
768 $error = 0;
769
770 if ($action == 'settracking_number') { // Test on permission not required
771 $object->tracking_number = trim(GETPOST('tracking_number', 'alpha'));
772 }
773 if ($action == 'settracking_url') { // Test on permission not required
774 $object->tracking_url = trim(GETPOST('tracking_url', 'restricthtml'));
775 }
776
777 if ($action == 'settrueWeight') { // Test on permission not required
778 $object->trueWeight = GETPOSTFLOAT('trueWeight');
779 $object->weight_units = GETPOSTINT('weight_units');
780 }
781 if ($action == 'settrueWidth') { // Test on permission not required
782 $object->trueWidth = GETPOSTFLOAT('trueWidth');
783 }
784 if ($action == 'settrueHeight') { // Test on permission not required
785 $object->trueHeight = GETPOSTFLOAT('trueHeight');
786 $object->size_units = GETPOSTINT('size_units');
787 }
788 if ($action == 'settrueDepth') { // Test on permission not required
789 $object->trueDepth = GETPOSTFLOAT('trueDepth');
790 }
791 if ($action == 'setshipping_method_id') { // Test on permission not required
792 $object->shipping_method_id = GETPOSTINT('shipping_method_id');
793 }
794
795 if ($object->update($user) >= 0) {
796 header("Location: card.php?id=" . $object->id);
797 exit;
798 }
799 setEventMessages($object->error, $object->errors, 'errors');
800 $action = "";
801 } elseif ($action == 'classifybilled' && $permissiontoadd) {
802 $object->fetch($id);
803 $result = $object->setBilled();
804 if ($result >= 0) {
805 header('Location: ' . $_SERVER["PHP_SELF"] . '?id=' . $object->id);
806 exit();
807 }
808 setEventMessages($object->error, $object->errors, 'errors');
809 } elseif ($action == 'classifyclosed' && $permissiontoadd) {
810 $object->fetch($id);
811 $result = $object->setClosed();
812 if ($result >= 0) {
813 header('Location: ' . $_SERVER["PHP_SELF"] . '?id=' . $object->id);
814 exit();
815 }
816 setEventMessages($object->error, $object->errors, 'errors');
817 } elseif ($action == 'deleteline' && !empty($line_id) && $permissiontoadd) {
818 // delete a line
819 $object->fetch($id);
820 $lines = $object->lines;
821 $line = new ExpeditionLigne($db);
822 $line->fk_expedition = $object->id;
823
824 $num_prod = count($lines);
825 for ($i = 0; $i < $num_prod; $i++) {
826 if ($lines[$i]->id == $line_id) {
827 if (count($lines[$i]->details_entrepot) > 1) {
828 // delete multi warehouse lines
829 foreach ($lines[$i]->details_entrepot as $details_entrepot) {
830 $line->id = $details_entrepot->line_id;
831 if (!$error && $line->delete($user) < 0) {
832 $error++;
833 }
834 }
835 } else {
836 // delete single warehouse line
837 $line->id = $line_id;
838 if (!$error && $line->delete($user) < 0) {
839 $error++;
840 }
841 }
842 }
843 unset($_POST["lineid"]);
844 }
845
846 if (!$error) {
847 header('Location: ' . $_SERVER["PHP_SELF"] . '?id=' . $object->id);
848 exit();
849 } else {
850 setEventMessages($line->error, $line->errors, 'errors');
851 }
852 } elseif ($action == 'updateline' && $permissiontoadd && GETPOST('save')) {
853 if (!$origin && getDolGlobalString('SHIPMENT_STANDALONE')) {
854 // Update a line
855 // Clean parameters
856
857 if (!$object->fetch($id) > 0) {
858 dol_print_error($db);
859 }
860 $object->fetch_thirdparty();
861
862 $qty = GETPOST('qty', 'alpha');
863 $description = '';
864 $fk_parent = 0;
865 $element_type = 'shipping';
866 $fk_unit = '';
867 $fk_product = 0;
868 $rang = 0;
869
870 // Extrafields
871 $extralabelsline = $extrafields->fetch_name_optionals_label($object->table_element_line);
872 $array_options = $extrafields->getOptionalsFromPost($object->table_element_line);
873 // Unset extrafield
874 if (is_array($extralabelsline)) {
875 // Get extra fields
876 foreach ($extralabelsline as $key => $value) {
877 unset($_POST["options_" . $key]);
878 }
879 }
880
881 $shipline = new ExpeditionLigne($db);
882 $shipline->fetch(GETPOSTINT('lineid'));
883
884
885 if (!$error) {
886 $result = $object->updatelinefree(GETPOSTINT('lineid'), (float) $qty, $element_type, $fk_product, GETPOSTINT('units'), $rang, $description, $fk_parent, 0, $array_options);
887
888 if ($result >= 0) {
889 if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
890 // Define output language
891 $outputlangs = $langs;
892 $newlang = '';
893 if (getDolGlobalInt('MAIN_MULTILANGS') /* && empty($newlang) */ && GETPOST('lang_id', 'aZ09')) {
894 $newlang = GETPOST('lang_id', 'aZ09');
895 }
896 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
897 $newlang = $object->thirdparty->default_lang;
898 }
899 if (!empty($newlang)) {
900 $outputlangs = new Translate("", $conf);
901 $outputlangs->setDefaultLang($newlang);
902 $outputlangs->load('products');
903 }
904
905 $ret = $object->fetch($object->id); // Reload to get new records
906 $object->generateDocument($object->model_pdf, $outputlangs, $hidedetails, $hidedesc, $hideref);
907 }
908 unset($_POST['qty']);
909 unset($_POST['units']);
910 } else {
911 setEventMessages($object->error, $object->errors, 'errors');
912 }
913 }
914 } elseif ($origin && $origin_id > 0) {
915 // Update a line
916 // Clean parameters
917 $qty = 0;
918 $entrepot_id = 0;
919 $batch_id = 0;
920
921 $lines = $object->lines;
922 $num_prod = count($lines);
923 for ($i = 0; $i < $num_prod; $i++) {
924 if ($lines[$i]->id == $line_id) { // we have found line to update
925 $update_done = false;
926 $line = new ExpeditionLigne($db);
927 $line->fk_expedition = $object->id;
928
929 // Extrafields Lines
930 $line->array_options = $extrafields->getOptionalsFromPost($object->table_element_line);
931 // Unset extrafield POST Data
932 if (is_array($extrafields->attributes[$object->table_element_line]['label'])) {
933 foreach ($extrafields->attributes[$object->table_element_line]['label'] as $key => $value) {
934 unset($_POST["options_" . $key]);
935 }
936 }
937 $line->fk_product = $lines[$i]->fk_product;
938 if (is_array($lines[$i]->detail_batch) && count($lines[$i]->detail_batch) > 0) {
939 // line with lot
940 foreach ($lines[$i]->detail_batch as $detail_batch) {
941 $lotStock = new Productbatch($db);
942 $batch = "batchl" . $detail_batch->fk_expeditiondet . "_" . $detail_batch->fk_origin_stock;
943 $qty = "qtyl" . $detail_batch->fk_expeditiondet . '_' . $detail_batch->id;
944 $batch_id = GETPOSTINT($batch);
945 $batch_qty = GETPOSTFLOAT($qty);
946 if (!empty($batch_id)) {
947 if ($lotStock->fetch($batch_id) > 0 && $line->fetch($detail_batch->fk_expeditiondet) > 0) { // $line is ExpeditionLine
948 if ($lines[$i]->entrepot_id != 0) {
949 // allow update line entrepot_id if not multi warehouse shipping
950 $line->entrepot_id = $lotStock->warehouseid;
951 }
952
953 // detail_batch can be an object with keys, or an array of ExpeditionLineBatch
954 if (empty($line->detail_batch)) {
955 $line->detail_batch = new stdClass();
956 }
957
958 $line->detail_batch->fk_origin_stock = $batch_id;
959 $line->detail_batch->batch = $lotStock->batch;
960 $line->detail_batch->id = $detail_batch->id;
961 $line->detail_batch->entrepot_id = $lotStock->warehouseid;
962 $line->detail_batch->qty = $batch_qty;
963 if ($line->update($user) < 0) {
964 setEventMessages($line->error, $line->errors, 'errors');
965 $error++;
966 } else {
967 $update_done = true;
968 }
969 } else {
970 setEventMessages($lotStock->error, $lotStock->errors, 'errors');
971 $error++;
972 }
973 }
974 unset($_POST[$batch]);
975 unset($_POST[$qty]);
976 }
977 // add new batch
978 $lotStock = new Productbatch($db);
979 $batch = "batchl" . $line_id . "_0";
980 $qty = "qtyl" . $line_id . "_0";
981 $batch_id = GETPOSTINT($batch);
982 $batch_qty = GETPOSTFLOAT($qty);
983 $lineIdToAddLot = 0;
984 if ($batch_qty > 0 && !empty($batch_id)) {
985 if ($lotStock->fetch($batch_id) > 0) {
986 // check if lotStock warehouse id is same as line warehouse id
987 if ($lines[$i]->entrepot_id > 0) {
988 // single warehouse shipment line
989 if ($lines[$i]->entrepot_id == $lotStock->warehouseid) {
990 $lineIdToAddLot = $line_id;
991 }
992 } elseif (count($lines[$i]->details_entrepot) > 1) {
993 // multi warehouse shipment lines
994 foreach ($lines[$i]->details_entrepot as $detail_entrepot) {
995 if ($detail_entrepot->entrepot_id == $lotStock->warehouseid) {
996 $lineIdToAddLot = $detail_entrepot->line_id;
997 }
998 }
999 }
1000 if ($lineIdToAddLot) {
1001 // add lot to existing line
1002 if ($line->fetch($lineIdToAddLot) > 0) {
1003 $line->detail_batch->fk_origin_stock = $batch_id;
1004 $line->detail_batch->batch = $lotStock->batch;
1005 $line->detail_batch->entrepot_id = $lotStock->warehouseid;
1006 $line->detail_batch->qty = $batch_qty;
1007 if ($line->update($user) < 0) {
1008 setEventMessages($line->error, $line->errors, 'errors');
1009 $error++;
1010 } else {
1011 $update_done = true;
1012 }
1013 } else {
1014 setEventMessages($line->error, $line->errors, 'errors');
1015 $error++;
1016 }
1017 } else {
1018 // create new line with new lot
1019 $line->origin_line_id = $lines[$i]->origin_line_id;
1020 $line->entrepot_id = $lotStock->warehouseid;
1021 $line->detail_batch[0] = new ExpeditionLineBatch($db);
1022 $line->detail_batch[0]->fk_origin_stock = $batch_id;
1023 $line->detail_batch[0]->batch = $lotStock->batch;
1024 $line->detail_batch[0]->entrepot_id = $lotStock->warehouseid;
1025 $line->detail_batch[0]->qty = $batch_qty;
1026 if ($object->create_line_batch($line, $line->array_options) < 0) {
1027 setEventMessages($object->error, $object->errors, 'errors');
1028 $error++;
1029 } else {
1030 $update_done = true;
1031 }
1032 }
1033 } else {
1034 setEventMessages($lotStock->error, $lotStock->errors, 'errors');
1035 $error++;
1036 }
1037 }
1038 } else {
1039 if ($lines[$i]->fk_product > 0) {
1040 // line without lot
1041 if ($lines[$i]->entrepot_id == 0) {
1042 // single warehouse shipment line or line in several warehouses context but with warehouse not defined
1043 $stockLocation = "entl" . $line_id;
1044 $qty = "qtyl" . $line_id;
1045 $line->id = $line_id;
1046 $line->entrepot_id = GETPOSTINT((string) $stockLocation);
1047 $line->qty = GETPOSTFLOAT($qty);
1048 if ($line->update($user) < 0) {
1049 setEventMessages($line->error, $line->errors, 'errors');
1050 $error++;
1051 }
1052 unset($_POST[$stockLocation]);
1053 unset($_POST[$qty]);
1054 } elseif ($lines[$i]->entrepot_id > 0) {
1055 // single warehouse shipment line
1056 $stockLocation = "entl" . $line_id;
1057 $qty = "qtyl" . $line_id;
1058 $line->id = $line_id;
1059 $line->entrepot_id = GETPOSTINT($stockLocation);
1060 $line->qty = GETPOSTFLOAT($qty);
1061 if ($line->update($user) < 0) {
1062 setEventMessages($line->error, $line->errors, 'errors');
1063 $error++;
1064 }
1065 unset($_POST[$stockLocation]);
1066 unset($_POST[$qty]);
1067 } elseif (count($lines[$i]->details_entrepot) > 1) {
1068 // multi warehouse shipment lines
1069 foreach ($lines[$i]->details_entrepot as $detail_entrepot) {
1070 if (!$error) {
1071 $stockLocation = "entl" . $detail_entrepot->line_id;
1072 $qty = "qtyl" . $detail_entrepot->line_id;
1073 $warehouse = GETPOSTINT($stockLocation);
1074 if (!empty($warehouse)) {
1075 $line->id = $detail_entrepot->line_id;
1076 $line->entrepot_id = $warehouse;
1077 $line->qty = GETPOSTFLOAT($qty);
1078 if ($line->update($user) < 0) {
1079 setEventMessages($line->error, $line->errors, 'errors');
1080 $error++;
1081 } else {
1082 $update_done = true;
1083 }
1084 }
1085 unset($_POST[$stockLocation]);
1086 unset($_POST[$qty]);
1087 }
1088 }
1089 } elseif (!isModEnabled('stock') && !isModEnabled('productbatch')) { // both product batch and stock are not activated.
1090 $qty = "qtyl" . $line_id;
1091 $line->id = $line_id;
1092 $line->qty = GETPOSTFLOAT($qty);
1093 $line->entrepot_id = 0;
1094 if ($line->update($user) < 0) {
1095 setEventMessages($line->error, $line->errors, 'errors');
1096 $error++;
1097 } else {
1098 $update_done = true;
1099 }
1100 unset($_POST[$qty]);
1101 }
1102 } else {
1103 // Product no predefined
1104 $qty = "qtyl" . $line_id;
1105 $line->id = $line_id;
1106 $line->qty = GETPOSTFLOAT($qty);
1107 $line->entrepot_id = 0;
1108 if ($line->update($user) < 0) {
1109 setEventMessages($line->error, $line->errors, 'errors');
1110 $error++;
1111 } else {
1112 $update_done = true;
1113 }
1114 unset($_POST[$qty]);
1115 }
1116 }
1117
1118 if (empty($update_done)) {
1119 $line->id = $lines[$i]->id;
1120 $line->insertExtraFields();
1121 }
1122 }
1123 }
1124
1125 unset($_POST["lineid"]);
1126
1127 if (!$error) {
1128 if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
1129 // Define output language
1130 $outputlangs = $langs;
1131 $newlang = '';
1132 if (getDolGlobalInt('MAIN_MULTILANGS') /* && empty($newlang) */ && GETPOST('lang_id', 'aZ09')) {
1133 $newlang = GETPOST('lang_id', 'aZ09');
1134 }
1135 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
1136 $newlang = $object->thirdparty->default_lang;
1137 }
1138 if (!empty($newlang)) {
1139 $outputlangs = new Translate("", $conf);
1140 $outputlangs->setDefaultLang($newlang);
1141 }
1142
1143 $ret = $object->fetch($object->id); // Reload to get new records
1144 $object->generateDocument($object->model_pdf, $outputlangs, $hidedetails, $hidedesc, $hideref);
1145 }
1146 } else {
1147 header('Location: ' . $_SERVER['PHP_SELF'] . '?id=' . $object->id); // To redisplay the form being edited
1148 exit();
1149 }
1150 }
1151 } elseif ($action == 'updateline' && $permissiontoadd && GETPOST('cancel', 'alpha') == $langs->trans("Cancel")) {
1152 header('Location: ' . $_SERVER['PHP_SELF'] . '?id=' . $object->id); // To redisplay the form being edited
1153 exit();
1154 } elseif ($action == 'addline' && !$origin && getDolGlobalString('SHIPMENT_STANDALONE') && $usercancreate) { // Add a new line
1155 $langs->load('errors');
1156 $error = 0;
1157 $line_desc = (GETPOSTISSET('dp_desc') ? GETPOST('dp_desc', 'restricthtml') : '');
1158 $predef = '';
1159 $description = '';
1160 $fk_parent = 0;
1161 $fk_elementdet = '';
1162 $element_type = 'shipping';
1163 $fk_unit = '';
1164 $idprod = 0;
1165 $fk_product = 0;
1166 $fk_entrepot = '';
1167 $rang = '';
1168 $prod_entry_mode = GETPOST('prod_entry_mode', 'aZ09');
1169 if ($prod_entry_mode == 'free') {
1170 $idprod = 0;
1171 } else {
1172 $idprod = GETPOSTINT('idprod');
1173 if (getDolGlobalString('MAIN_DISABLE_FREE_LINES') && $idprod <= 0) {
1174 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("ProductOrService")), null, 'errors');
1175 $error++;
1176 }
1177 }
1178
1179 $qty = price2num(GETPOST('qty'.$predef, 'alpha'), 'MS', 2);
1180
1181 // Extrafields
1182 $extralabelsline = $extrafields->fetch_name_optionals_label($object->table_element_line);
1183 $array_options = $extrafields->getOptionalsFromPost($object->table_element_line, $predef);
1184 // Unset extrafield
1185 if (is_array($extralabelsline)) {
1186 // Get extra fields
1187 foreach ($extralabelsline as $key => $value) {
1188 unset($_POST["options_".$key]);
1189 }
1190 }
1191
1192 if ($prod_entry_mode == 'free' && (empty($idprod) || $idprod < 0) && GETPOST('type') < 0) {
1193 setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv('Type')), null, 'errors');
1194 $error++;
1195 }
1196
1197 if ($qty == '') {
1198 setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv('Qty')), null, 'errors');
1199 $error++;
1200 }
1201 if ($qty < 0) {
1202 setEventMessages($langs->trans('FieldCannotBeNegative', $langs->transnoentitiesnoconv('Qty')), null, 'errors');
1203 $error++;
1204 }
1205 if ($prod_entry_mode == 'free' && (empty($idprod) || $idprod < 0) && empty($line_desc)) {
1206 setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv('Description')), null, 'errors');
1207 $error++;
1208 }
1209
1210 if (!$error && isModEnabled('variants') && $prod_entry_mode != 'free') {
1211 if ($combinations = GETPOST('combinations', 'array')) {
1212 // Check if there is a product with the given combination
1213 $prodcomb = new ProductCombination($db);
1214
1215 if ($res = $prodcomb->fetchByProductCombination2ValuePairs($idprod, $combinations)) {
1216 $idprod = $res->fk_product_child;
1217 $fk_product = $idprod; // Update $fk_product with the fetched child product
1218 } else {
1219 setEventMessages($langs->trans('ErrorProductCombinationNotFound'), null, 'errors');
1220 $error++;
1221 }
1222 }
1223 }
1224
1225 if (!$error && ($qty >= 0) && (!empty($line_desc) || (!empty($idprod) && $idprod > 0))) {
1226 // Clean parameters
1227 if (!empty($idprod) && $idprod > 0) {
1228 $prod = new Product($db);
1229 $prod->fetch($idprod);
1230 $desc = $prod->label;
1231 $description = $desc;
1232 // Define output language
1233 if (getDolGlobalInt('MAIN_MULTILANGS') && getDolGlobalString('PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE')) {
1234 $outputlangs = $langs;
1235 $newlang = '';
1236 if (GETPOST('lang_id', 'aZ09')) {
1237 $newlang = GETPOST('lang_id', 'aZ09');
1238 }
1239 if (empty($newlang)) {
1240 $newlang = $object->thirdparty->default_lang;
1241 }
1242 if (!empty($newlang)) {
1243 $outputlangs = new Translate("", $conf);
1244 $outputlangs->setDefaultLang($newlang);
1245 }
1246
1247 $description = (!empty($prod->multilangs[$outputlangs->defaultlang]["description"])) ? $prod->multilangs[$outputlangs->defaultlang]["description"] : $prod->description;
1248 } else {
1249 $description = $prod->description;
1250 }
1251 if (getDolGlobalInt('PRODUIT_AUTOFILL_DESC') == 0) {
1252 $description = dol_concatdesc($desc, $line_desc, false, getDolGlobalString('MAIN_CHANGE_ORDER_CONCAT_DESCRIPTION') ? true : false);
1253 } else {
1254 $description = $line_desc;
1255 }
1256
1257 // Add custom code and origin country into description
1258 if (!getDolGlobalString('MAIN_PRODUCT_DISABLE_CUSTOMCOUNTRYCODE') && (!empty($prod->customcode) || !empty($prod->country_code))) {
1259 $tmptxt = '(';
1260 if (getDolGlobalInt('MAIN_MULTILANGS') && getDolGlobalString('PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE')) {
1261 $outputlangs = $langs;
1262 $newlang = '';
1263 if (GETPOST('lang_id', 'alpha')) {
1264 $newlang = GETPOST('lang_id', 'alpha');
1265 }
1266 if (empty($newlang)) {
1267 $newlang = $object->thirdparty->default_lang;
1268 }
1269 if (!empty($newlang)) {
1270 $outputlangs = new Translate("", $conf);
1271 $outputlangs->setDefaultLang($newlang);
1272 $outputlangs->load('products');
1273 }
1274 if (!empty($prod->customcode)) {
1275 $tmptxt .= $outputlangs->transnoentitiesnoconv("CustomsCode").': '.$prod->customcode;
1276 }
1277 if (!empty($prod->customcode) && !empty($prod->country_code)) {
1278 $tmptxt .= ' - ';
1279 }
1280 if (!empty($prod->country_code)) {
1281 $tmptxt .= $outputlangs->transnoentitiesnoconv("CountryOrigin").': '.getCountry($prod->country_code, '', $db, $outputlangs, 0);
1282 }
1283 } else {
1284 if (!empty($prod->customcode)) {
1285 $tmptxt .= $langs->transnoentitiesnoconv("CustomsCode").': '.$prod->customcode;
1286 }
1287 if (!empty($prod->customcode) && !empty($prod->country_code)) {
1288 $tmptxt .= ' - ';
1289 }
1290 if (!empty($prod->country_code)) {
1291 $tmptxt .= $langs->transnoentitiesnoconv("CountryOrigin").': '.getCountry($prod->country_code, '', $db, $langs, 0);
1292 }
1293 }
1294 $tmptxt .= ')';
1295 $description = dol_concatdesc($desc, $tmptxt);
1296 }
1297 $type = $prod->type;
1298 $fk_unit = $prod->fk_unit;
1299 } else {
1300 $label = (GETPOST('product_label') ? GETPOST('product_label') : '');
1301 $desc = $line_desc;
1302 $type = GETPOST('type');
1303 $fk_unit = GETPOST('units', 'alpha');
1304 $description = $desc;
1305 $fk_elementdet = '';
1306 }
1307 $desc = dol_htmlcleanlastbr($desc);
1308
1309 // Insert line
1310 $result = $object->addlinefree((float) $qty, $element_type, $idprod, $fk_unit, min($rank, count($object->lines) + 1), $description, $fk_parent, $array_options);
1311
1312 if ($result > 0) {
1313 $ret = $object->fetch($object->id); // Reload to get new records
1314 $object->fetch_thirdparty();
1315 if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
1316 // Define output language
1317 $outputlangs = $langs;
1318 $newlang = GETPOST('lang_id', 'alpha');
1319 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
1320 $newlang = $object->thirdparty->default_lang;
1321 }
1322 if (!empty($newlang)) {
1323 $outputlangs = new Translate("", $conf);
1324 $outputlangs->setDefaultLang($newlang);
1325 }
1326 $object->generateDocument($object->model_pdf, $outputlangs, $hidedetails, $hidedesc, $hideref);
1327 }
1328 } else {
1329 header('Location: '.$_SERVER['PHP_SELF'].'?id='.$object->id); // To redisplay the form being edited
1330 exit();
1331 }
1332 }
1333 } elseif ($action == 'confirm_sign' && $confirm == 'yes' && $permissiontoadd) {
1334 $result = $object->setSignedStatus($user, GETPOSTINT('signed_status'), 0, 'SHIPPING_MODIFY');
1335 if ($result >= 0) {
1336 if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
1337 // Define output language
1338 $outputlangs = $langs;
1339 $newlang = '';
1340 if (getDolGlobalInt('MAIN_MULTILANGS') /* && empty($newlang) */ && GETPOST('lang_id', 'aZ09')) {
1341 $newlang = GETPOST('lang_id', 'aZ09');
1342 }
1343 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
1344 $newlang = $object->thirdparty->default_lang;
1345 }
1346 if (!empty($newlang)) {
1347 $outputlangs = new Translate("", $conf);
1348 $outputlangs->setDefaultLang($newlang);
1349 }
1350 $object->generateDocument($object->model_pdf, $outputlangs, $hidedetails, $hidedesc, $hideref);
1351 }
1352
1353 header('Location: ' . $_SERVER["PHP_SELF"] . '?id=' . $object->id);
1354 exit;
1355 } else {
1356 $mesg = $object->error;
1357 }
1358 } elseif ($action == 'confirm_unsign' && $confirm == 'yes' && $permissiontoadd) {
1359 $result = $object->setSignedStatus($user, Expedition::$SIGNED_STATUSES['STATUS_NO_SIGNATURE'], 0, 'SHIPPING_MODIFY');
1360 if ($result >= 0) {
1361 if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
1362 // Define output language
1363 $outputlangs = $langs;
1364 $newlang = '';
1365 if (getDolGlobalInt('MAIN_MULTILANGS') /* && empty($newlang) */ && GETPOST('lang_id', 'aZ09')) {
1366 $newlang = GETPOST('lang_id', 'aZ09');
1367 }
1368 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
1369 $newlang = $object->thirdparty->default_lang;
1370 }
1371 if (!empty($newlang)) {
1372 $outputlangs = new Translate("", $conf);
1373 $outputlangs->setDefaultLang($newlang);
1374 }
1375 $object->generateDocument($object->model_pdf, $outputlangs, $hidedetails, $hidedesc, $hideref);
1376 }
1377
1378 header('Location: ' . $_SERVER["PHP_SELF"] . '?id=' . $object->id);
1379 exit;
1380 } else {
1381 $mesg = $object->error;
1382 }
1383 }
1384
1385 include DOL_DOCUMENT_ROOT . '/core/actions_printing.inc.php';
1386
1387 // Actions to send emails
1388 if (empty($id)) {
1389 $id = $facid;
1390 }
1391 $triggersendname = 'SHIPPING_SENTBYMAIL';
1392 $paramname = 'id';
1393 $autocopy = 'MAIN_MAIL_AUTOCOPY_SHIPMENT_TO';
1394 $mode = 'emailfromshipment';
1395 $trackid = 'shi' . $object->id;
1396 include DOL_DOCUMENT_ROOT . '/core/actions_sendmails.inc.php';
1397}
1398
1399/*
1400 * View
1401 */
1402
1403$title = $object->ref . ' - ' . $langs->trans("Card");
1404if ($action == 'create') {
1405 $title = $langs->trans("NewSending");
1406}
1407
1408$help_url = 'EN:Module_Shipments|FR:Module_Expéditions|ES:M&oacute;dulo_Expediciones|DE:Modul_Lieferungen';
1409
1410llxHeader('', $title, $help_url, '', 0, 0, '', '', '', 'mod-expedition page-card');
1411
1412if (empty($action)) {
1413 $action = 'view';
1414}
1415
1416$form = new Form($db);
1417$formfile = new FormFile($db);
1418$formproduct = new FormProduct($db);
1419if (isModEnabled('project')) {
1420 $formproject = new FormProjets($db);
1421} else {
1422 $formproject = null;
1423}
1424
1425$product_static = new Product($db);
1426$shipment_static = new Expedition($db);
1427$warehousestatic = new Entrepot($db);
1428
1429if (!$origin && $action == 'create' && !getDolGlobalString('SHIPMENT_STANDALONE')) {
1430 print load_fiche_titre($langs->trans("CreateShipment"), '', 'dolly');
1431
1432 print '<br>' .$langs->trans("ShipmentCreationIsDoneFromOrder");
1433 $action = '';
1434 $id = '';
1435 $ref = '';
1436}
1437
1438// Mode creation.
1439if ($action == 'create' && $usercancreate) {
1440 $expe = new Expedition($db);
1441
1442 print load_fiche_titre($langs->trans("NewSending"), '', 'dolly');
1443
1444 if (!$origin && getDolGlobalString('SHIPMENT_STANDALONE')) {
1445 $soc = new Societe($db);
1446 if ($socid > 0) {
1447 $res = $soc->fetch($socid);
1448 }
1449
1450 $shipping_method_id = $soc->shipping_method_id;
1451 $note_private = $object->getDefaultCreateValueFor('note_private');
1452 $note_public = $object->getDefaultCreateValueFor('note_public');
1453
1454 print '<form name="crea_expedition" action="' . $_SERVER["PHP_SELF"] . '" method="POST">';
1455 print '<input type="hidden" name="token" value="' . newToken() . '">';
1456 print '<input type="hidden" name="action" value="add">';
1457 print '<input type="hidden" name="changecompany" value="0">'; // will be set to 1 by javascript so we know post is done after a company change
1458 print '<input type="hidden" name="originid" value="' . $id . '">';
1459 print '<input type="hidden" name="backtopage" value="' . $backtopage . '">';
1460
1461 print dol_get_fiche_head([]);
1462
1463 print '<table class="border centpercent">';
1464
1465 // Thirdparty
1466 print '<tr>';
1467 print '<td class="fieldrequired">' . $langs->trans('ThirdParty') . '</td>';
1468 if ($socid > 0) {
1469 print '<td>';
1470 print $soc->getNomUrl(1);
1471 print '<input type="hidden" name="socid" value="' . $soc->id . '">';
1472 print '</td>';
1473 } else {
1474 print '<td class="valuefieldcreate">';
1475 print img_picto('', 'company', 'class="pictofixedwidth"').$form->select_company('', 'socid', '', 'SelectThirdParty', 1, 0, array(), 0, 'minwidth175 maxwidth500 widthcentpercentminusxx');
1476 // reload page to retrieve customer information
1477 if (!getDolGlobalString('RELOAD_PAGE_ON_CUSTOMER_CHANGE_DISABLED')) {
1478 print '<script>
1479 $(document).ready(function() {
1480 $("#socid").change(function() {
1481 console.log("We have changed the company - Reload page");
1482 var socid = $(this).val();
1483 // reload page
1484 $("input[name=action]").val("create");
1485 $("input[name=changecompany]").val("1");
1486 $("form[name=crea_expedition]").submit();
1487 });
1488 });
1489 </script>';
1490 }
1491 print ' <a href="'.DOL_URL_ROOT.'/societe/card.php?action=create&client=3&fournisseur=0&backtopage='.urlencode($_SERVER["PHP_SELF"].'?action=create').'"><span class="fa fa-plus-circle valignmiddle paddingleft" title="'.$langs->trans("AddThirdParty").'"></span></a>';
1492 print '</td>';
1493 }
1494 print '</tr>'."\n";
1495
1496 // Project
1497 if (isModEnabled('project') && is_object($formproject)) {
1498 $projectid = GETPOSTINT('projectid');
1499 if (empty($projectid) && !empty($object->fk_project)) {
1500 $projectid = (int) $object->fk_project;
1501 }
1502
1503 $langs->load("projects");
1504 print '<tr>';
1505 print '<td>' . $langs->trans("Project") . '</td><td colspan="2">';
1506 print img_picto('', 'project', 'class="pictofixedwidth"');
1507 print $formproject->select_projects($soc->id, $projectid, 'projectid', 0, 0, 1, 0, 0, 0, 0, '', 1, 0, 'widthcentpercentminusxx');
1508 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>';
1509 print '</td>';
1510 print '</tr>';
1511 }
1512
1513 // Date sending
1514 print '<tr><td>'.$langs->trans("DateShipping").'</td>';
1515 print '<td colspan="3">';
1516 print img_picto('', 'action', 'class="pictofixedwidth"');
1517 $date_shipping = ($date_shipping ? $date_shipping : $object->date_shipping); // $date_shipping comes from GETPOST
1518 print $form->selectDate($date_shipping ? $date_shipping : -1, 'date_shipping', 1, 1, 1);
1519 print "</td>\n";
1520 print '</tr>';
1521
1522 // Date delivery planned
1523 print '<tr><td>'.$langs->trans("DateDeliveryPlanned").'</td>';
1524 print '<td colspan="3">';
1525 print img_picto('', 'action', 'class="pictofixedwidth"');
1526 $date_delivery = ($date_delivery ? $date_delivery : $object->delivery_date); // $date_delivery comes from GETPOST
1527 print $form->selectDate($date_delivery ? $date_delivery : -1, 'date_delivery', 1, 1, 1);
1528 print "</td>\n";
1529 print '</tr>';
1530
1531 // Weight
1532 print '<tr><td>';
1533 print $langs->trans("Weight");
1534 print '</td><td colspan="3">';
1535 print img_picto('', 'fa-balance-scale', 'class="pictofixedwidth"');
1536 print '<input name="weight" size="4" value="' . GETPOST('weight') . '"> '; // Do not use GETPOSTINT here, we must accept '' also.
1537 $text = $formproduct->selectMeasuringUnits("weight_units", "weight", GETPOST('weight_units'), 0, 2);
1538 $htmltext = $langs->trans("KeepEmptyForAutoCalculation");
1539 print $form->textwithpicto($text, $htmltext);
1540 print '</td></tr>';
1541
1542 // Dim width x height x depth
1543 print '<tr><td>';
1544 print $langs->trans("Width") . ' x ' . $langs->trans("Height") . ' x ' . $langs->trans("Depth");
1545 print ' </td><td colspan="3">';
1546 print img_picto('', 'fa-ruler', 'class="pictofixedwidth"');
1547 print '<input name="sizeW" size="4" value="' . GETPOST('sizeW') . '">';
1548 print ' x <input name="sizeH" size="4" value="' . GETPOST('sizeH') . '">';
1549 print ' x <input name="sizeS" size="4" value="' . GETPOST('sizeS') . '">';
1550 print ' ';
1551 $text = $formproduct->selectMeasuringUnits("size_units", "size", GETPOST('size_units'), 0, 2);
1552 $htmltext = $langs->trans("KeepEmptyForAutoCalculation");
1553 print $form->textwithpicto($text, $htmltext);
1554 print '</td></tr>';
1555
1556 // Delivery method
1557 print "<tr><td>".$langs->trans("DeliveryMethod")."</td>";
1558 print '<td colspan="3">';
1559 $expe->fetch_delivery_methods();
1560 print img_picto('', 'dolly', 'class="pictofixedwidth"');
1561 print $form->selectarray("shipping_method_id", $expe->meths, GETPOSTINT('shipping_method_id'), 1, 0, 0, "", 1, 0, 0, '', 'widthcentpercentminusxx');
1562 if ($user->admin) {
1563 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
1564 }
1565 print "</td></tr>\n";
1566
1567 // Tracking number
1568 print "<tr><td>".$langs->trans("TrackingNumber")."</td>";
1569 print '<td colspan="3">';
1570 print img_picto('', 'barcode', 'class="pictofixedwidth"');
1571 print '<input name="tracking_number" size="20" value="'.GETPOST('tracking_number', 'alpha').'">';
1572 print "</td></tr>\n";
1573
1574 // Other attributes
1575 $parameters = array('objectsrc' => isset($objectsrc) ? $objectsrc : '', 'colspan' => ' colspan="3"', 'cols' => '3', 'socid' => $socid);
1576 $reshook = $hookmanager->executeHooks('formObjectOptions', $parameters, $expe, $action); // Note that $action and $object may have been modified by hook
1577 print $hookmanager->resPrint;
1578
1579 if (empty($reshook)) {
1580 // copy from order
1581 if ($object->fetch_optionals() > 0) {
1582 $expe->array_options = array_merge($expe->array_options, $object->array_options);
1583 }
1584 print $expe->showOptionals($extrafields, 'edit', $parameters);
1585 }
1586
1587 // Incoterms
1588 if (isModEnabled('incoterm')) {
1589 print '<tr>';
1590 print '<td><label for="incoterm_id">'.$form->textwithpicto($langs->trans("IncotermLabel"), $object->label_incoterms, 1).'</label></td>';
1591 print '<td colspan="3" class="maxwidthonsmartphone">';
1592 print img_picto('', 'incoterm', 'class="pictofixedwidth"');
1593 print $form->select_incoterms((!empty($object->fk_incoterms) ? $object->fk_incoterms : ''), (!empty($object->location_incoterms) ? $object->location_incoterms : ''));
1594 print '</td></tr>';
1595 }
1596
1597 // Document model
1598 include_once DOL_DOCUMENT_ROOT.'/core/modules/expedition/modules_expedition.php';
1600 if (is_array($list) && count($list) > 1) {
1601 print "<tr><td>".$langs->trans("DefaultModel")."</td>";
1602 print '<td colspan="3">';
1603 print img_picto('', 'pdf', 'class="pictofixedwidth"');
1604 print $form->selectarray('model', $list, getDolGlobalString('EXPEDITION_ADDON_PDF'), 0, 0, 0, '', 0, 0, 0, '', 'widthcentpercentminusx');
1605 print "</td></tr>\n";
1606 }
1607
1608 // Note Public
1609 $htmltext ='';
1610 print '<tr>';
1611 print '<td class="tdtop">';
1612 print $form->textwithpicto($langs->trans('NotePublic'), $htmltext);
1613 print '</td>';
1614 print '<td valign="top" colspan="2">';
1615 $doleditor = new DolEditor('note_public', (string) $note_public, '', 80, 'dolibarr_notes', 'In', false, false, !getDolGlobalString('FCKEDITOR_ENABLE_NOTE_PUBLIC') ? 0 : 1, ROWS_3, '90%');
1616 print $doleditor->Create(1);
1617
1618 // Note Private
1619 if (!$user->socid) {
1620 print '<tr>';
1621 print '<td class="tdtop">';
1622 print $form->textwithpicto($langs->trans('NotePrivate'), $htmltext);
1623 print '</td>';
1624 print '<td valign="top" colspan="2">';
1625 $doleditor = new DolEditor('note_private', (string) $note_private, '', 80, 'dolibarr_notes', 'In', false, false, !getDolGlobalString('FCKEDITOR_ENABLE_NOTE_PRIVATE') ? 0 : 1, ROWS_3, '90%');
1626 print $doleditor->Create(1);
1627 print "</td></tr>";
1628 }
1629
1630 print "</table>\n";
1631
1632 print dol_get_fiche_end();
1633
1634 print $form->buttonsSaveCancel("CreateDraft");
1635
1636 print "</form>\n";
1637 } elseif ($origin) {
1638 $classname = ucfirst($origin);
1639
1640 $object = new $classname($db);
1641 /* @var Commande|Facture $object */
1642 '@phan-var-force Commande|Facture $object';
1643
1644
1645 if ($object->fetch($origin_id)) { // This include the fetch_lines
1646 $soc = new Societe($db);
1647 $soc->fetch($object->socid);
1648
1649 $author = new User($db);
1650 $author->fetch($object->user_author_id);
1651
1652 if (isModEnabled('stock')) {
1653 $entrepot = new Entrepot($db);
1654 }
1655
1656 print '<form action="' . $_SERVER["PHP_SELF"] . '" method="post">';
1657 print '<input type="hidden" name="token" value="' . newToken() . '">';
1658 print '<input type="hidden" name="action" value="add">';
1659 print '<input type="hidden" name="origin" value="' . $origin . '">';
1660 print '<input type="hidden" name="origin_id" value="' . $object->id . '">';
1661 if (GETPOSTINT('entrepot_id')) {
1662 print '<input type="hidden" name="entrepot_id" value="' . GETPOSTINT('entrepot_id') . '">';
1663 }
1664
1665 print dol_get_fiche_head([]);
1666
1667 print '<table class="border centpercent">';
1668
1669 // Ref
1670 print '<tr><td class="titlefieldcreate fieldrequired">';
1671 if ($origin == 'commande' && isModEnabled('order')) {
1672 print $langs->trans("RefOrder");
1673 }
1674 if ($origin == 'propal' && isModEnabled("propal")) {
1675 print $langs->trans("RefProposal");
1676 }
1677 print '</td><td colspan="3">';
1678 print $object->getNomUrl(1);
1679 print '</td>';
1680 print "</tr>\n";
1681
1682 // Ref client
1683 print '<tr><td>';
1684 if ($origin == 'commande') {
1685 print $langs->trans('RefCustomerOrder');
1686 } elseif ($origin == 'propal') {
1687 print $langs->trans('RefCustomerOrder');
1688 } else {
1689 print $langs->trans('RefCustomer');
1690 }
1691 print '</td><td colspan="3">';
1692 print '<input type="text" name="ref_customer" value="' . $object->ref_client . '" />';
1693 print '</td>';
1694 print '</tr>';
1695
1696 // Thirdparty
1697 print '<tr><td class="titlefieldcreate fieldrequired">' . $langs->trans('Company') . '</td>';
1698 print '<td colspan="3">' . $soc->getNomUrl(1) . '</td>';
1699 print '<input type="hidden" name="socid" value="' . $soc->id . '">';
1700 print '</tr>';
1701
1702 // Project
1703 if (isModEnabled('project') && is_object($formproject)) {
1704 $projectid = GETPOSTINT('projectid');
1705 if (empty($projectid) && !empty($object->fk_project)) {
1706 $projectid = (int) $object->fk_project;
1707 }
1708 if ($origin == 'project') {
1709 $projectid = ($object->id ? $object->id : 0);
1710 }
1711 $langs->load("projects");
1712 print '<tr>';
1713 print '<td>' . $langs->trans("Project") . '</td><td colspan="2">';
1714 print img_picto('', 'project', 'class="pictofixedwidth"');
1715 print $formproject->select_projects($soc->id, $projectid, 'projectid', 0, 0, 1, 0, 0, 0, 0, '', 1, 0, 'widthcentpercentminusxx');
1716 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>';
1717 print '</td>';
1718 print '</tr>';
1719 }
1720
1721 // Date delivery planned
1722 print '<tr><td>' . $langs->trans("DateDeliveryPlanned") . '</td>';
1723 print '<td colspan="3">';
1724 print img_picto('', 'action', 'class="pictofixedwidth"');
1725 $date_delivery = ($date_delivery ? $date_delivery : $object->delivery_date); // $date_delivery comes from GETPOST
1726 print $form->selectDate($date_delivery ? $date_delivery : -1, 'date_delivery', 1, 1, 1);
1727 print "</td>\n";
1728 print '</tr>';
1729
1730 // Date shipment (sending)
1731 print '<tr><td>' . $langs->trans("DateShipping") . '</td>';
1732 print '<td colspan="3">';
1733 print img_picto('', 'action', 'class="pictofixedwidth"');
1734 //$date_shipping = ($date_shipping ? $date_shipping : $object->date_shipping); // $date_shipping comes from GETPOST
1735 print $form->selectDate($date_shipping ? $date_shipping : -1, 'date_shipping', 1, 1, 1);
1736 print "</td>\n";
1737 print '</tr>';
1738
1739 // Note Public
1740 print '<tr><td>' . $langs->trans("NotePublic") . '</td>';
1741 print '<td colspan="3">';
1742 $doleditor = new DolEditor('note_public', $object->note_public, '', 60, 'dolibarr_notes', 'In', false, false, !getDolGlobalString('FCKEDITOR_ENABLE_NOTE_PUBLIC') ? 0 : 1, ROWS_3, '90%');
1743 print $doleditor->Create(1);
1744 print "</td></tr>";
1745
1746 // Note Private
1747 if ($object->note_private && !$user->socid) {
1748 print '<tr><td>' . $langs->trans("NotePrivate") . '</td>';
1749 print '<td colspan="3">';
1750 $doleditor = new DolEditor('note_private', $object->note_private, '', 60, 'dolibarr_notes', 'In', false, false, !getDolGlobalString('FCKEDITOR_ENABLE_NOTE_PRIVATE') ? 0 : 1, ROWS_3, '90%');
1751 print $doleditor->Create(1);
1752 print "</td></tr>";
1753 }
1754
1755 // Weight
1756 print '<tr><td>';
1757 print $langs->trans("Weight");
1758 print '</td><td colspan="3">';
1759 print img_picto('', 'fa-balance-scale', 'class="pictofixedwidth"');
1760
1761 print '<input name="weight" size="4" value="' . dol_escape_htmltag(GETPOST('weight')) . '"> '; // Do not use GETPOSTINT here, we must accept '' also.
1762 $text = $formproduct->selectMeasuringUnits("weight_units", "weight", (string) GETPOST('weight_units'), 0, 2);
1763 $htmltext = $langs->trans("KeepEmptyForAutoCalculation");
1764 print $form->textwithpicto($text, $htmltext);
1765 print '</td></tr>';
1766
1767 // Dim Width x Height x Depth
1768 print '<tr><td>';
1769 print $langs->trans("Width") . ' x ' . $langs->trans("Height") . ' x ' . $langs->trans("Depth");
1770 print ' </td><td colspan="3">';
1771 print img_picto('', 'fa-ruler', 'class="pictofixedwidth"');
1772 print '<input name="sizeW" size="4" value="' . GETPOST('sizeW') . '">';
1773 print ' x <input name="sizeH" size="4" value="' . GETPOST('sizeH') . '">';
1774 print ' x <input name="sizeS" size="4" value="' . GETPOST('sizeS') . '">';
1775 print ' ';
1776 $text = $formproduct->selectMeasuringUnits("size_units", "size", GETPOST('size_units'), 0, 2);
1777 $htmltext = $langs->trans("KeepEmptyForAutoCalculation");
1778 print $form->textwithpicto($text, $htmltext);
1779 print '</td></tr>';
1780
1781 // Delivery method
1782 print "<tr><td>" . $langs->trans("DeliveryMethod") . "</td>";
1783 print '<td colspan="3">';
1784 $expe->fetch_delivery_methods();
1785 print img_picto('', 'dolly', 'class="pictofixedwidth"');
1786 print $form->selectarray("shipping_method_id", $expe->meths, GETPOSTINT('shipping_method_id'), 1, 0, 0, "", 1, 0, 0, '', 'widthcentpercentminusxx');
1787 if ($user->admin) {
1788 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
1789 }
1790 print "</td></tr>\n";
1791
1792 // Tracking number
1793 print "<tr><td>" . $langs->trans("TrackingNumber") . "</td>";
1794 print '<td colspan="3">';
1795 print img_picto('', 'barcode', 'class="pictofixedwidth"');
1796 print '<input name="tracking_number" size="20" value="' . GETPOST('tracking_number', 'alpha') . '">';
1797 print "</td></tr>\n";
1798
1799 // Incoterms
1800 if (isModEnabled('incoterm')) {
1801 print '<tr>';
1802 print '<td><label for="incoterm_id">' . $form->textwithpicto($langs->trans("IncotermLabel"), $object->label_incoterms, 1) . '</label></td>';
1803 print '<td colspan="3" class="maxwidthonsmartphone">';
1804 print img_picto('', 'incoterm', 'class="pictofixedwidth"');
1805 print $form->select_incoterms((!empty($object->fk_incoterms) ? $object->fk_incoterms : ''), (!empty($object->location_incoterms) ? $object->location_incoterms : ''));
1806 print '</td></tr>';
1807 }
1808
1809 // Document model
1810 include_once DOL_DOCUMENT_ROOT . '/core/modules/expedition/modules_expedition.php';
1812 if (is_array($list) && count($list) > 1) {
1813 print "<tr><td>" . $langs->trans("DefaultModel") . "</td>";
1814 print '<td colspan="3">';
1815 print img_picto('', 'pdf', 'class="pictofixedwidth"');
1816 print $form->selectarray('model', $list, getDolGlobalString('EXPEDITION_ADDON_PDF'), 0, 0, 0, '', 0, 0, 0, '', 'widthcentpercentminusx');
1817 print "</td></tr>\n";
1818 }
1819
1820 // Other attributes. Fields from hook formObjectOptions and Extrafields.
1821 // $objectsrc is Commande|Facture
1822 $objectsav = $object; // Because Expedition is $expe and not $object that is wrongly a duplicate of $objectsrc.
1823 $object = $expe;
1824 // Propagate extrafieldsvalue from source object to shipment object
1825 if (isset($extrafields->attributes[$object->table_element]['label']) && is_array($extrafields->attributes[$object->table_element]['label']) && !empty($extrafields->attributes[$object->table_element]['label'])) {
1826 foreach ($extrafields->attributes[$object->table_element]['label'] as $key => $val) {
1827 if (array_key_exists('options_'.$key, $objectsav->array_options)) { // We take value from order only if extrafield has the same name/key.
1828 $object->array_options['options_'.$key] = $objectsav->array_options['options_'.$key];
1829 }
1830 }
1831 }
1832 $parameters = array(
1833 'objectsrc' => isset($objectsrc) ? $objectsrc : '',
1834 'cols' => '3',
1835 'socid' => $socid
1836 );
1837 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_add.tpl.php';
1838 $object = $objectsav;
1839
1840 print "</table>";
1841
1842 print dol_get_fiche_end();
1843
1844
1845 // Shipment lines
1846
1847 $numAsked = count($object->lines);
1848
1849 print '<script type="text/javascript">' . "\n";
1850 print 'jQuery(document).ready(function() {' . "\n";
1851 print 'jQuery("#autofill").click(function() {';
1852 $i = 0;
1853 while ($i < $numAsked) {
1854 print 'jQuery("#qtyl' . $i . '").val(jQuery("#qtyasked' . $i . '").val() - jQuery("#qtydelivered' . $i . '").val());' . "\n";
1855 if (isModEnabled('productbatch')) {
1856 print 'jQuery("#qtyl' . $i . '_' . $i . '").val(jQuery("#qtyasked' . $i . '").val() - jQuery("#qtydelivered' . $i . '").val());' . "\n";
1857 }
1858 $i++;
1859 }
1860 print 'return false; });' . "\n";
1861 print 'jQuery("#autoreset").click(function() { console.log("Reset values to 0"); jQuery(".qtyl").val(0);' . "\n";
1862 print 'return false; });' . "\n";
1863 print '});' . "\n";
1864 print '</script>' . "\n";
1865
1866 print '<br>';
1867
1868 print '<div class="div-table-responsive-no-min">';
1869 print '<table class="noborder centpercent">';
1870
1871 // Load shipments already done for same order
1872 $object->loadExpeditions();
1873
1874 $alreadyQtyBatchSetted = $alreadyQtySetted = array();
1875
1876 $title_lines_to_disable = array();
1877
1878 if ($numAsked) {
1879 if (isModEnabled('subtotals')) {
1880 if (!(getDolGlobalString('SHIPMENT_SUPPORTS_SERVICES') || getDolGlobalString('STOCK_SUPPORTS_SERVICES'))) {
1881 $title_lines_to_disable = $object->getDisabledShippmentSubtotalLines();
1882 }
1883 foreach ($object->lines as $line) {
1884 if ($line->special_code == SUBTOTALS_SPECIAL_CODE) {
1885 $show_check_add_buttons = true;
1886 break;
1887 }
1888 }
1889 }
1890 print '<tr class="liste_titre">';
1891 print '<td>';
1892 if (isset($show_check_add_buttons)) {
1893 print $form->showCheckAddButtons('checkforselect');
1894 }
1895 print $langs->trans("Description");
1896 print '</td>';
1897 print '<td class="center">' . $langs->trans("QtyOrdered") . '</td>';
1898 print '<td class="center">' . $langs->trans("QtyShipped") . '</td>';
1899 print '<td class="center">' . $langs->trans("QtyToShip");
1900 if (!isModEnabled('productbatch')) {
1901 print '<br><a href="#" id="autofill" class="opacitymedium link cursor cursorpointer">' . img_picto($langs->trans("Autofill"), 'autofill', 'class="paddingrightonly"') . '</a>';
1902 print ' / ';
1903 } else {
1904 print '<br>';
1905 }
1906 print '<span id="autoreset" class="opacitymedium link cursor cursorpointer">' . img_picto($langs->trans("Reset"), 'eraser') . '</span>';
1907 print '</td>';
1908 if (isModEnabled('stock')) {
1909 if (!isModEnabled('productbatch')) {
1910 print '<td class="left">' . $langs->trans("Warehouse") . ' (' . $langs->trans("Stock") . ')</td>';
1911 } else {
1912 print '<td class="left">' . $langs->trans("Warehouse") . ' / ' . $langs->trans("Batch") . ' (' . $langs->trans("Stock") . ')</td>';
1913 }
1914 }
1915 if (getDolGlobalString('SHIPPING_DISPLAY_STOCK_ENTRY_DATE')) {
1916 print '<td class="left">' . $langs->trans('StockEntryDate') . '</td>';
1917 }
1918 print "</tr>\n";
1919 }
1920
1921 $warehouse_id = GETPOSTINT('entrepot_id');
1922 $warehousePicking = array();
1923 // get all warehouse children for picking
1924 if ($warehouse_id > 0) {
1925 $warehousePicking[] = $warehouse_id;
1926 $warehouseObj = new Entrepot($db);
1927 $warehouseObj->get_children_warehouses($warehouse_id, $warehousePicking);
1928 }
1929
1930 $indiceAsked = 0;
1931 while ($indiceAsked < $numAsked) {
1932 $product = new Product($db);
1933
1934 $line = $object->lines[$indiceAsked];
1935
1936 $parameters = array('i' => $indiceAsked, 'line' => $line, 'num' => $numAsked);
1937 $reshook = $hookmanager->executeHooks('printObjectLine', $parameters, $object, $action);
1938 if ($reshook < 0) {
1939 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
1940 }
1941
1942 if (empty($reshook) && $line->special_code != SUBTOTALS_SPECIAL_CODE) {
1943 // Show product and description
1944 $type = $line->product_type ? $line->product_type : $line->fk_product_type;
1945 // Try to enhance type detection using date_start and date_end for free lines where type was not saved.
1946 if (!empty($line->date_start)) {
1947 $type = 1;
1948 }
1949 if (!empty($line->date_end)) {
1950 $type = 1;
1951 }
1952
1953 print '<!-- line for order line ' . $line->id . ' -->' . "\n";
1954 print '<tr class="oddeven" id="row-' . $line->id . '">' . "\n";
1955
1956 $qtyProdCom = $line->qty;
1957 $productChildrenNb = 0;
1958 // Product label
1959 if ($line->fk_product > 0) { // If predefined product
1960 $res = $product->fetch($line->fk_product);
1961 if ($res < 0) {
1962 dol_print_error($db, $product->error, $product->errors);
1963 }
1964 if (getDolGlobalInt('PRODUIT_SOUSPRODUITS')) {
1965 $productChildrenNb = $product->hasFatherOrChild(1);
1966 }
1967 if ($productChildrenNb > 0) {
1968 $product->loadStockForVirtualProduct('warehouseopen', $qtyProdCom);
1969 } else {
1970 $product->load_stock('warehouseopen'); // Load all $product->stock_warehouse[idwarehouse]->detail_batch
1971 }
1972 //var_dump($product->stock_warehouse[1]);
1973
1974 print '<td>';
1975 print '<a name="' . $line->id . '"></a>'; // ancre pour retourner sur la ligne
1976
1977 // Show product and description
1978 $product_static->type = $line->fk_product_type;
1979 $product_static->id = $line->fk_product;
1980 $product_static->ref = $line->ref;
1981 $product_static->status = $line->product_tosell;
1982 $product_static->status_buy = $line->product_tobuy;
1983 $product_static->status_batch = $line->product_tobatch;
1984
1985 $showdescinproductdesc = getDolGlobalString('PRODUIT_DESC_IN_FORM_ACCORDING_TO_DEVICE');
1986
1987 $text = $product_static->getNomUrl(1);
1988 $text .= ' - ' . (!empty($line->label) ? $line->label : $line->product_label);
1989 $description = ($showdescinproductdesc ? '' : dol_htmlentitiesbr($line->desc));
1990 $description .= empty($product->stockable_product) ? $langs->trans('StockDisabled') : $langs->trans('StockEnabled');
1991 print $form->textwithtooltip($text, $description, 3, 0, '', (string) $i);
1992
1993 // Show range
1994 print_date_range($db->jdate($line->date_start), $db->jdate($line->date_end));
1995
1996 // Add description in form
1997 if ($showdescinproductdesc) {
1998 print ($line->desc && $line->desc != $line->product_label) ? '<br>' . dol_htmlentitiesbr($line->desc) : '';
1999 }
2000
2001 print '</td>';
2002 } else {
2003 print "<td>";
2004 if ($type == 1) {
2005 $text = img_object($langs->trans('Service'), 'service');
2006 } else {
2007 $text = img_object($langs->trans('Product'), 'product');
2008 }
2009
2010 if (!empty($line->label)) {
2011 $text .= ' <strong>' . $line->label . '</strong>';
2012 print $form->textwithtooltip($text, $line->desc, 3, 0, '', (string) $i);
2013 } else {
2014 print $text . ' ' . nl2br($line->desc);
2015 }
2016
2017 // Show range
2018 print_date_range($db->jdate($line->date_start), $db->jdate($line->date_end));
2019 print "</td>\n";
2020 }
2021
2022 // unit of order
2023 $unit_order = '';
2024 if (getDolGlobalString('PRODUCT_USE_UNITS')) {
2025 $unit_order = measuringUnitString($line->fk_unit);
2026 }
2027
2028 // Qty
2029 print '<td class="center">' . $line->qty;
2030 print '<input name="qtyasked' . $indiceAsked . '" id="qtyasked' . $indiceAsked . '" type="hidden" value="' . $line->qty . '">';
2031 if ($line->qty) {
2032 print ' ' . $unit_order . '</td>';
2033 }
2034
2035 // Qty already shipped
2036 print '<td class="center">';
2037 $quantityDelivered = isset($object->expeditions[$line->id]) ? $object->expeditions[$line->id] : '';
2038 print $quantityDelivered;
2039 print '<input name="qtydelivered' . $indiceAsked . '" id="qtydelivered' . $indiceAsked . '" type="hidden" value="' . $quantityDelivered . '">';
2040 if ($quantityDelivered) {
2041 print ' ' . $unit_order . '</td>';
2042 }
2043
2044 // Qty to ship
2045 $quantityAsked = $line->qty;
2046 if ($line->product_type == Product::TYPE_SERVICE && !getDolGlobalString('STOCK_SUPPORTS_SERVICES') && !getDolGlobalString('SHIPMENT_SUPPORTS_SERVICES')) {
2047 $quantityToBeDelivered = 0;
2048 } else {
2049 if (is_numeric($quantityDelivered)) {
2050 $quantityToBeDelivered = $quantityAsked - $quantityDelivered;
2051 } else {
2052 $quantityToBeDelivered = $quantityAsked;
2053 }
2054 }
2055
2056 $warehouseObject = null;
2057 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
2058 print '<!-- Case warehouse already known or product not a predefined product -->';
2059 //ship from preselected location
2060 $stock = + (isset($product->stock_warehouse[$warehouse_id]->real) ? $product->stock_warehouse[$warehouse_id]->real : 0); // Convert to number
2061 if (($line->product_type == Product::TYPE_SERVICE && getDolGlobalString('SHIPMENT_SUPPORTS_SERVICES')) || $product->stockable_product == Product::DISABLED_STOCK) {
2062 $deliverableQty = $quantityToBeDelivered;
2063 } else {
2064 $deliverableQty = min($quantityToBeDelivered, $stock);
2065 }
2066 if ($deliverableQty < 0) {
2067 $deliverableQty = 0;
2068 }
2069 if (!isModEnabled('productbatch') || !$product->hasbatch()) {
2070 // Quantity to send
2071 print '<td class="center">';
2072 if ($line->product_type == Product::TYPE_PRODUCT || getDolGlobalString('STOCK_SUPPORTS_SERVICES') || ($line->product_type == Product::TYPE_SERVICE && getDolGlobalString('SHIPMENT_SUPPORTS_SERVICES'))) {
2073 if (GETPOSTISSET('qtyl'.$indiceAsked) && GETPOST('qtyl'.$indiceAsked) !== '') {
2074 $deliverableQty = GETPOSTFLOAT('qtyl'.$indiceAsked, 'MS');
2075 }
2076 print '<input name="idl' . $indiceAsked . '" type="hidden" value="' . $line->id . '">';
2077 $qtylValue = $deliverableQty;
2078 if (getDolGlobalBool('SHIPMENT_DONT_PREFILL_QTY', false)) {
2079 $qtylValue = '';
2080 } elseif (is_numeric($qtylValue)) {
2081 // Render as locale number so GETPOSTFLOAT() on submit reads it back via price2num option=2 without confusing '.' for a thousand separator in es_ES.
2082 $qtylValue = price($qtylValue);
2083 }
2084 print '<input name="qtyl' . $indiceAsked . '" id="qtyl' . $indiceAsked . '" class="qtyl right" type="text" size="4" value="' . $qtylValue . '">';
2085 } else {
2086 if (getDolGlobalString('SHIPMENT_GETS_ALL_ORDER_PRODUCTS')) {
2087 print '<input name="idl' . $indiceAsked . '" type="hidden" value="' . $line->id . '">';
2088 print '<input name="qtyl' . $indiceAsked . '" id="qtyl' . $indiceAsked . '" type="hidden" value="0">';
2089 }
2090
2091 print $langs->trans("NA");
2092 }
2093 print '</td>';
2094
2095 // Stock
2096 if (isModEnabled('stock')) {
2097 print '<td class="left">';
2098 if ($line->product_type == Product::TYPE_PRODUCT || getDolGlobalString('STOCK_SUPPORTS_SERVICES')) { // Type of product need stock change ?
2099 // Show warehouse combo list
2100 $ent = "entl" . $indiceAsked;
2101 $idl = "idl" . $indiceAsked;
2102 $tmpentrepot_id = is_numeric(GETPOST($ent)) ? GETPOSTINT($ent) : $warehouse_id;
2103 if ($line->fk_product > 0) {
2104 print '<!-- Show warehouse selection -->';
2105
2106 $stockMin = false;
2107 if (getDolGlobalInt('STOCK_DISALLOW_NEGATIVE_TRANSFER')) {
2108 $stockMin = 0;
2109 }
2110 if ($productChildrenNb > 0) {
2111 print $formproduct->selectWarehouses($tmpentrepot_id, 'entl' . $indiceAsked, '', 1, 0, 0, '', 0, 0, array(), 'minwidth200', array(), 1, $stockMin, 'stock DESC, e.ref');
2112 } else {
2113 if ($product->stockable_product == Product::ENABLED_STOCK) {
2114 print $formproduct->selectWarehouses($tmpentrepot_id, 'entl' . $indiceAsked, '', 1, 0, $line->fk_product, '', 1, 0, array(), 'minwidth200', array(), 1, $stockMin, 'stock DESC, e.ref');
2115 } else {
2116 print img_warning() . ' ' . $langs->trans('StockDisabled');
2117 }
2118 }
2119
2120 if ($tmpentrepot_id > 0 && $tmpentrepot_id == $warehouse_id) {
2121 //print $stock.' '.$quantityToBeDelivered;
2122 if ($stock < $quantityToBeDelivered) {
2123 print ' ' . img_warning($langs->trans("StockTooLow")); // Stock too low for this $warehouse_id but you can change warehouse
2124 }
2125 }
2126 }
2127 } else {
2128 print '<span class="opacitymedium">(' . $langs->trans("Service") . ')</span><input name="entl' . $indiceAsked . '" id="entl' . $indiceAsked . '" type="hidden" value="0">';
2129 }
2130 print '</td>';
2131 }
2132 if (getDolGlobalString('SHIPPING_DISPLAY_STOCK_ENTRY_DATE')) {
2133 print '<td></td>';
2134 } //StockEntrydate
2135 print "</tr>\n";
2136
2137 // Show subproducts of product
2138 if (getDolGlobalString('PRODUIT_SOUSPRODUITS') && $line->fk_product > 0) {
2139 $product->get_sousproduits_arbo();
2140 $prods_arbo = $product->get_arbo_each_prod($qtyProdCom);
2141 if (count($prods_arbo) > 0) {
2142 foreach ($prods_arbo as $key => $value) {
2143 //print $value[0];
2144 $img = '';
2145 if ($value['stock'] < $value['stock_alert']) {
2146 $img = img_warning($langs->trans("StockTooLow"));
2147 }
2148 print "<tr class=\"oddeven\"><td>&nbsp; &nbsp; &nbsp; ->
2149 <a href=\"" . DOL_URL_ROOT . "/product/card.php?id=" . $value['id'] . "\">" . $value['fullpath'] . "
2150 </a> (" . $value['nb'] . ")</td><td class=\"center\"> " . $value['nb_total'] . "</td><td>&nbsp;</td><td>&nbsp;</td>
2151 <td class=\"center\">" . $value['stock'] . " " . $img . "</td>";
2152 if (getDolGlobalString('SHIPPING_DISPLAY_STOCK_ENTRY_DATE')) {
2153 print '<td></td>';
2154 } //StockEntrydate
2155 print "</tr>";
2156 }
2157 }
2158 }
2159 } else {
2160 // Product need lot
2161 print '<td></td><td></td>';
2162 if (getDolGlobalString('SHIPPING_DISPLAY_STOCK_ENTRY_DATE')) {
2163 print '<td></td>';
2164 } //StockEntrydate
2165 print '</tr>'; // end line and start a new one for lot/serial
2166 print '<!-- Case product need lot -->';
2167
2168 $staticwarehouse = new Entrepot($db);
2169 if ($warehouse_id > 0) {
2170 $staticwarehouse->fetch($warehouse_id);
2171 }
2172
2173 $subj = 0;
2174 // Define nb of lines suggested for this order line
2175 $nbofsuggested = 0;
2176 if (is_object($product->stock_warehouse[$warehouse_id]) && !empty($product->stock_warehouse[$warehouse_id]->detail_batch)) {
2177 foreach ($product->stock_warehouse[$warehouse_id]->detail_batch as $dbatch) {
2178 $nbofsuggested++;
2179 }
2180 }
2181 print '<input name="idl'.$indiceAsked.'" type="hidden" value="'.$line->id.'">';
2182 if (is_object($product->stock_warehouse[$warehouse_id]) && !empty($product->stock_warehouse[$warehouse_id]->detail_batch)) {
2183 foreach ($product->stock_warehouse[$warehouse_id]->detail_batch as $dbatch) { // $dbatch is instance of Productbatch
2184 //var_dump($dbatch);
2185 $batchStock = +$dbatch->qty; // To get a numeric
2186 $deliverableQty = min($quantityToBeDelivered, $batchStock);
2187
2188 // Now we will check if we have to reduce the deliverableQty by taking into account the qty already suggested in previous line
2189 if (isset($alreadyQtyBatchSetted[$line->fk_product][$dbatch->batch][intval($warehouse_id)])) {
2190 $deliverableQty = min($quantityToBeDelivered, $batchStock - $alreadyQtyBatchSetted[$line->fk_product][$dbatch->batch][intval($warehouse_id)]);
2191 } else {
2192 if (!isset($alreadyQtyBatchSetted[$line->fk_product])) {
2193 $alreadyQtyBatchSetted[$line->fk_product] = array();
2194 }
2195
2196 if (!isset($alreadyQtyBatchSetted[$line->fk_product][$dbatch->batch])) {
2197 $alreadyQtyBatchSetted[$line->fk_product][$dbatch->batch] = array();
2198 }
2199
2200 $deliverableQty = min($quantityToBeDelivered, $batchStock);
2201 }
2202
2203 if ($deliverableQty < 0) {
2204 $deliverableQty = 0;
2205 }
2206
2207 $inputName = 'qtyl' . $indiceAsked . '_' . $subj;
2208 if (GETPOSTISSET($inputName)) {
2209 $deliverableQty = GETPOST($inputName, 'int');
2210 }
2211
2212 $tooltipClass = $tooltipTitle = '';
2213 if (!empty($alreadyQtyBatchSetted[$line->fk_product][$dbatch->batch][intval($warehouse_id)])) {
2214 $tooltipClass = ' classfortooltip';
2215 $tooltipTitle = $langs->trans('StockQuantitiesAlreadyAllocatedOnPreviousLines') . ' : ' . $alreadyQtyBatchSetted[$line->fk_product][$dbatch->batch][intval($warehouse_id)];
2216 } else {
2217 $alreadyQtyBatchSetted[$line->fk_product][$dbatch->batch][intval($warehouse_id)] = 0;
2218 }
2219 $alreadyQtyBatchSetted[$line->fk_product][$dbatch->batch][intval($warehouse_id)] = $deliverableQty + $alreadyQtyBatchSetted[$line->fk_product][$dbatch->batch][intval($warehouse_id)];
2220
2221 print '<!-- subj=' . $subj . '/' . $nbofsuggested . ' --><tr ' . ((($subj + 1) == $nbofsuggested) ? 'oddeven' : '') . '>';
2222 print '<td colspan="3" ></td><td class="center">';
2223 $qtylValue = $deliverableQty;
2224 if (getDolGlobalBool('SHIPMENT_DONT_PREFILL_QTY', false)) {
2225 $qtylValue = '';
2226 } elseif (is_numeric($qtylValue)) {
2227 $qtylValue = price($qtylValue);
2228 }
2229 print '<input class="qtyl ' . $tooltipClass . ' right" title="' . $tooltipTitle . '" name="qtyl' . $indiceAsked . '_' . $subj . '" id="qtyl' . $indiceAsked . '_' . $subj . '" type="text" size="4" value="' . $qtylValue . '">';
2230 print '</td>';
2231
2232 print '<!-- Show details of lot -->';
2233 print '<td class="left">';
2234
2235 print $staticwarehouse->getNomUrl(0) . ' / ';
2236
2237 print '<input name="batchl' . $indiceAsked . '_' . $subj . '" type="hidden" value="' . $dbatch->id . '">';
2238
2239 $detail = '';
2240 $detail .= $langs->trans("Batch") . ': ' . $dbatch->batch;
2241 if (!getDolGlobalString('PRODUCT_DISABLE_SELLBY') && !empty($dbatch->sellby)) {
2242 $detail .= ' - ' . $langs->trans("SellByDate") . ': ' . dol_print_date($dbatch->sellby, "day");
2243 }
2244 if (!getDolGlobalString('PRODUCT_DISABLE_EATBY') && !empty($dbatch->eatby)) {
2245 $detail .= ' - ' . $langs->trans("EatByDate") . ': ' . dol_print_date($dbatch->eatby, "day");
2246 }
2247 $detail .= ' - ' . $langs->trans("Qty") . ': ' . $dbatch->qty;
2248 $detail .= '<br>';
2249 print $detail;
2250
2251 $quantityToBeDelivered -= $deliverableQty;
2252 if ($quantityToBeDelivered < 0) {
2253 $quantityToBeDelivered = 0;
2254 }
2255 $subj++;
2256 print '</td>';
2257 if (getDolGlobalInt('SHIPPING_DISPLAY_STOCK_ENTRY_DATE')) {
2258 print '<td>' . dol_print_date($dbatch->context['stock_entry_date'], 'day') . '</td>'; //StockEntrydate
2259 }
2260 print '</tr>';
2261 }
2262 } else {
2263 print '<!-- Case there is no details of lot at all -->';
2264 print '<tr class="oddeven"><td colspan="3"></td><td class="center">';
2265 print '<input class="qtyl right" name="qtyl' . $indiceAsked . '_' . $subj . '" id="qtyl' . $indiceAsked . '_' . $subj . '" type="text" size="4" value="0" disabled="disabled"> ';
2266 print '</td>';
2267
2268 print '<td class="left">';
2269 print img_warning() . ' ' . $langs->trans("NoProductToShipFoundIntoStock", $staticwarehouse->label);
2270 print '</td>';
2271 if (getDolGlobalInt('SHIPPING_DISPLAY_STOCK_ENTRY_DATE')) {
2272 print '<td></td>';
2273 } //StockEntrydate
2274 print '</tr>';
2275 }
2276 }
2277 } else {
2278 // ship from multiple locations
2279 if (!isModEnabled('productbatch') || !$product->hasbatch()) {
2280 print '<!-- Case warehouse not already known and product does not need lot -->';
2281 print '<td></td><td></td>';
2282 if (getDolGlobalString('SHIPPING_DISPLAY_STOCK_ENTRY_DATE')) {
2283 print '<td></td>';
2284 } //StockEntrydate
2285 print '</tr>' . "\n"; // end line and start a new one for each warehouse
2286
2287 print '<input name="idl' . $indiceAsked . '" type="hidden" value="' . $line->id . '">';
2288 $subj = 0;
2289 // Define nb of lines suggested for this order line
2290 $nbofsuggested = 0;
2291
2292 foreach ($product->stock_warehouse as $warehouse_id => $stock_warehouse) {
2293 if ($stock_warehouse->real > 0 || !getDolGlobalInt('STOCK_DISALLOW_NEGATIVE_TRANSFER')) {
2294 $nbofsuggested++;
2295 }
2296 }
2297 $tmpwarehouseObject = new Entrepot($db);
2298 foreach ($product->stock_warehouse as $warehouse_id => $stock_warehouse) { // $stock_warehouse is product_stock
2299 $var = $subj % 2;
2300 if (!empty($warehousePicking) && !in_array($warehouse_id, $warehousePicking)) {
2301 // if a warehouse was selected by user, picking is limited to this warehouse and his children
2302 continue;
2303 }
2304
2305 $tmpwarehouseObject->fetch($warehouse_id);
2306 if ($stock_warehouse->real > 0 || !getDolGlobalInt('STOCK_DISALLOW_NEGATIVE_TRANSFER')) {
2307 $stock = +$stock_warehouse->real; // Convert it to number
2308 $deliverableQty = min($quantityToBeDelivered, $stock);
2309 $deliverableQty = max(0, $deliverableQty);
2310 // Quantity to send
2311 print '<!-- subj=' . $subj . '/' . $nbofsuggested . ' --><tr ' . ((($subj + 1) == $nbofsuggested) ? 'oddeven' : '') . '>';
2312 print '<td colspan="3" ></td><td class="center"><!-- qty to ship (no lot management for product line indiceAsked=' . $indiceAsked . ') -->';
2313 if ($line->product_type == Product::TYPE_PRODUCT || getDolGlobalString('STOCK_SUPPORTS_SERVICES') || getDolGlobalString('SHIPMENT_SUPPORTS_SERVICES')) {
2314 if (isset($alreadyQtySetted[$line->fk_product][intval($warehouse_id)])) {
2315 $deliverableQty = min($quantityToBeDelivered, $stock - $alreadyQtySetted[$line->fk_product][intval($warehouse_id)]);
2316 } else {
2317 if (!isset($alreadyQtySetted[$line->fk_product])) {
2318 $alreadyQtySetted[$line->fk_product] = array();
2319 }
2320
2321 $deliverableQty = min($quantityToBeDelivered, $stock);
2322 }
2323
2324 if ($deliverableQty < 0) {
2325 $deliverableQty = 0;
2326 }
2327
2328 $tooltipClass = $tooltipTitle = '';
2329 if (!empty($alreadyQtySetted[$line->fk_product][intval($warehouse_id)])) {
2330 $tooltipClass = ' classfortooltip';
2331 $tooltipTitle = $langs->trans('StockQuantitiesAlreadyAllocatedOnPreviousLines') . ' : ' . $alreadyQtySetted[$line->fk_product][intval($warehouse_id)];
2332 } else {
2333 $alreadyQtySetted[$line->fk_product][intval($warehouse_id)] = 0;
2334 }
2335
2336 $alreadyQtySetted[$line->fk_product][intval($warehouse_id)] = $deliverableQty + $alreadyQtySetted[$line->fk_product][intval($warehouse_id)];
2337
2338 $inputName = 'qtyl' . $indiceAsked . '_' . $subj;
2339 if (GETPOSTISSET($inputName)) {
2340 $deliverableQty = GETPOSTINT($inputName);
2341 }
2342 $qtylValue = $deliverableQty;
2343 if (getDolGlobalBool('SHIPMENT_DONT_PREFILL_QTY', false)) {
2344 $qtylValue = '';
2345 } elseif (is_numeric($qtylValue)) {
2346 $qtylValue = price($qtylValue);
2347 }
2348 print '<input class="qtyl' . $tooltipClass . ' right" title="' . $tooltipTitle . '" name="qtyl' . $indiceAsked . '_' . $subj . '" id="qtyl' . $indiceAsked . '" type="text" size="4" value="' . $qtylValue . '">';
2349 print '<input name="ent1' . $indiceAsked . '_' . $subj . '" type="hidden" value="' . $warehouse_id . '">';
2350 } else {
2351 if (getDolGlobalString('SHIPMENT_GETS_ALL_ORDER_PRODUCTS')) {
2352 print '<input name="qtyl' . $indiceAsked . '_' . $subj . '" id="qtyl' . $indiceAsked . '" type="hidden" value="0">';
2353 }
2354
2355 print $langs->trans("NA");
2356 }
2357 print '</td>';
2358
2359 // Stock
2360 print '<td class="left">';
2361 if ($line->product_type == Product::TYPE_PRODUCT || getDolGlobalString('STOCK_SUPPORTS_SERVICES')) {
2362 if ($product->stockable_product == Product::ENABLED_STOCK || $productChildrenNb > 0) {
2363 print $tmpwarehouseObject->getNomUrl(0) . ' ';
2364 if ($productChildrenNb <= 0) {
2365 print '<!-- Show details of stock -->';
2366 print '(' . $stock . ')';
2367 }
2368 } else {
2369 print img_warning() . ' ' . $langs->trans('StockDisabled');
2370 }
2371 } else {
2372 print '<span class="opacitymedium">(' . $langs->trans("Service") . ')</span>';
2373 }
2374 print '</td>';
2375 $quantityToBeDelivered -= $deliverableQty;
2376 if ($quantityToBeDelivered < 0) {
2377 $quantityToBeDelivered = 0;
2378 }
2379 $subj++;
2380 if (getDolGlobalString('SHIPPING_DISPLAY_STOCK_ENTRY_DATE')) {
2381 print '<td></td>';
2382 } //StockEntrydate
2383 print "</tr>\n";
2384 }
2385 }
2386 // Show subproducts of product (not recommended)
2387 if (getDolGlobalString('PRODUIT_SOUSPRODUITS') && $line->fk_product > 0) {
2388 $product->get_sousproduits_arbo();
2389 $prods_arbo = $product->get_arbo_each_prod($qtyProdCom);
2390 if (count($prods_arbo) > 0) {
2391 foreach ($prods_arbo as $key => $value) {
2392 //print $value[0];
2393 $img = '';
2394 if ($value['stock'] < $value['stock_alert']) {
2395 $img = img_warning($langs->trans("StockTooLow"));
2396 }
2397 print '<tr class"oddeven"><td>';
2398 print "&nbsp; &nbsp; &nbsp; ->
2399 <a href=\"" . DOL_URL_ROOT . "/product/card.php?id=" . $value['id'] . "\">" . $value['fullpath'] . "
2400 </a> (" . $value['nb'] . ")</td><td class=\"center\"> " . $value['nb_total'] . "</td><td>&nbsp;</td><td>&nbsp;</td>
2401 <td class=\"center\">" . $value['stock'] . " " . $img . "</td>";
2402 if (getDolGlobalString('SHIPPING_DISPLAY_STOCK_ENTRY_DATE')) {
2403 print '<td></td>';
2404 } //StockEntrydate
2405 print "</tr>";
2406 }
2407 }
2408 }
2409 } else {
2410 print '<!-- Case warehouse not already known and product need lot -->';
2411 print '<td></td><td></td>';
2412 if (getDolGlobalString('SHIPPING_DISPLAY_STOCK_ENTRY_DATE')) {
2413 print '<td></td>';
2414 } //StockEntrydate
2415 print '</tr>'; // end line and start a new one for lot/serial
2416
2417 $subj = 0;
2418 print '<input name="idl' . $indiceAsked . '" type="hidden" value="' . $line->id . '">';
2419
2420 $tmpwarehouseObject = new Entrepot($db);
2421 $productlotObject = new Productlot($db);
2422
2423 // Define nb of lines suggested for this order line
2424 $nbofsuggested = 0;
2425 foreach ($product->stock_warehouse as $warehouse_id => $stock_warehouse) {
2426 if (($stock_warehouse->real > 0 || !getDolGlobalInt('STOCK_DISALLOW_NEGATIVE_TRANSFER')) && (!empty($stock_warehouse->detail_batch))) {
2427 $nbofsuggested += count($stock_warehouse->detail_batch);
2428 }
2429 }
2430
2431 foreach ($product->stock_warehouse as $warehouse_id => $stock_warehouse) {
2432 $var = $subj % 2;
2433 if (!empty($warehousePicking) && !in_array($warehouse_id, $warehousePicking)) {
2434 // if a warehouse was selected by user, picking is limited to this warehouse and his children
2435 continue;
2436 }
2437
2438 $tmpwarehouseObject->fetch($warehouse_id);
2439 if (($stock_warehouse->real > 0 || !getDolGlobalInt('STOCK_DISALLOW_NEGATIVE_TRANSFER')) && (!empty($stock_warehouse->detail_batch))) {
2440 foreach ($stock_warehouse->detail_batch as $dbatch) {
2441 $batchStock = +$dbatch->qty; // To get a numeric
2442 if (isset($alreadyQtyBatchSetted[$line->fk_product][$dbatch->batch][intval($warehouse_id)])) {
2443 $deliverableQty = min($quantityToBeDelivered, $batchStock - $alreadyQtyBatchSetted[$line->fk_product][$dbatch->batch][intval($warehouse_id)]);
2444 } else {
2445 if (!isset($alreadyQtyBatchSetted[$line->fk_product])) {
2446 $alreadyQtyBatchSetted[$line->fk_product] = array();
2447 }
2448
2449 if (!isset($alreadyQtyBatchSetted[$line->fk_product][$dbatch->batch])) {
2450 $alreadyQtyBatchSetted[$line->fk_product][$dbatch->batch] = array();
2451 }
2452
2453 $deliverableQty = min($quantityToBeDelivered, $batchStock);
2454 }
2455
2456 if ($deliverableQty < 0) {
2457 $deliverableQty = 0;
2458 }
2459
2460 $inputName = 'qtyl' . $indiceAsked . '_' . $subj;
2461 if (GETPOSTISSET($inputName)) {
2462 $deliverableQty = GETPOSTINT($inputName);
2463 }
2464
2465 $tooltipClass = $tooltipTitle = '';
2466 if (!empty($alreadyQtyBatchSetted[$line->fk_product][$dbatch->batch][intval($warehouse_id)])) {
2467 $tooltipClass = ' classfortooltip';
2468 $tooltipTitle = $langs->trans('StockQuantitiesAlreadyAllocatedOnPreviousLines') . ' : ' . $alreadyQtyBatchSetted[$line->fk_product][$dbatch->batch][intval($warehouse_id)];
2469 } else {
2470 $alreadyQtyBatchSetted[$line->fk_product][$dbatch->batch][intval($warehouse_id)] = 0;
2471 }
2472 $alreadyQtyBatchSetted[$line->fk_product][$dbatch->batch][intval($warehouse_id)] = $deliverableQty + $alreadyQtyBatchSetted[$line->fk_product][$dbatch->batch][intval($warehouse_id)];
2473
2474 print '<!-- subj=' . $subj . '/' . $nbofsuggested . ' --><tr ' . ((($subj + 1) == $nbofsuggested) ? 'oddeven' : '') . '><td colspan="3"></td><td class="center">';
2475 $qtylValue = $deliverableQty;
2476 if (getDolGlobalBool('SHIPMENT_DONT_PREFILL_QTY', false)) {
2477 $qtylValue = '';
2478 } elseif (is_numeric($qtylValue)) {
2479 $qtylValue = price($qtylValue);
2480 }
2481 print '<input class="qtyl right ' . $tooltipClass . '" title="' . $tooltipTitle . '" name="' . $inputName . '" id="' . $inputName . '" type="text" size="4" value="' . $qtylValue . '">';
2482 print '</td>';
2483
2484 print '<td class="left">';
2485
2486 print $tmpwarehouseObject->getNomUrl(0) . ' / ';
2487
2488 print '<!-- Show details of lot -->';
2489 print '<input name="batchl' . $indiceAsked . '_' . $subj . '" type="hidden" value="' . $dbatch->id . '">';
2490 print '<input name="entl' . $indiceAsked . '_'.$subj.'" type="hidden" value="' . $tmpwarehouseObject->id . '">';
2491
2492 //print '|'.$line->fk_product.'|'.$dbatch->batch.'|<br>';
2493 print $langs->trans("Batch") . ': ';
2494 $result = $productlotObject->fetch(0, $line->fk_product, $dbatch->batch);
2495 if ($result > 0) {
2496 print $productlotObject->getNomUrl(1);
2497 } else {
2498 print $langs->trans("TableLotIncompleteRunRepairWithParamStandardEqualConfirmed");
2499 }
2500 if (!getDolGlobalString('PRODUCT_DISABLE_SELLBY') && !empty($dbatch->sellby)) {
2501 print ' - ' . $langs->trans("SellByDate") . ': ' . dol_print_date($dbatch->sellby, "day");
2502 }
2503 if (!getDolGlobalString('PRODUCT_DISABLE_EATBY') && !empty($dbatch->eatby)) {
2504 print ' - ' . $langs->trans("EatByDate") . ': ' . dol_print_date($dbatch->eatby, "day");
2505 }
2506 print ' (' . $dbatch->qty . ')';
2507 $quantityToBeDelivered -= $deliverableQty;
2508 if ($quantityToBeDelivered < 0) {
2509 $quantityToBeDelivered = 0;
2510 }
2511 //dol_syslog('deliverableQty = '.$deliverableQty.' batchStock = '.$batchStock);
2512 $subj++;
2513 print '</td>';
2514 if (getDolGlobalString('SHIPPING_DISPLAY_STOCK_ENTRY_DATE')) {
2515 print '<td class="left">' . dol_print_date($dbatch->context['stock_entry_date'], 'day') . '</td>';
2516 }
2517 print '</tr>';
2518 }
2519 }
2520 }
2521 }
2522 if ($subj == 0) { // Line not shown yet, we show it
2523 $warehouse_selected_id = GETPOSTINT('entrepot_id');
2524
2525 print '<!-- line not shown yet, we show it -->';
2526 print '<tr class="oddeven"><td colspan="3"></td><td class="center">';
2527
2528 if ($line->product_type == Product::TYPE_PRODUCT || getDolGlobalString('STOCK_SUPPORTS_SERVICES')) {
2529 $disabled = '';
2530 $alt = '';
2531 if (isModEnabled('productbatch') && $product->hasbatch()) {
2532 $disabled = 'disabled="disabled"';
2533 $alt = 'Product need serial or batch number';
2534 }
2535 if ($warehouse_selected_id <= 0) { // We did not force a given warehouse, so we won't have no warehouse to change qty.
2536 $disabled = 'disabled="disabled"';
2537 }
2538 // finally we overwrite the input with the product status stockable_product if it's disabled
2539 if ($product->stockable_product == Product::ENABLED_STOCK) {
2540 $disabled = '';
2541 }
2542 print '<input class="qtyl right" name="qtyl'.$indiceAsked.'_'.$subj.'" id="qtyl'.$indiceAsked.'_'.$subj.'" type="text" size="4" value="0"'.($disabled ? ' '.$disabled : '').($alt ? ' title="'.dolPrintHTMLForAttribute($alt).'"' : '').'> ';
2543 if (empty($disabled) && (!getDolGlobalInt('STOCK_DISALLOW_NEGATIVE_TRANSFER') || $product->stockable_product == Product::DISABLED_STOCK)) {
2544 print '<input name="ent1' . $indiceAsked . '_' . $subj . '" type="hidden" value="' . $warehouse_selected_id . '">';
2545 }
2546 } elseif ($line->product_type == Product::TYPE_SERVICE && getDolGlobalString('SHIPMENT_SUPPORTS_SERVICES')) {
2547 $disabled = '';
2548 if (isModEnabled('productbatch') && $product->hasbatch()) {
2549 $disabled = 'disabled="disabled"';
2550 }
2551 if ($warehouse_selected_id <= 0) { // We did not force a given warehouse, so we won't have no warehouse to change qty.
2552 $disabled = 'disabled="disabled"';
2553 }
2554 print '<input class="qtyl right" name="qtyl'.$indiceAsked.'_'.$subj.'" id="qtyl'.$indiceAsked.'_'.$subj.'" type="text" size="4" value="'.$quantityToBeDelivered.'"'.($disabled ? ' '.$disabled : '').'> ';
2555 if (empty($disabled) && !getDolGlobalInt('STOCK_DISALLOW_NEGATIVE_TRANSFER')) {
2556 print '<input name="ent1' . $indiceAsked . '_' . $subj . '" type="hidden" value="' . $warehouse_selected_id . '">';
2557 }
2558 } else {
2559 print $langs->trans("NA");
2560 }
2561 print '</td>';
2562
2563 print '<td class="left">';
2564 if ($line->product_type == Product::TYPE_PRODUCT || getDolGlobalString('STOCK_SUPPORTS_SERVICES')) {
2565 // product may use stock management
2566 if (($warehouse_selected_id > 0 && $product->stockable_product == Product::ENABLED_STOCK)) {
2567 $warehouseObject = new Entrepot($db);
2568 $warehouseObject->fetch($warehouse_selected_id);
2569 print img_warning() . ' ' . $langs->trans("NoProductToShipFoundIntoStock", $warehouseObject->label);
2570 } else {
2571 if ($line->fk_product) {
2572 if ($product->stockable_product != Product::ENABLED_STOCK) {
2573 print img_warning() . ' ' . $langs->trans('StockDisabled');
2574 } else {
2575 print img_warning() . ' ' . $langs->trans('StockTooLow');
2576 }
2577 } else {
2578 print '';
2579 }
2580 }
2581 } else {
2582 print '<span class="opacitymedium">(' . $langs->trans("Service") . ')</span>';
2583 }
2584 print '</td>';
2585 if (getDolGlobalString('SHIPPING_DISPLAY_STOCK_ENTRY_DATE')) {
2586 print '<td></td>';
2587 } //StockEntrydate
2588 print '</tr>';
2589 }
2590 }
2591
2592 // Display lines for extrafields of the Shipment line
2593 // $line is a 'Order line'
2594 $colspan = 5;
2595 $expLine = new ExpeditionLigne($db);
2596
2597 $srcLine = new OrderLine($db);
2598 $srcLine->id = $line->id;
2599 $srcLine->fetch_optionals(); // fetch extrafields also available in orderline
2600
2601 $expLine->array_options = array_merge($expLine->array_options, $srcLine->array_options);
2602
2603 print $expLine->showOptionals($extrafields, 'edit', array('style' => 'class="drag drop oddeven"', 'colspan' => $colspan), (string) $indiceAsked, '', '1');
2604 } elseif (empty($reshook) && $line->special_code == SUBTOTALS_SPECIAL_CODE && !in_array($line->id, $title_lines_to_disable)) {
2605 require dol_buildpath('/core/tpl/subtotalline_select.tpl.php');
2606 }
2607
2608 $indiceAsked++;
2609 }
2610
2611 print "</table>";
2612 print '</div>';
2613
2614 print '<br>';
2615
2616 print $form->buttonsSaveCancel("Create");
2617
2618 print '</form>';
2619
2620 print '<br>';
2621 } else {
2622 dol_print_error($db);
2623 }
2624 }
2625} elseif ($object->id > 0) {
2626 '@phan-var-force Expedition $object'; // Need to force it (type overridden earlier)
2627
2628 // Edit and view mode
2629
2630 $lines = $object->lines;
2631
2632 $num_prod = count($lines);
2633
2634 if (!empty($object->origin) && $object->origin_id > 0) {
2635 $typeobject = $object->origin;
2636 $origin = $object->origin;
2637 $origin_id = $object->origin_id;
2638
2639 $object->fetch_origin(); // Load property $object->origin_object (old $object->commande, $object->propal, ...)
2640 }
2641
2642 $soc = new Societe($db);
2643 $soc->fetch($object->socid);
2644
2645 $res = $object->fetch_optionals();
2646
2647 $head = shipping_prepare_head($object);
2648 print dol_get_fiche_head($head, 'shipping', $langs->trans("Shipment"), -1, $object->picto);
2649
2650 $formconfirm = '';
2651
2652 // Confirm deletion
2653 if ($action == 'delete') {
2654 $formquestion = array();
2655 if ($object->status == Expedition::STATUS_CLOSED && getDolGlobalString('STOCK_CALCULATE_ON_SHIPMENT_CLOSE')) {
2656 $formquestion = array(
2657 array(
2658 'label' => $langs->trans('ShipmentIncrementStockOnDelete'),
2659 'name' => 'alsoUpdateStock',
2660 'type' => 'checkbox',
2661 'value' => 0
2662 ),
2663 );
2664 }
2665 $formconfirm = $form->formconfirm(
2666 $_SERVER['PHP_SELF'] . '?id=' . $object->id,
2667 $langs->trans('DeleteSending'),
2668 $langs->trans("ConfirmDeleteSending", $object->ref),
2669 'confirm_delete',
2670 $formquestion,
2671 0,
2672 1
2673 );
2674 }
2675
2676 // Confirm delete of subtotal line
2677 if ($action == 'ask_subtotal_deleteline') {
2678 $lineid = GETPOSTINT('lineid');
2679 $langs->load("subtotals");
2680 $title = "DeleteSubtotalLine";
2681 $question = "ConfirmDeleteSubtotalLine";
2682 if (GETPOST('type') == 'title') {
2683 $formconfirm = array(array('type' => 'checkbox', 'name' => 'deletecorrespondingsubtotalline', 'label' => $langs->trans("DeleteCorrespondingSubtotalLine"), 'value' => 0));
2684 $title = "DeleteTitleLine";
2685 $question = "ConfirmDeleteTitleLine";
2686 }
2687 $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"] . '?id=' . $object->id . '&lineid=' . $lineid, $langs->trans($title), $langs->trans($question), 'confirm_delete_subtotalline', $formconfirm, 'no', 1);
2688 }
2689
2690 // Confirm validation
2691 if ($action == 'valid') {
2692 $objectref = substr($object->ref, 1, 4);
2693 if ($objectref == 'PROV') {
2694 $numref = $object->getNextNumRef($soc);
2695 } else {
2696 $numref = (string) $object->ref;
2697 }
2698
2699 $text = $langs->trans("ConfirmValidateSending", $numref);
2700 if (getDolGlobalString('STOCK_CALCULATE_ON_SHIPMENT')) {
2701 $text .= '<br>' . img_picto('', 'movement', 'class="pictofixedwidth"') . $langs->trans("StockMovementWillBeRecorded") . '.';
2702 } elseif (getDolGlobalString('STOCK_CALCULATE_ON_SHIPMENT_CLOSE')) {
2703 $text .= '<br>' . img_picto('', 'movement', 'class="pictofixedwidth"') . $langs->trans("StockMovementNotYetRecorded") . '.';
2704 }
2705
2706 if (isModEnabled('notification')) {
2707 require_once DOL_DOCUMENT_ROOT . '/core/class/notify.class.php';
2708 $notify = new Notify($db);
2709 $text .= '<br>';
2710 $text .= $notify->confirmMessage('SHIPPING_VALIDATE', $object->socid, $object);
2711 }
2712
2713 $formconfirm = $form->formconfirm($_SERVER['PHP_SELF'].'?id='.$object->id, $langs->trans('ValidateSending'), $text, 'confirm_valid', '', 0, 1, 260);
2714 }
2715
2716 // Confirm cancellation
2717 if ($action == 'cancel') {
2718 $formconfirm = $form->formconfirm($_SERVER['PHP_SELF'] . '?id=' . $object->id, $langs->trans('CancelSending'), $langs->trans("ConfirmCancelSending", $object->ref), 'confirm_cancel', '', 0, 1);
2719 }
2720
2721 // Confirm sign
2722 if ($action == 'sign') {
2723 $text = $langs->trans('ConfirmSignShipping');
2724 if (isModEnabled('notification')) {
2725 require_once DOL_DOCUMENT_ROOT . '/core/class/notify.class.php';
2726 $notify = new Notify($db);
2727 $text .= '<br>';
2728 $text .= $notify->confirmMessage('SHIPPING_MODIFY', $object->socid, $object);
2729 }
2730 $formquestion = [];
2731 $formquestion[] = [
2732 'type' => 'select',
2733 'name' => 'signed_status',
2734 'select_show_empty' => 0,
2735 'label' => '<span class="fieldrequired">' . $langs->trans('SignStatus') . '</span>',
2736 'values' => $object->getSignedStatusLocalisedArray()
2737 ];
2738 $formconfirm = $form->formconfirm(dolBuildUrl($_SERVER["PHP_SELF"], ['id' => $object->id]), $langs->trans('SignShipping'), $text, 'confirm_sign', $formquestion, 0, 1);
2739 }
2740
2741 // Confirm unsign
2742 if ($action == 'unsign') {
2743 $text = $langs->trans('ConfirmUnsignShipping');
2744 if (isModEnabled('notification')) {
2745 require_once DOL_DOCUMENT_ROOT . '/core/class/notify.class.php';
2746 $notify = new Notify($db);
2747 $text .= '<br>';
2748 $text .= $notify->confirmMessage('SHIPPING_MODIFY', $object->socid, $object);
2749 }
2750 $formconfirm = $form->formconfirm(dolBuildUrl($_SERVER["PHP_SELF"], ['id' => $object->id]), $langs->trans('UnsignShipping'), $text, 'confirm_unsign', '', 0, 1);
2751 }
2752
2753 // Call Hook formConfirm
2754 $parameters = array('formConfirm' => $formconfirm);
2755 $reshook = $hookmanager->executeHooks('formConfirm', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
2756 if (empty($reshook)) {
2757 $formconfirm .= $hookmanager->resPrint;
2758 } elseif ($reshook > 0) {
2759 $formconfirm = $hookmanager->resPrint;
2760 }
2761
2762 // Print form confirm
2763 print $formconfirm;
2764
2765 // Calculate totalWeight and totalVolume for all products
2766 // by adding weight and volume of each product line.
2767 $tmparray = $object->getTotalWeightVolume();
2768 $totalWeight = $tmparray['weight'];
2769 $totalVolume = $tmparray['volume'];
2770
2771 if (!empty($typeobject) && $typeobject === 'commande' && is_object($object->origin_object) && $object->origin_object->id && isModEnabled('order')) {
2772 $objectsrc = new Commande($db);
2773 $objectsrc->fetch($object->origin_object->id);
2774 }
2775 if (!empty($typeobject) && $typeobject === 'propal' && is_object($object->origin_object) && $object->origin_object->id && isModEnabled("propal")) {
2776 $objectsrc = new Propal($db);
2777 $objectsrc->fetch($object->origin_object->id);
2778 }
2779
2780 // Shipment card
2781 $linkback = '<a href="' . DOL_URL_ROOT . '/expedition/list.php?restore_lastsearch_values=1' . (!empty($socid) ? '&socid=' . $socid : '') . '">' . $langs->trans("BackToList") . '</a>';
2782 $morehtmlref = '<div class="refidno">';
2783 // Ref customer shipment
2784 $morehtmlref .= $form->editfieldkey("RefCustomer", 'ref_customer', $object->ref_customer, $object, $user->hasRight('expedition', 'creer'), 'string', '', 0, 1);
2785 $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);
2786
2787 // Thirdparty
2788 $morehtmlref .= '<br>' . $object->thirdparty->getNomUrl(1);
2789
2790 // Project
2791 if ($origin && $origin_id > 0) {
2792 if (isModEnabled('project')) {
2793 $langs->load("projects");
2794 $morehtmlref .= '<br>';
2795 if (0) { // @phpstan-ignore-line Do not change on shipment
2796 $morehtmlref .= img_picto($langs->trans("Project"), 'project', 'class="pictofixedwidth"');
2797 if ($action != 'classify') {
2798 $morehtmlref .= '<a class="editfielda" href="'.$_SERVER['PHP_SELF'].'?action=classify&token='.newToken().'&id='.$object->id.'">'.img_edit($langs->transnoentitiesnoconv('SetProject')).'</a> ';
2799 }
2800 $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'].'?id='.$object->id, $objectsrc->socid, (string) $objectsrc->fk_project, ($action == 'classify' ? 'projectid' : 'none'), 0, 0, 0, 1, '', 'maxwidth300');
2801 } else {
2802 if (!empty($objectsrc) && !empty($objectsrc->fk_project)) {
2803 $proj = new Project($db);
2804 $proj->fetch($objectsrc->fk_project);
2805 $morehtmlref .= $proj->getNomUrl(1);
2806 if ($proj->title) {
2807 $morehtmlref .= '<span class="opacitymedium"> - '.dol_escape_htmltag($proj->title).'</span>';
2808 }
2809 }
2810 }
2811 }
2812 } elseif (!$origin && getDolGlobalString('SHIPMENT_STANDALONE')) {
2813 // Project
2814 if (isModEnabled('project')) {
2815 $langs->load("projects");
2816 $morehtmlref .= '<br>';
2817 if ($permissiontoadd) {
2818 $morehtmlref .= img_picto($langs->trans("Project"), 'project', 'class="pictofixedwidth"');
2819 if ($action != 'classify') {
2820 $morehtmlref .= '<a class="editfielda" href="' . $_SERVER['PHP_SELF'] . '?action=classify&token=' . newToken() . '&id=' . $object->id . '">' . img_edit($langs->transnoentitiesnoconv('SetProject')) . '</a> ';
2821 }
2822 $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->socid, (string) $object->fk_project, ($action == 'classify' ? 'projectid' : 'none'), 0, 0, 0, 1, '', 'maxwidth300');
2823 } else {
2824 if (!empty($object->fk_project)) {
2825 $proj = new Project($db);
2826 $proj->fetch($object->fk_project);
2827 $morehtmlref .= $proj->getNomUrl(1);
2828 if ($proj->title) {
2829 $morehtmlref .= '<span class="opacitymedium"> - ' . dol_escape_htmltag($proj->title) . '</span>';
2830 }
2831 }
2832 }
2833 }
2834 }
2835
2836 $morehtmlref .= '</div>';
2837 dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref);
2838
2839 print '<div class="fichecenter">';
2840 print '<div class="fichehalfleft">';
2841 print '<div class="underbanner clearboth"></div>';
2842
2843 print '<table class="border tableforfield centpercent">';
2844
2845 // Linked documents
2846 if (!empty($typeobject) && $typeobject == 'commande' && $object->origin_object->id && isModEnabled('order')) {
2847 print '<tr><td>';
2848 print $langs->trans("RefOrder") . '</td>';
2849 print '<td>';
2850 print $objectsrc->getNomUrl(1, 'commande');
2851 print "</td>\n";
2852 print '</tr>';
2853 }
2854 if (!empty($typeobject) && $typeobject == 'propal' && $object->origin_object->id && isModEnabled("propal")) {
2855 print '<tr><td>';
2856 print $langs->trans("RefProposal") . '</td>';
2857 print '<td>';
2858 print $objectsrc->getNomUrl(1, 'expedition');
2859 print "</td>\n";
2860 print '</tr>';
2861 }
2862
2863 // Date creation
2864 print '<tr><td class="titlefieldmiddle">' . $langs->trans("DateCreation") . '</td>';
2865 print '<td>' . dol_print_date($object->date_creation, "dayhour") . "</td>\n";
2866 print '</tr>';
2867
2868 // Delivery date planned
2869 print '<tr><td height="10">';
2870 print '<table class="nobordernopadding centpercent"><tr><td>';
2871 print $langs->trans('DateDeliveryPlanned');
2872 print '</td>';
2873 if ($action != 'editdate_livraison') {
2874 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>';
2875 }
2876 print '</tr></table>';
2877 print '</td><td>';
2878 if ($action == 'editdate_livraison') {
2879 print '<form name="setdate_livraison" action="' . $_SERVER["PHP_SELF"] . '?id=' . $object->id . '" method="post">';
2880 print '<input type="hidden" name="token" value="' . newToken() . '">';
2881 print '<input type="hidden" name="action" value="setdate_livraison">';
2882 print $form->selectDate($object->date_delivery ? $object->date_delivery : -1, 'liv_', 1, 1, 0, "setdate_livraison", 1, 0);
2883 print '<input type="submit" class="button button-edit smallpaddingimp" value="' . $langs->trans('Modify') . '">';
2884 print '</form>';
2885 } else {
2886 print $object->date_delivery ? dol_print_date($object->date_delivery, 'dayhour') : '&nbsp;';
2887 }
2888 print '</td>';
2889 print '</tr>';
2890
2891 // Delivery sending date
2892 print '<tr><td height="10">';
2893 print '<table class="nobordernopadding centpercent"><tr><td>';
2894 print $langs->trans('DateShipping');
2895 print '</td>';
2896 if ($action != 'editdate_shipping') {
2897 print '<td class="right"><a class="editfielda" href="' . $_SERVER["PHP_SELF"] . '?action=editdate_shipping&token=' . newToken() . '&id=' . $object->id . '">' . img_edit($langs->trans('SetShippingDate'), 1) . '</a></td>';
2898 }
2899 print '</tr></table>';
2900 print '</td><td>';
2901 if ($action == 'editdate_shipping') {
2902 print '<form name="setdate_shipping" action="' . $_SERVER["PHP_SELF"] . '?id=' . $object->id . '" method="post">';
2903 print '<input type="hidden" name="token" value="' . newToken() . '">';
2904 print '<input type="hidden" name="action" value="setdate_shipping">';
2905 print $form->selectDate($object->date_shipping ? $object->date_shipping : -1, 'ship_', 1, 1, 0, "setdate_shipping", 1, 0);
2906 print '<input type="submit" class="button button-edit smallpaddingimp" value="' . $langs->trans('Modify') . '">';
2907 print '</form>';
2908 } else {
2909 print $object->date_shipping ? dol_print_date($object->date_shipping, 'dayhour') : '&nbsp;';
2910 }
2911 print '</td>';
2912 print '</tr>';
2913
2914 // Weight
2915 print '<tr><td>';
2916 print $form->editfieldkey("Weight", 'trueWeight', $object->trueWeight, $object, $user->hasRight('expedition', 'creer'));
2917 print '</td><td>';
2918
2919 if ($action == 'edittrueWeight') {
2920 print '<form name="settrueweight" action="' . $_SERVER["PHP_SELF"] . '" method="post">';
2921 print '<input name="action" value="settrueWeight" type="hidden">';
2922 print '<input name="id" value="' . $object->id . '" type="hidden">';
2923 print '<input type="hidden" name="token" value="' . newToken() . '">';
2924 print '<input id="trueWeight" name="trueWeight" value="' . $object->trueWeight . '" type="text" class="width50 valignmiddle">';
2925 print $formproduct->selectMeasuringUnits("weight_units", "weight", (string) $object->weight_units, 0, 2, 'maxwidth125 valignmiddle');
2926 print ' <input class="button smallpaddingimp valignmiddle" name="modify" value="' . $langs->trans("Modify") . '" type="submit">';
2927 print ' <input class="button button-cancel smallpaddingimp valignmiddle" name="cancel" value="' . $langs->trans("Cancel") . '" type="submit">';
2928 print '</form>';
2929 } else {
2930 print $object->trueWeight;
2931 print ($object->trueWeight && $object->weight_units != '') ? ' ' . measuringUnitString(0, "weight", $object->weight_units) : '';
2932 }
2933
2934 // Calculated
2935 if ($totalWeight > 0) {
2936 if (!empty($object->trueWeight)) {
2937 print ' (' . $langs->trans("SumOfProductWeights") . ': ';
2938 }
2939 print showDimensionInBestUnit($totalWeight, 0, "weight", $langs, getDolGlobalInt('MAIN_WEIGHT_DEFAULT_ROUND', -1), getDolGlobalString('MAIN_WEIGHT_DEFAULT_UNIT', 'no'));
2940 if (!empty($object->trueWeight)) {
2941 print ')';
2942 }
2943 }
2944 print '</td></tr>';
2945
2946 // Width
2947 print '<tr><td>' . $form->editfieldkey("Width", 'trueWidth', $object->trueWidth, $object, $user->hasRight('expedition', 'creer')) . '</td><td>';
2948 print $form->editfieldval("Width", 'trueWidth', $object->trueWidth, $object, $user->hasRight('expedition', 'creer'));
2949 print ($object->trueWidth && $object->width_units != '') ? ' ' . measuringUnitString(0, "size", $object->width_units) : '';
2950 print '</td></tr>';
2951
2952 // Height
2953 print '<tr><td>' . $form->editfieldkey("Height", 'trueHeight', $object->trueHeight, $object, $user->hasRight('expedition', 'creer')) . '</td><td>';
2954 if ($action == 'edittrueHeight') {
2955 print '<form name="settrueHeight" action="' . $_SERVER["PHP_SELF"] . '" method="post">';
2956 print '<input name="action" value="settrueHeight" type="hidden">';
2957 print '<input name="id" value="' . $object->id . '" type="hidden">';
2958 print '<input type="hidden" name="token" value="' . newToken() . '">';
2959 print '<input id="trueHeight" name="trueHeight" value="' . $object->trueHeight . '" type="text" class="width50">';
2960 print $formproduct->selectMeasuringUnits("size_units", "size", $object->size_units, 0, 2);
2961 print ' <input class="button smallpaddingimp" name="modify" value="' . $langs->trans("Modify") . '" type="submit">';
2962 print ' <input class="button button-cancel smallpaddingimp" name="cancel" value="' . $langs->trans("Cancel") . '" type="submit">';
2963 print '</form>';
2964 } else {
2965 print $object->trueHeight;
2966 print ($object->trueHeight && $object->height_units != '') ? ' ' . measuringUnitString(0, "size", $object->height_units) : '';
2967 }
2968
2969 print '</td></tr>';
2970
2971 // Depth
2972 print '<tr><td>' . $form->editfieldkey("Depth", 'trueDepth', $object->trueDepth, $object, $user->hasRight('expedition', 'creer')) . '</td><td>';
2973 print $form->editfieldval("Depth", 'trueDepth', $object->trueDepth, $object, $user->hasRight('expedition', 'creer'));
2974 print ($object->trueDepth && $object->depth_units != '') ? ' ' . measuringUnitString(0, "size", $object->depth_units) : '';
2975 print '</td></tr>';
2976
2977 // Volume
2978 print '<tr><td>';
2979 print $langs->trans("Volume");
2980 print '</td>';
2981 print '<td>';
2982 $calculatedVolume = 0;
2983 $volumeUnit = 0;
2984 if ($object->trueWidth && $object->trueHeight && $object->trueDepth) {
2985 $calculatedVolume = ($object->trueWidth * $object->trueHeight * $object->trueDepth);
2986 $volumeUnit = $object->size_units * 3;
2987 }
2988 // If sending volume not defined we use sum of products
2989 if ($calculatedVolume > 0) {
2990 if ($volumeUnit < 50) {
2991 print showDimensionInBestUnit($calculatedVolume, $volumeUnit, "volume", $langs, getDolGlobalInt('MAIN_VOLUME_DEFAULT_ROUND', -1), getDolGlobalString('MAIN_VOLUME_DEFAULT_UNIT', 'no'));
2992 } else {
2993 print $calculatedVolume . ' ' . measuringUnitString(0, "volume", $volumeUnit);
2994 }
2995 }
2996 if ($totalVolume > 0) {
2997 if ($calculatedVolume) {
2998 print ' (' . $langs->trans("SumOfProductVolumes") . ': ';
2999 }
3000 print showDimensionInBestUnit($totalVolume, 0, "volume", $langs, getDolGlobalInt('MAIN_VOLUME_DEFAULT_ROUND', -1), getDolGlobalString('MAIN_VOLUME_DEFAULT_UNIT', 'no'));
3001 //if (empty($calculatedVolume)) print ' ('.$langs->trans("Calculated").')';
3002 if ($calculatedVolume) {
3003 print ')';
3004 }
3005 }
3006 print "</td>\n";
3007 print '</tr>';
3008
3009 // Other attributes
3010 //$cols = 2;
3011 include DOL_DOCUMENT_ROOT . '/core/tpl/extrafields_view.tpl.php';
3012
3013 print '</table>';
3014
3015 print '</div>';
3016 print '<div class="fichehalfright">';
3017 print '<div class="underbanner clearboth"></div>';
3018
3019 print '<table class="border centpercent tableforfield">';
3020
3021 // Sending method
3022 print '<tr><td>';
3023 print '<table class="nobordernopadding centpercent"><tr><td>';
3024 print $langs->trans('SendingMethod');
3025 print '</td>';
3026
3027 if ($action != 'editshipping_method_id' && $permissiontoadd) {
3028 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>';
3029 }
3030 print '</tr></table>';
3031 print '</td><td>';
3032 if ($action == 'editshipping_method_id') {
3033 print '<form name="setshipping_method_id" action="' . $_SERVER["PHP_SELF"] . '?id=' . $object->id . '" method="post">';
3034 print '<input type="hidden" name="token" value="' . newToken() . '">';
3035 print '<input type="hidden" name="action" value="setshipping_method_id">';
3036 $object->fetch_delivery_methods();
3037 print $form->selectarray("shipping_method_id", $object->meths, $object->shipping_method_id, 1, 0, 0, "", 1);
3038 if ($user->admin) {
3039 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
3040 }
3041 print '<input type="submit" class="button button-edit smallpaddingimp" value="' . $langs->trans('Modify') . '">';
3042 print '</form>';
3043 } else {
3044 if ($object->shipping_method_id > 0) {
3045 // Get code using getLabelFromKey
3046 $code = $langs->getLabelFromKey($db, (string) $object->shipping_method_id, 'c_shipment_mode', 'rowid', 'code');
3047 print $langs->trans("SendingMethod" . strtoupper($code));
3048 }
3049 }
3050 print '</td>';
3051 print '</tr>';
3052
3053 // Tracking Number
3054 print '<tr><td class="titlefieldmiddle">' . $form->editfieldkey("TrackingNumber", 'tracking_number', $object->tracking_number, $object, $user->hasRight('expedition', 'creer')) . '</td><td>';
3055 print $form->editfieldval("TrackingNumber", 'tracking_number', $object->tracking_url, $object, $user->hasRight('expedition', 'creer'), 'safehtmlstring', $object->tracking_number);
3056 print '</td></tr>';
3057
3058 // Incoterms
3059 if (isModEnabled('incoterm')) {
3060 print '<tr><td>';
3061 print '<table class="nobordernopadding centpercent"><tr><td>';
3062 print $langs->trans('IncotermLabel');
3063 print '<td><td class="right">';
3064 if ($permissiontoadd) {
3065 print '<a class="editfielda" href="' . DOL_URL_ROOT . '/expedition/card.php?id=' . $object->id . '&action=editincoterm&token=' . newToken() . '">' . img_edit() . '</a>';
3066 } else {
3067 print '&nbsp;';
3068 }
3069 print '</td></tr></table>';
3070 print '</td>';
3071 print '<td>';
3072 if ($action != 'editincoterm') {
3073 print $form->textwithpicto($object->display_incoterms(), $object->label_incoterms, 1);
3074 } else {
3075 print $form->select_incoterms((!empty($object->fk_incoterms) ? $object->fk_incoterms : ''), (!empty($object->location_incoterms) ? $object->location_incoterms : ''), $_SERVER['PHP_SELF'] . '?id=' . $object->id);
3076 }
3077 print '</td></tr>';
3078 }
3079
3080 // Other attributes
3081 $parameters = array();
3082 $reshook = $hookmanager->executeHooks('formObjectOptions', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
3083 print $hookmanager->resPrint;
3084
3085 print "</table>";
3086
3087 print '</div>';
3088 print '</div>';
3089
3090 print '<div class="clearboth"></div>';
3091
3092 print dol_get_fiche_end();
3093
3094
3095 /*
3096 * Lines of simple shipment
3097 */
3098 if (!$origin && getDolGlobalString('SHIPMENT_STANDALONE')) {
3099 if (!empty($object->table_element_line)) {
3100 // Show object lines
3101 $result = $object->getLinesArray();
3102
3103 print ' <form name="addproduct" id="addproduct" action="'.$_SERVER["PHP_SELF"].'?id='.$object->id.(($action != 'editline') ? '' : '#line_'.GETPOSTINT('lineid')).'" method="POST">
3104 <input type="hidden" name="token" value="' . newToken().'">
3105 <input type="hidden" name="action" value="' . (($action != 'editline') ? 'addline' : 'updateline').'">
3106 <input type="hidden" name="mode" value="">
3107 <input type="hidden" name="page_y" value="">
3108 <input type="hidden" name="id" value="' . $object->id.'">
3109 ';
3110
3111 if (!empty($conf->use_javascript_ajax) && $object->status == 0) {
3112 include DOL_DOCUMENT_ROOT.'/core/tpl/ajaxrow.tpl.php';
3113 }
3114
3115 print '<div class="div-table-responsive-no-min">';
3116 if (!empty($object->lines) || ($object->status == $object::STATUS_DRAFT && $permissiontoadd && $action != 'selectlines' && $action != 'editline')) {
3117 print '<table id="tablelines" class="noborder noshadow" width="100%">';
3118 }
3119
3120 if (!empty($object->lines)) {
3121 $object->printObjectLines($action, $mysoc, null, GETPOSTINT('lineid'), 1, '/expedition/tpl');
3122 }
3123
3124 // Form to add new line
3125 if ($object->status == 0 && $permissiontoadd && $action != 'selectlines') {
3126 if ($action != 'editline') {
3127 // Add products/services form
3128
3129 $parameters = array();
3130 $reshook = $hookmanager->executeHooks('formAddObjectLine', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
3131 if ($reshook < 0) {
3132 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
3133 }
3134 if (empty($reshook)) {
3135 $object->formAddObjectLine(1, $mysoc, $soc);
3136 }
3137 }
3138 }
3139
3140 if (!empty($object->lines) || ($object->status == $object::STATUS_DRAFT && $permissiontoadd && $action != 'selectlines' && $action != 'editline')) {
3141 print '</table>';
3142 }
3143 print '</div>';
3144
3145 print "</form>\n";
3146 }
3147 }
3148
3149 // Lines of products of origin
3150 if (!empty($object->origin) && $object->origin_id > 0) {
3151 if ($action == 'editline') {
3152 print ' <form name="updateline" id="updateline" action="' . $_SERVER["PHP_SELF"] . '?id=' . $object->id . '&amp;lineid=' . $line_id . '" method="POST">
3153 <input type="hidden" name="token" value="' . newToken() . '">
3154 <input type="hidden" name="action" value="updateline">
3155 <input type="hidden" name="mode" value="">
3156 <input type="hidden" name="id" value="' . $object->id . '">
3157 ';
3158 }
3159 print '<br>';
3160
3161 print '<div class="div-table-responsive-no-min">';
3162 print '<table class="noborder centpercent" id="tablelines" >';
3163 print '<thead>';
3164 print '<tr class="liste_titre">';
3165 // Adds a line numbering column
3166 if (getDolGlobalString('MAIN_VIEW_LINE_NUMBER')) {
3167 print '<td width="5" class="center linecolnum">&nbsp;</td>';
3168 }
3169 // Product/Service
3170 print '<td class="linecoldescription" >' . $langs->trans("Products") . '</td>';
3171 // Qty
3172 print '<td class="center linecolqty">' . $langs->trans("QtyOrdered") . '</td>';
3173 if ($origin_id > 0) {
3174 print '<td class="center linecolqtyinothershipments">' . $langs->trans("QtyInOtherShipments") . '</td>';
3175 }
3176 if ($action == 'editline') {
3177 $editColspan = 3;
3178 if (!isModEnabled('stock')) {
3179 $editColspan--;
3180 }
3181 if (!isModEnabled('productbatch')) {
3182 $editColspan--;
3183 }
3184 print '<td class="center linecoleditlineotherinfo" colspan="' . $editColspan . '">';
3185 if ($object->status <= 1) {
3186 print $langs->trans("QtyToShip");
3187 } else {
3188 print $langs->trans("QtyShipped");
3189 }
3190 if (isModEnabled('stock')) {
3191 print ' - ' . $langs->trans("WarehouseSource");
3192 }
3193 if (isModEnabled('productbatch')) {
3194 print ' - ' . $langs->trans("Batch");
3195 }
3196 print '</td>';
3197 } else {
3198 if ($object->status <= 1) {
3199 print '<td class="center linecolqtytoship">' . $langs->trans("QtyToShip") . '</td>';
3200 } else {
3201 print '<td class="center linecolqtyshipped">' . $langs->trans("QtyShipped") . '</td>';
3202 }
3203 if (isModEnabled('stock')) {
3204 print '<td class="left linecolwarehousesource">' . $langs->trans("WarehouseSource") . '</td>';
3205 }
3206
3207 if (isModEnabled('productbatch')) {
3208 print '<td class="left linecolbatch">' . $langs->trans("Batch") . '</td>';
3209 }
3210 }
3211 print '<td class="center linecolweight">' . $langs->trans("CalculatedWeight") . '</td>';
3212 print '<td class="center linecolvolume">' . $langs->trans("CalculatedVolume") . '</td>';
3213 //print '<td class="center">'.$langs->trans("Size").'</td>';
3214 if ($object->status == 0) {
3215 print '<td class="linecoledit"></td>';
3216 print '<td class="linecoldelete" width="10"></td>';
3217 }
3218 print "</tr>\n";
3219 print '</thead>';
3220
3221 $outputlangs = $langs;
3222
3223 if (getDolGlobalInt('MAIN_MULTILANGS') && getDolGlobalString('PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE')) {
3224 $object->fetch_thirdparty();
3225 $newlang = '';
3226 if (/* empty($newlang) && */GETPOST('lang_id', 'aZ09')) {
3227 $newlang = GETPOST('lang_id', 'aZ09');
3228 }
3229 if (empty($newlang)) {
3230 $newlang = $object->thirdparty->default_lang;
3231 }
3232 if (!empty($newlang)) {
3233 $outputlangs = new Translate("", $conf);
3234 $outputlangs->setDefaultLang($newlang);
3235 }
3236 }
3237
3238 // Get list of products already sent for same source object into $alreadysent
3239 $alreadysent = array();
3240 if ($origin_id > 0) {
3241 $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, obj.special_code";
3242 $sql .= ", ed.rowid as shipmentline_id, ed.qty as qty_shipped, ed.fk_expedition as expedition_id, ed.fk_elementdet, ed.fk_entrepot";
3243 $sql .= ", e.rowid as shipment_id, e.ref as shipment_ref, e.date_creation, e.date_valid, e.date_delivery, e.date_expedition";
3244 //if (getDolGlobalInt('MAIN_SUBMODULE_DELIVERY')) $sql .= ", l.rowid as livraison_id, l.ref as livraison_ref, l.date_delivery, ld.qty as qty_received";
3245 $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';
3246 $sql .= ', p.description as product_desc';
3247 $sql .= " FROM " . MAIN_DB_PREFIX . "expeditiondet as ed";
3248 $sql .= ", " . MAIN_DB_PREFIX . "expedition as e";
3249 $sql .= ", " . MAIN_DB_PREFIX . $origin . "det as obj";
3250 //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";
3251 $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "product as p ON obj.fk_product = p.rowid";
3252 $sql .= " WHERE e.entity IN (" . getEntity('expedition') . ")";
3253 $sql .= " AND obj.fk_" . $origin . " = " . ((int) $origin_id);
3254 $sql .= " AND obj.rowid = ed.fk_elementdet";
3255 $sql .= " AND ed.fk_expedition = e.rowid";
3256 //if ($filter) $sql.= $filter;
3257 $sql .= " ORDER BY obj.fk_product";
3258
3259 dol_syslog("expedition/card.php get list of shipment lines", LOG_DEBUG);
3260 $resql = $db->query($sql);
3261 if ($resql) {
3262 $num = $db->num_rows($resql);
3263 $i = 0;
3264
3265 while ($i < $num) {
3266 $obj = $db->fetch_object($resql);
3267 if ($obj) {
3268 // $obj->rowid is rowid in $origin."det" table
3269 $alreadysent[$obj->rowid][$obj->shipmentline_id] = array(
3270 'shipment_ref' => $obj->shipment_ref,
3271 'shipment_id' => $obj->shipment_id,
3272 'warehouse' => $obj->fk_entrepot,
3273 'qty_shipped' => $obj->qty_shipped,
3274 'product_tosell' => $obj->product_tosell,
3275 'product_tobuy' => $obj->product_tobuy,
3276 'product_tobatch' => $obj->product_tobatch,
3277 'date_valid' => $db->jdate($obj->date_valid),
3278 'date_delivery' => $db->jdate($obj->date_delivery));
3279 }
3280 $i++;
3281 }
3282 }
3283 //var_dump($alreadysent);
3284 }
3285
3286 print '<tbody>';
3287
3288 // Loop on each product to send/sent
3289 $conf->cache['product'] = array();
3290 $conf->cache['warehouse'] = array();
3291 for ($i = 0; $i < $num_prod; $i++) {
3292 $parameters = array('i' => $i, 'line' => $lines[$i], 'line_id' => $line_id, 'num' => $num_prod, 'alreadysent' => $alreadysent, 'editColspan' => !empty($editColspan) ? $editColspan : 0, 'outputlangs' => $outputlangs);
3293 $reshook = $hookmanager->executeHooks('printObjectLine', $parameters, $object, $action);
3294 if ($reshook < 0) {
3295 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
3296 }
3297
3298 if (empty($reshook) && $lines[$i]->product_type != "9") {
3299 print '<!-- origin line id = ' . $lines[$i]->origin_line_id . ' -->'; // id of order line
3300 print '<tr class="oddeven" id="row-' . $lines[$i]->id . '" data-id="' . $lines[$i]->id . '" data-element="' . $lines[$i]->element . '" >';
3301
3302 // #
3303 if (getDolGlobalString('MAIN_VIEW_LINE_NUMBER')) {
3304 print '<td class="center linecolnum">' . ($i + 1) . '</td>';
3305 }
3306
3307 // Predefined product or service
3308 if ($lines[$i]->fk_product > 0) {
3309 // Define output language
3310 if (getDolGlobalInt('MAIN_MULTILANGS') && getDolGlobalString('PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE')) {
3311 $product_id = $lines[$i]->fk_product;
3312 if (!isset($conf->cache['product'][$product_id])) {
3313 $prod = new Product($db);
3314 $prod->fetch($product_id);
3315 $conf->cache['product'][$product_id] = $prod;
3316 } else {
3317 $prod = $conf->cache['product'][$product_id];
3318 }
3319 $label = (!empty($prod->multilangs[$outputlangs->defaultlang]["label"])) ? $prod->multilangs[$outputlangs->defaultlang]["label"] : $lines[$i]->product_label;
3320 } else {
3321 $label = (!empty($lines[$i]->label) ? $lines[$i]->label : $lines[$i]->product_label);
3322 }
3323
3324 print '<td class="linecoldescription">';
3325
3326 // Show product and description
3327 $product_static->type = $lines[$i]->fk_product_type;
3328 $product_static->id = $lines[$i]->fk_product;
3329 $product_static->ref = $lines[$i]->ref;
3330 $product_static->status = $lines[$i]->product_tosell;
3331 $product_static->status_buy = $lines[$i]->product_tobuy;
3332 $product_static->status_batch = $lines[$i]->product_tobatch;
3333
3334 $product_static->weight = $lines[$i]->weight;
3335 $product_static->weight_units = $lines[$i]->weight_units;
3336 $product_static->length = $lines[$i]->length;
3337 $product_static->length_units = $lines[$i]->length_units;
3338 $product_static->width = !empty($lines[$i]->width) ? $lines[$i]->width : 0;
3339 $product_static->width_units = !empty($lines[$i]->width_units) ? $lines[$i]->width_units : 0;
3340 $product_static->height = !empty($lines[$i]->height) ? $lines[$i]->height : 0;
3341 $product_static->height_units = !empty($lines[$i]->height_units) ? $lines[$i]->height_units : 0;
3342 $product_static->surface = $lines[$i]->surface;
3343 $product_static->surface_units = $lines[$i]->surface_units;
3344 $product_static->volume = $lines[$i]->volume;
3345 $product_static->volume_units = $lines[$i]->volume_units;
3346 $product_static->stockable_product = $lines[$i]->stockable_product;
3347
3348 $text = $product_static->getNomUrl(1);
3349 $text .= ' - ' . $label;
3350 $description = (getDolGlobalInt('PRODUIT_DESC_IN_FORM_ACCORDING_TO_DEVICE') ? '' : dol_htmlentitiesbr($lines[$i]->description));
3351 print $form->textwithtooltip($text, $description, 3, 0, '', (string) $i);
3352 print_date_range(!empty($lines[$i]->date_start) ? $lines[$i]->date_start : '', !empty($lines[$i]->date_end) ? $lines[$i]->date_end : '');
3353 if (getDolGlobalInt('PRODUIT_DESC_IN_FORM_ACCORDING_TO_DEVICE')) {
3354 print (!empty($lines[$i]->description) && $lines[$i]->description != $lines[$i]->product) ? '<br>' . dol_htmlentitiesbr($lines[$i]->description) : '';
3355 }
3356 print "</td>\n";
3357 } else {
3358 print '<td class="linecoldescription" >';
3359 if ($lines[$i]->product_type == Product::TYPE_SERVICE) {
3360 $text = img_object($langs->trans('Service'), 'service');
3361 } else {
3362 $text = img_object($langs->trans('Product'), 'product');
3363 }
3364
3365 if (!empty($lines[$i]->label)) {
3366 $text .= ' <strong>' . $lines[$i]->label . '</strong>';
3367 print $form->textwithtooltip($text, $lines[$i]->description, 3, 0, '', (string) $i);
3368 } else {
3369 print $text . ' ' . nl2br($lines[$i]->description);
3370 }
3371
3372 print_date_range($lines[$i]->date_start, $lines[$i]->date_end);
3373 print "</td>\n";
3374 }
3375
3376 $unit_order = '';
3377 if (getDolGlobalString('PRODUCT_USE_UNITS')) {
3378 $unit_order = measuringUnitString((int) $lines[$i]->fk_unit);
3379 }
3380
3381 // Qty ordered
3382 print '<td class="center linecolqty">' . $lines[$i]->qty_asked . ' ' . $unit_order . '</td>';
3383
3384 // Qty in other shipments (with shipment and warehouse used)
3385 if ($origin_id > 0) {
3386 print '<td class="linecolqtyinothershipments center nowrap">';
3387 $htmltooltip = '';
3388 $qtyalreadysent = 0;
3389 foreach ($alreadysent as $key => $val) {
3390 if ($lines[$i]->fk_elementdet == $key) {
3391 $j = 0;
3392 foreach ($val as $shipmentline_id => $shipmentline_var) {
3393 if ($shipmentline_var['shipment_id'] == $lines[$i]->fk_expedition) {
3394 continue; // We want to show only "other shipments"
3395 }
3396
3397 $j++;
3398 if ($j > 1) {
3399 $htmltooltip .= '<br>';
3400 }
3401 $shipment_static->fetch($shipmentline_var['shipment_id']);
3402 $htmltooltip .= $shipment_static->getNomUrl(1, '', 0, 0, 1);
3403 $htmltooltip .= ' - ' . $shipmentline_var['qty_shipped'];
3404 $htmltooltip .= ' - ' . $langs->trans("DateValidation") . ' : ' . (empty($shipmentline_var['date_valid']) ? $langs->trans("Draft") : dol_print_date($shipmentline_var['date_valid'], 'dayhour'));
3405 /*if (isModEnabled('stock') && $shipmentline_var['warehouse'] > 0) {
3406 $warehousestatic->fetch($shipmentline_var['warehouse']);
3407 $htmltext .= '<br>'.$langs->trans("FromLocation").' : '.$warehousestatic->getNomUrl(1, '', 0, 1);
3408 }*/
3409 //print ' '.$form->textwithpicto('', $htmltext, 1);
3410
3411 $qtyalreadysent += $shipmentline_var['qty_shipped'];
3412 }
3413 if ($j) {
3414 $htmltooltip = $langs->trans("QtyInOtherShipments") . '...<br><br>' . $htmltooltip . '<br><input type="submit" name="dummyhiddenbuttontogetfocus" style="display:none" autofocus>';
3415 }
3416 }
3417 }
3418 print $form->textwithpicto((string) $qtyalreadysent, $htmltooltip, 1, 'info', '', 0, 3, 'tooltip' . $lines[$i]->id);
3419 print '</td>';
3420 }
3421
3422 if ($action == 'editline' && $lines[$i]->id == $line_id) {
3423 // edit mode
3424 print '<td colspan="' . $editColspan . '" class="center"><table class="nobordernopadding centpercent">';
3425 if (is_array($lines[$i]->detail_batch) && count($lines[$i]->detail_batch) > 0) {
3426 print '<!-- case edit 1 -->';
3427 $line = new ExpeditionLigne($db);
3428 foreach ($lines[$i]->detail_batch as $detail_batch) {
3429 print '<tr>';
3430 // Qty to ship or shipped
3431 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>';
3432 // Batch number management
3433 if ($lines[$i]->entrepot_id == 0) {
3434 // only show lot numbers from src warehouse when shipping from multiple warehouses
3435 $line->fetch($detail_batch->fk_expeditiondet);
3436 }
3437 $entrepot_id = !empty($detail_batch->entrepot_id) ? $detail_batch->entrepot_id : $lines[$i]->entrepot_id;
3438 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>';
3439 print '</tr>';
3440 }
3441 // add a 0 qty lot row to be able to add a lot
3442 print '<tr>';
3443 // Qty to ship or shipped
3444 print '<td><input class="qtyl" name="qtyl' . $line_id . '_0" id="qtyl' . $line_id . '_0" type="text" size="4" value="0"></td>';
3445 // Batch number management
3446 print '<td>' . $formproduct->selectLotStock('', 'batchl' . $line_id . '_0', '', 1, 0, $lines[$i]->fk_product) . '</td>';
3447 print '</tr>';
3448 } elseif (isModEnabled('stock')) {
3449 if ($lines[$i]->fk_product > 0) {
3450 if ($lines[$i]->entrepot_id > 0) {
3451 print '<!-- case edit 2 -->';
3452 print '<tr>';
3453 // Qty to ship or shipped
3454 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>';
3455 // Warehouse source
3456 print '<td>' . $formproduct->selectWarehouses($lines[$i]->entrepot_id, 'entl' . $line_id, '', 1, 0, $lines[$i]->fk_product, '', 1, 0, array(), 'minwidth200') . '</td>';
3457 // Batch number management
3458 print '<td>';
3459 if (isModEnabled('productbatch')) {
3460 print ' - ' . $langs->trans("NA");
3461 }
3462 print '</td>';
3463 print '</tr>';
3464 } elseif (count($lines[$i]->details_entrepot) > 1) {
3465 print '<!-- case edit 3 -->';
3466 foreach ($lines[$i]->details_entrepot as $detail_entrepot) {
3467 print '<tr>';
3468 // Qty to ship or shipped
3469 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>';
3470 // Warehouse source
3471 print '<td>' . $formproduct->selectWarehouses($detail_entrepot->entrepot_id, 'entl' . $detail_entrepot->line_id, '', 1, 0, $lines[$i]->fk_product, '', 1, 0, array(), 'minwidth200') . '</td>';
3472 // Batch number management
3473 print '<td>';
3474 if (isModEnabled('productbatch')) {
3475 print ' - ' . $langs->trans("NA");
3476 }
3477 print '</td>';
3478 print '</tr>';
3479 }
3480 } elseif ($lines[$i]->product_type == Product::TYPE_SERVICE && getDolGlobalString('SHIPMENT_SUPPORTS_SERVICES')) {
3481 print '<!-- case edit 4 -->';
3482 print '<tr>';
3483 // Qty to ship or shipped
3484 print '<td><input class="qtyl right" name="qtyl' . $line_id . '" id="qtyl' . $line_id . '" type="text" size="4" value="' . $lines[$i]->qty_shipped . '"></td>';
3485 print '<td><span class="opacitymedium">(' . $langs->trans("Service") . ')</span></td>';
3486 print '<td></td>';
3487 print '</tr>';
3488 } else {
3489 print '<!-- case edit 5 -->';
3490 print '<tr><td colspan="3">' . $langs->trans("ErrorStockIsNotEnough") . '</td></tr>';
3491 }
3492 } else {
3493 print '<!-- case edit 6 -->';
3494 print '<tr>';
3495 // Qty to ship or shipped
3496 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>';
3497 // Warehouse source
3498 print '<td></td>';
3499 // Batch number management
3500 print '<td></td>';
3501 print '</tr>';
3502 }
3503 } else { // both product batch and stock are not activated.
3504 print '<!-- case edit 7 -->';
3505 print '<tr>';
3506 // Qty to ship or shipped
3507 print '<td><input class="qtyl right" name="qtyl' . $line_id . '" id="qtyl' . $line_id . '" type="text" size="4" value="' . $lines[$i]->qty_shipped . '"></td>';
3508 // Warehouse source
3509 print '<td></td>';
3510 // Batch number management
3511 print '<td></td>';
3512 print '</tr>';
3513 }
3514
3515 print '</table></td>';
3516 } else {
3517 // Qty to ship or shipped
3518 print '<td class="linecolqtytoship center">' . $lines[$i]->qty_shipped . ' ' . $unit_order . '</td>';
3519
3520 // Warehouse source
3521 if (isModEnabled('stock')) {
3522 print '<td class="linecolwarehousesource tdoverflowmax200">';
3523 if ($lines[$i]->product_type == Product::TYPE_SERVICE && getDolGlobalString('SHIPMENT_SUPPORTS_SERVICES')) {
3524 print '<span class="opacitymedium">(' . $langs->trans("Service") . ')</span>';
3525 } elseif ($lines[$i]->entrepot_id > 0 && $lines[$i]->stockable_product == Product::ENABLED_STOCK) {
3526 $warehouse_id = $lines[$i]->entrepot_id;
3527 if (!isset($conf->cache['warehouse'][$warehouse_id])) {
3528 $warehouse = new Entrepot($db);
3529 $warehouse->fetch($warehouse_id);
3530 $conf->cache['warehouse'][$warehouse_id] = $warehouse;
3531 } else {
3532 $warehouse = $conf->cache['warehouse'][$warehouse_id];
3533 }
3534 print $warehouse->getNomUrl(1);
3535 } elseif (count($lines[$i]->details_entrepot) > 1) {
3536 $detail = '';
3537 foreach ($lines[$i]->details_entrepot as $detail_entrepot) {
3538 $warehouse_id = $detail_entrepot->entrepot_id;
3539 if ($warehouse_id > 0) {
3540 if (!isset($conf->cache['warehouse'][$warehouse_id])) {
3541 $warehouse = new Entrepot($db);
3542 $warehouse->fetch($warehouse_id);
3543 $conf->cache['warehouse'][$warehouse_id] = $warehouse;
3544 } else {
3545 $warehouse = $conf->cache['warehouse'][$warehouse_id];
3546 }
3547 $detail .= $langs->trans("DetailWarehouseFormat", $warehouse->label, $detail_entrepot->qty_shipped) . '<br>';
3548 }
3549 }
3550 print $form->textwithtooltip(img_picto('', 'object_stock') . ' ' . $langs->trans("DetailWarehouseNumber"), $detail);
3551 } elseif (count($lines[$i]->detail_children ?? []) > 1) {
3552 $detail = '';
3553 foreach ($lines[$i]->detail_children as $child_product_id => $child_stock_list) {
3554 foreach ($child_stock_list as $warehouse_id => $total_qty) {
3555 // get product from cache
3556 $child_product_label = '';
3557 if (!isset($conf->cache['product'][$child_product_id])) {
3558 $child_product = new Product($db);
3559 $child_product->fetch($child_product_id);
3560 $conf->cache['product'][$child_product_id] = $child_product;
3561 } else {
3562 $child_product = $conf->cache['product'][$child_product_id];
3563 }
3564 $child_product_label = $child_product->ref . ' ' . $child_product->label;
3565
3566 // get warehouse from cache
3567 if (!isset($conf->cache['warehouse'][$warehouse_id])) {
3568 $child_warehouse = new Entrepot($db);
3569 $child_warehouse->fetch($warehouse_id);
3570 $conf->cache['warehouse'][$warehouse_id] = $child_warehouse;
3571 } else {
3572 $child_warehouse = $conf->cache['warehouse'][$warehouse_id];
3573 }
3574 $detail .= $langs->trans('DetailChildrenFormat', $child_product_label, $child_warehouse->label, price2num($total_qty, 'MS')) . '<br>';
3575 }
3576 }
3577 print $form->textwithtooltip(img_picto('', 'object_stock') . ' ' . $langs->trans('DetailWarehouseNumber'), $detail);
3578 }
3579 print '</td>';
3580 }
3581
3582 // Batch number management
3583 if (isModEnabled('productbatch')) {
3584 if (isset($lines[$i]->detail_batch)) {
3585 print '<!-- Detail of lot -->';
3586 print '<td class="linecolbatch">';
3587 if ($lines[$i]->product_tobatch) {
3588 $detail = '';
3589 foreach ($lines[$i]->detail_batch as $dbatch) { // $dbatch is instance of ExpeditionLineBatch
3590 $detail .= $langs->trans("Batch") . ': ' . $dbatch->batch;
3591 if (!getDolGlobalString('PRODUCT_DISABLE_SELLBY')) {
3592 $detail .= ' - ' . $langs->trans("SellByDate") . ': ' . dol_print_date($dbatch->sellby, "day");
3593 }
3594 if (!getDolGlobalString('PRODUCT_DISABLE_EATBY')) {
3595 $detail .= ' - ' . $langs->trans("EatByDate") . ': ' . dol_print_date($dbatch->eatby, "day");
3596 }
3597 $detail .= ' - ' . $langs->trans("Qty") . ': ' . $dbatch->qty;
3598 $detail .= '<br>';
3599 }
3600 print $form->textwithtooltip(img_picto('', 'object_barcode') . ' ' . $langs->trans("DetailBatchNumber"), $detail);
3601 } else {
3602 print $langs->trans("NA");
3603 }
3604 print '</td>';
3605 } else {
3606 print '<td class="linecolbatch" ></td>';
3607 }
3608 }
3609 }
3610
3611 // Weight
3612 print '<td class="center linecolweight">';
3613 if ($lines[$i]->fk_product_type == Product::TYPE_PRODUCT) {
3614 print $lines[$i]->weight * $lines[$i]->qty_shipped . ' ' . measuringUnitString(0, "weight", $lines[$i]->weight_units);
3615 } else {
3616 print '&nbsp;';
3617 }
3618 print '</td>';
3619
3620 // Volume
3621 print '<td class="center linecolvolume">';
3622 if ($lines[$i]->fk_product_type == Product::TYPE_PRODUCT) {
3623 print $lines[$i]->volume * $lines[$i]->qty_shipped . ' ' . measuringUnitString(0, "volume", $lines[$i]->volume_units);
3624 } else {
3625 print '&nbsp;';
3626 }
3627 print '</td>';
3628
3629 // Size
3630 //print '<td class="center">'.$lines[$i]->volume*$lines[$i]->qty_shipped.' '.measuringUnitString(0, "volume", $lines[$i]->volume_units).'</td>';
3631
3632 if ($action == 'editline' && $lines[$i]->id == $line_id) {
3633 print '<td class="center" colspan="2" valign="middle">';
3634 print '<input type="submit" class="button button-save" id="savelinebutton marginbottomonly" name="save" value="' . $langs->trans("Save") . '"><br>';
3635 print '<input type="submit" class="button button-cancel" id="cancellinebutton" name="cancel" value="' . $langs->trans("Cancel") . '"><br>';
3636 print '</td>';
3637 } elseif ($object->status == Expedition::STATUS_DRAFT) {
3638 $edit_url = $_SERVER["PHP_SELF"] . '?id=' . $object->id . '&action=editline&token=' . newToken() . '&lineid=' . $lines[$i]->id;
3639 if (getDolGlobalInt('PRODUIT_SOUSPRODUITS')) {
3640 $product_id = $lines[$i]->fk_product;
3641 if (!isset($conf->cache['product'][$product_id])) {
3642 $product = new Product($db);
3643 $product->fetch($product_id);
3644 $conf->cache['product'][$product_id] = $product;
3645 } else {
3646 $product = $conf->cache['product'][$product_id];
3647 }
3648
3649 if ($product->hasFatherOrChild(1)) {
3650 $edit_url = dol_buildpath('/expedition/dispatch.php?id=' . $object->id, 1);
3651 }
3652 }
3653
3654 // edit-delete buttons
3655 print '<td class="linecoledit center">';
3656 print '<a class="editfielda reposition" href="' . $edit_url . '">' . img_edit() . '</a>';
3657 print '</td>';
3658 print '<td class="linecoldelete" width="10">';
3659 print '<a class="reposition" href="' . $_SERVER["PHP_SELF"] . '?id=' . $object->id . '&action=deleteline&token=' . newToken() . '&lineid=' . $lines[$i]->id . '">' . img_delete() . '</a>';
3660 print '</td>';
3661
3662 // Display lines extrafields
3663 if (!empty($rowExtrafieldsStart)) {
3664 print $rowExtrafieldsStart;
3665 print $rowExtrafieldsView;
3666 print $rowEnd;
3667 }
3668 }
3669 print "</tr>";
3670
3671 // Display lines extrafields.
3672 // $line is a line of shipment
3673
3674 $colspan = 6;
3675 if ($origin_id > 0) {
3676 $colspan++;
3677 }
3678 if (isModEnabled('productbatch')) {
3679 $colspan++;
3680 }
3681 if (isModEnabled('stock')) {
3682 $colspan++;
3683 }
3684
3685 $line = $lines[$i];
3686 $line->fetch_optionals();
3687
3688 // TODO Show all in same line by setting $display_type = 'line'
3689 if ($action == 'editline' && $line->id == $line_id) {
3690 print $lines[$i]->showOptionals($extrafields, 'edit', array('colspan' => $colspan), !empty($indiceAsked) ? $indiceAsked : '', '', '', 'card');
3691 } else {
3692 print $lines[$i]->showOptionals($extrafields, 'view', array('colspan' => $colspan), !empty($indiceAsked) ? $indiceAsked : '', '', '', 'card');
3693 }
3694 } elseif (empty($reshook) && $lines[$i]->product_type == "9") {
3695 $objectsrc = new OrderLine($db);
3696 $objectsrc->fetch($lines[$i]->origin_line_id);
3697 if ($objectsrc->special_code == SUBTOTALS_SPECIAL_CODE) {
3698 $line = $lines[$i];
3699 require dol_buildpath('/core/tpl/subtotal_expedition_view.tpl.php');
3700 }
3701 }
3702 }
3703 // TODO Show also lines ordered but not delivered
3704 if (empty($num_prod)) {
3705 print '<tr><td colspan="8"><span class="opacitymedium">' . $langs->trans("NoLineGoOnTabToAddSome", $langs->transnoentitiesnoconv("ShipmentDistribution")) . '</span></td></tr>';
3706 }
3707
3708 print '</tbody>';
3709 print "</table>\n";
3710 print '</div>';
3711
3712 $object->fetchObjectLinked($object->id, $object->element);
3713 }
3714
3715 /*
3716 * Boutons actions
3717 */
3718
3719 if (($user->socid == 0) && ($action != 'presend')) {
3720 print '<div class="tabsAction">';
3721
3722 $parameters = array();
3723 $reshook = $hookmanager->executeHooks('addMoreActionsButtons', $parameters, $object, $action); // Note that $action and $object may have been
3724 // modified by hook
3725 if (empty($reshook)) {
3726 if ($object->status == Expedition::STATUS_DRAFT && $num_prod > 0) {
3727 if ((!getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && $user->hasRight('expedition', 'creer'))
3728 || (getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && $user->hasRight('expedition', 'shipping_advance', 'validate'))
3729 ) {
3730 print dolGetButtonAction('', $langs->trans('Validate'), 'default', $_SERVER["PHP_SELF"] . '?action=valid&token=' . newToken() . '&id=' . $object->id, '');
3731 } else {
3732 print dolGetButtonAction($langs->trans('NotAllowed'), $langs->trans('Validate'), 'default', $_SERVER['PHP_SELF'] . '#', '', false);
3733 }
3734 }
3735
3736 // 0=draft, 1=validated/delivered, 2=closed/delivered
3737 if ($object->status == Expedition::STATUS_VALIDATED && !getDolGlobalString('STOCK_CALCULATE_ON_SHIPMENT')) {
3738 if ($user->hasRight('expedition', 'creer')) {
3739 print dolGetButtonAction('', $langs->trans('SetToDraft'), 'default', $_SERVER["PHP_SELF"] . '?action=setdraft&token=' . newToken() . '&id=' . $object->id, '');
3740 }
3741 }
3742 if ($object->status == Expedition::STATUS_CLOSED) {
3743 if ($user->hasRight('expedition', 'creer')) {
3744 print dolGetButtonAction('', $langs->trans('ReOpen'), 'default', $_SERVER["PHP_SELF"] . '?action=reopen&token=' . newToken() . '&id=' . $object->id, '');
3745 }
3746 }
3747
3748 // Send
3749 if (empty($user->socid)) {
3750 if ($object->status > 0) {
3751 if (!getDolGlobalString('MAIN_USE_ADVANCED_PERMS') || $user->hasRight('expedition', 'shipping_advance', 'send')) {
3752 print dolGetButtonAction('', $langs->trans('SendMail'), 'email', $_SERVER["PHP_SELF"] . '?action=presend&token=' . newToken() . '&id=' . $object->id . '&mode=init#formmailbeforetitle', '');
3753 } else {
3754 print dolGetButtonAction('', $langs->trans('SendMail'), 'email', $_SERVER['PHP_SELF'] . '#', '', false);
3755 }
3756 }
3757 }
3758
3759 // This is just to generate a delivery receipt when option to do this is on
3760 //var_dump($object->linkedObjectsIds['delivery']);
3761 if (getDolGlobalInt('MAIN_SUBMODULE_DELIVERY') && ($object->status == Expedition::STATUS_VALIDATED || $object->status == Expedition::STATUS_CLOSED) && $user->hasRight('expedition', 'delivery', 'creer') && empty($object->linkedObjectsIds['delivery'])) {
3762 print dolGetButtonAction('', $langs->trans('CreateDeliveryOrder'), 'default', $_SERVER["PHP_SELF"] . '?action=create_delivery&token=' . newToken() . '&id=' . $object->id, '');
3763 }
3764
3765 // Sign (to set to status "Signed" without using the online signature page)
3766 if ($object->status > Expedition::STATUS_DRAFT) {
3767 if ($object->signed_status != Expedition::$SIGNED_STATUSES['STATUS_SIGNED_ALL']) {
3768 print '<div class="inline-block divButAction"><a class="butAction" href="' . $_SERVER["PHP_SELF"] . '?id=' . $object->id . '&action=sign&token=' . newToken() . '">' . $langs->trans("SignShipping") . '</a></div>';
3769 } else {
3770 print '<div class="inline-block divButAction"><a class="butAction" href="' . $_SERVER["PHP_SELF"] . '?id=' . $object->id . '&action=unsign&token=' . newToken() . '">' . $langs->trans("UnsignShipping") . '</a></div>';
3771 }
3772 }
3773
3774 // Create bill
3775 if (isModEnabled('invoice') && ($object->status == Expedition::STATUS_VALIDATED || $object->status == Expedition::STATUS_CLOSED)) {
3776 if ($user->hasRight('facture', 'creer')) {
3777 if (getDolGlobalString('WORKFLOW_BILL_ON_SHIPMENT') !== '0') {
3778 print dolGetButtonAction('', $langs->trans('CreateBill'), 'default', DOL_URL_ROOT . '/compta/facture/card.php?action=create&origin=' . $object->element . '&originid=' . $object->id . '&socid=' . $object->socid, '');
3779 }
3780 }
3781 }
3782
3783 // Set Billed and Closed
3784 if ($object->status == Expedition::STATUS_VALIDATED) {
3785 if ($user->hasRight('expedition', 'creer') && $object->status > 0) {
3786 if (!$object->billed && getDolGlobalString('WORKFLOW_BILL_ON_SHIPMENT') !== '0') {
3787 print dolGetButtonAction('', $langs->trans('ClassifyBilled'), 'default', $_SERVER["PHP_SELF"] . '?action=classifybilled&token=' . newToken() . '&id=' . $object->id, '');
3788 }
3789 print dolGetButtonAction('', $langs->trans("Close"), 'default', $_SERVER["PHP_SELF"] . '?action=classifyclosed&token=' . newToken() . '&id=' . $object->id, '');
3790 }
3791 }
3792
3793 // Cancel
3794 if ($object->status == Expedition::STATUS_VALIDATED) {
3795 if ($user->hasRight('expedition', 'creer')) {
3796 print dolGetButtonAction('', $langs->trans('Cancel'), 'danger', $_SERVER["PHP_SELF"] . '?action=cancel&token=' . newToken() . '&id=' . $object->id . '&mode=init#formmailbeforetitle', '');
3797 }
3798 }
3799
3800 // Delete
3801 if ($user->hasRight('expedition', 'supprimer')) {
3802 print dolGetButtonAction('', $langs->trans('Delete'), 'delete', $_SERVER["PHP_SELF"] . '?action=delete&token=' . newToken() . '&id=' . $object->id, '');
3803 }
3804 }
3805
3806 print '</div>';
3807 }
3808
3809
3810 /*
3811 * Documents generated
3812 */
3813
3814 if ($action != 'presend' && $action != 'editline') {
3815 print '<div class="fichecenter"><div class="fichehalfleft">';
3816
3817 $objectref = dol_sanitizeFileName($object->ref);
3818 $filedir = $conf->expedition->dir_output . "/sending/" . $objectref;
3819
3820 $urlsource = $_SERVER["PHP_SELF"] . "?id=" . $object->id;
3821
3822 $genallowed = $user->hasRight('expedition', 'lire');
3823 $delallowed = $user->hasRight('expedition', 'creer');
3824
3825 print $formfile->showdocuments('expedition', $objectref, $filedir, $urlsource, $genallowed, $delallowed, $object->model_pdf, 1, 0, 0, 28, 0, '', '', '', $soc->default_lang);
3826
3827
3828 // Show links to link elements
3829 $tmparray = $form->showLinkToObjectBlock($object, array(), array('shipping'), 1);
3830 $linktoelem = $tmparray['linktoelem'];
3831 $htmltoenteralink = $tmparray['htmltoenteralink'];
3832 print $htmltoenteralink;
3833
3834 $somethingshown = $form->showLinkedObjectBlock($object, $linktoelem);
3835
3836 // Show online signature link
3837 $useonlinesignature = getDolGlobalInt('EXPEDITION_ALLOW_ONLINESIGN');
3838
3839 if ($object->statut != Expedition::STATUS_DRAFT && $useonlinesignature) {
3840 print '<br><!-- Link to sign -->';
3841 require_once DOL_DOCUMENT_ROOT . '/core/lib/signature.lib.php';
3842 print showOnlineSignatureUrl('expedition', $object->ref, $object) . '<br>';
3843 }
3844
3845 print '</div><div class="fichehalfright">';
3846
3847
3848 // List of actions on element
3849 include_once DOL_DOCUMENT_ROOT . '/core/class/html.formactions.class.php';
3850 $formactions = new FormActions($db);
3851
3852 //button to go to messaging from the events box
3853 $MAXEVENT = 10;
3854 $morehtmlcenter = dolGetButtonTitle($langs->trans('FullConversation'), '', 'fa fa-comments imgforviewmode', DOL_URL_ROOT . '/expedition/messaging.php?id=' . $object->id);
3855
3856 $somethingshown = $formactions->showactions($object, 'shipping', $socid, 1, '', $MAXEVENT, '', $morehtmlcenter);
3857 print '</div></div>';
3858 }
3859
3860
3861 /*
3862 * Action presend
3863 */
3864
3865 //Select mail models is same action as presend
3866 if (GETPOST('modelselected')) {
3867 $action = 'presend';
3868 }
3869
3870 // Presend form
3871 $modelmail = 'shipping_send';
3872 $defaulttopic = 'SendShippingRef';
3873 $diroutput = $conf->expedition->dir_output . '/sending';
3874 $trackid = 'shi' . $object->id;
3875
3876 include DOL_DOCUMENT_ROOT . '/core/tpl/card_presend.tpl.php';
3877}
3878
3879// End of page
3880llxFooter();
3881$db->close();
$id
Support class for third parties, contacts, members, users or resources.
Definition account.php:47
if(! $sortfield) if(! $sortorder) $object
Definition account.php:100
llxFooter($comment='', $zone='private', $disabledoutputofmessages=0)
Empty footer.
Definition wrapper.php:91
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:73
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 ProductCombination Used to represent the relation between a product and one of its variants.
Class to manage products or services.
const DISABLED_STOCK
Stockable product.
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.
getCountry($searchkey, $withcode='', $dbtouse=null, $outputlangs=null, $entconv=1, $searchlabel='')
Return country label, code or id from an id, code or label.
global $mysoc
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...
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='', $noduplicate=0, $attop=0)
Set event messages in dol_events session object.
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2, $allowothertags=array())
Show picto whatever it's its name (generic function)
img_warning($titlealt='default', $moreatt='', $morecss='pictowarning')
Show warning logo.
img_delete($titlealt='default', $other='class="pictodelete"', $morecss='')
Show delete logo.
GETPOSTINT($paramname, $method=0)
Return the value of a $_GET or $_POST supervariable, converted into integer.
dolBuildUrl($url, $params=[], $addtoken=false)
Return path of url.
dol_get_fiche_head($links=array(), $active='', $title='', $notab=0, $picto='', $pictoisfullpath=0, $morehtmlright='', $morecss='', $limittoshow=0, $moretabssuffix='', $dragdropfile=0, $morecssdiv='')
Show tabs of a record.
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
dolGetButtonTitle($label, $helpText='', $iconClass='fa fa-file', $url='', $id='', $status=1, $params=array())
Function dolGetButtonTitle : this kind of buttons are used in title in list.
dol_get_fiche_end($notab=0)
Return tab footer of a card.
dol_eval($s, $returnvalue=1, $hideerrors=1, $onlysimplestring='1')
Replace eval function to add more security.
img_object($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $allowothertags=array())
Show a picto called object_picto (generic function)
dol_sanitizeFileName($str, $newstr='_', $unaccent=1, $includequotes=0, $allowdash=0)
Clean a string to use it as a file name.
price($amount, $form=0, $outlangs='', $trunc=1, $rounding=-1, $forcerounding=-1, $currency_code='')
Function to format a value into an amount for visual output Function used into PDF and HTML pages.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
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'.
GETPOSTFLOAT($paramname, $rounding='', $option=2)
Return the value of a $_GET or $_POST supervariable, converted into float.
dolGetButtonAction($label, $text='', $actionType='default', $url='', $id='', $userRight=1, $params=array())
Function dolGetButtonAction.
dol_htmlcleanlastbr($stringtodecode)
This function remove all ending and br at end.
dol_concatdesc($text1, $text2, $forxml=false, $invert=false)
Concat 2 descriptions with a new line between them (second operand after first one with appropriate n...
dolPrintHTMLForAttribute($s, $escapeonlyhtmltags=0, $allowothertags=array())
Return a string ready to be output into an HTML attribute (alt, title, data-html, ....
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.
dol_buildpath($path, $type=0, $returnemptyifnotfound=0)
Return path of url or filesystem.
dol_clone($srcobject, $native=2)
Create a clone of instance of object (new instance with same value for each properties) With native =...
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs=null, $encodetooutput=false, $decorate=0)
Output date in a string format according to outputlangs (or langs if not defined).
getDolGlobalBool($key, $default=false)
Return a Dolibarr global constant boolean value.
dol_print_error($db=null, $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
load_fiche_titre($title, $morehtmlright='', $picto='generic', $pictoisfullpath=0, $id='', $morecssontable='', $morehtmlcenter='', $morecssonpicto='widthpictotitle')
Load a title with picto.
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.
isModEnabled($module)
Is Dolibarr module enabled.
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.
getEntity($element, $shared=1, $currentobject=null)
Get list of entity id to use.
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0, $cleanalsojavascript=0)
Returns text escaped for inclusion in HTML alt or title or value tags, or into values of HTML input f...
measuringUnitString($unitid, $measuring_style='', $unitscale=null, $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.