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