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