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