dolibarr 24.0.0-beta
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 if (isset($alreadyQtySetted[$line->fk_product][intval($warehouse_id)])) {
2361 $deliverableQty = min($quantityToBeDelivered, $stock - $alreadyQtySetted[$line->fk_product][intval($warehouse_id)]);
2362 } else {
2363 if (!isset($alreadyQtySetted[$line->fk_product])) {
2364 $alreadyQtySetted[$line->fk_product] = array();
2365 }
2366
2367 $deliverableQty = min($quantityToBeDelivered, $stock);
2368 }
2369
2370 if ($deliverableQty < 0) {
2371 $deliverableQty = 0;
2372 }
2373
2374 $tooltipClass = $tooltipTitle = '';
2375 if (!empty($alreadyQtySetted[$line->fk_product][intval($warehouse_id)])) {
2376 $tooltipClass = ' classfortooltip';
2377 $tooltipTitle = $langs->trans('StockQuantitiesAlreadyAllocatedOnPreviousLines') . ' : ' . $alreadyQtySetted[$line->fk_product][intval($warehouse_id)];
2378 } else {
2379 $alreadyQtySetted[$line->fk_product][intval($warehouse_id)] = 0;
2380 }
2381
2382 $alreadyQtySetted[$line->fk_product][intval($warehouse_id)] = $deliverableQty + $alreadyQtySetted[$line->fk_product][intval($warehouse_id)];
2383
2384 $inputName = 'qtyl' . $indiceAsked . '_' . $subj;
2385 if (GETPOSTISSET($inputName)) {
2386 $deliverableQty = GETPOSTINT($inputName);
2387 }
2388 $qtylValue = $deliverableQty;
2389 if (getDolGlobalBool('SHIPMENT_DONT_PREFILL_QTY', false)) {
2390 $qtylValue = '';
2391 } elseif (is_numeric($qtylValue)) {
2392 $qtylValue = price($qtylValue);
2393 }
2394 print '<input class="qtyl' . $tooltipClass . ' right" title="' . $tooltipTitle . '" name="qtyl' . $indiceAsked . '_' . $subj . '" id="qtyl' . $indiceAsked . '" type="text" size="4" value="' . $qtylValue . '">';
2395 print '<input name="ent1' . $indiceAsked . '_' . $subj . '" type="hidden" value="' . $warehouse_id . '">';
2396 } else {
2397 if (getDolGlobalString('SHIPMENT_GETS_ALL_ORDER_PRODUCTS')) {
2398 print '<input name="qtyl' . $indiceAsked . '_' . $subj . '" id="qtyl' . $indiceAsked . '" type="hidden" value="0">';
2399 }
2400
2401 print $langs->trans("NA");
2402 }
2403 print '</td>';
2404
2405 // Stock
2406 print '<td class="left">';
2407 if ($line->product_type == Product::TYPE_PRODUCT || getDolGlobalString('STOCK_SUPPORTS_SERVICES')) {
2408 if ($product->stockable_product == Product::ENABLED_STOCK || $productChildrenNb > 0) {
2409 print $tmpwarehouseObject->getNomUrl(0) . ' ';
2410 if ($productChildrenNb <= 0) {
2411 print '<!-- Show details of stock -->';
2412 print '(' . $stock . ')';
2413 }
2414 } else {
2415 print img_warning() . ' ' . $langs->trans('StockDisabled');
2416 }
2417 } else {
2418 print '<span class="opacitymedium">(' . $langs->trans("Service") . ')</span>';
2419 }
2420 print '</td>';
2421 $quantityToBeDelivered -= $deliverableQty;
2422 if ($quantityToBeDelivered < 0) {
2423 $quantityToBeDelivered = 0;
2424 }
2425 $subj++;
2426 if (getDolGlobalString('SHIPPING_DISPLAY_STOCK_ENTRY_DATE')) {
2427 print '<td></td>';
2428 } //StockEntrydate
2429 print "</tr>\n";
2430 }
2431 }
2432 // Show subproducts of product (not recommended)
2433 if (getDolGlobalString('PRODUIT_SOUSPRODUITS') && $line->fk_product > 0) {
2434 $product->get_sousproduits_arbo();
2435 $prods_arbo = $product->get_arbo_each_prod($qtyProdCom);
2436 if (count($prods_arbo) > 0) {
2437 foreach ($prods_arbo as $key => $value) {
2438 //print $value[0];
2439 $img = '';
2440 if ($value['stock'] < $value['stock_alert']) {
2441 $img = img_warning($langs->trans("StockTooLow"));
2442 }
2443 print '<tr class"oddeven"><td>';
2444 print "&nbsp; &nbsp; &nbsp; ->
2445 <a href=\"" . DOL_URL_ROOT . "/product/card.php?id=" . $value['id'] . "\">" . $value['fullpath'] . "
2446 </a> (" . $value['nb'] . ")</td><td class=\"center\"> " . $value['nb_total'] . "</td><td>&nbsp;</td><td>&nbsp;</td>
2447 <td class=\"center\">" . $value['stock'] . " " . $img . "</td>";
2448 if (getDolGlobalString('SHIPPING_DISPLAY_STOCK_ENTRY_DATE')) {
2449 print '<td></td>';
2450 } //StockEntrydate
2451 print "</tr>";
2452 }
2453 }
2454 }
2455 } else {
2456 print '<!-- Case warehouse not already known and product need lot -->';
2457 print '<td></td><td></td>';
2458 if (getDolGlobalString('SHIPPING_DISPLAY_STOCK_ENTRY_DATE')) {
2459 print '<td></td>';
2460 } //StockEntrydate
2461 print '</tr>'; // end line and start a new one for lot/serial
2462
2463 $subj = 0;
2464 print '<input name="idl' . $indiceAsked . '" type="hidden" value="' . $line->id . '">';
2465
2466 $tmpwarehouseObject = new Entrepot($db);
2467 $productlotObject = new Productlot($db);
2468
2469 // Define nb of lines suggested for this order line
2470 $nbofsuggested = 0;
2471 foreach ($product->stock_warehouse as $warehouse_id => $stock_warehouse) {
2472 if (($stock_warehouse->real > 0 || !getDolGlobalInt('STOCK_DISALLOW_NEGATIVE_TRANSFER')) && (!empty($stock_warehouse->detail_batch))) {
2473 $nbofsuggested += count($stock_warehouse->detail_batch);
2474 }
2475 }
2476
2477 foreach ($product->stock_warehouse as $warehouse_id => $stock_warehouse) {
2478 $var = $subj % 2;
2479 if (!empty($warehousePicking) && !in_array($warehouse_id, $warehousePicking)) {
2480 // if a warehouse was selected by user, picking is limited to this warehouse and his children
2481 continue;
2482 }
2483
2484 $tmpwarehouseObject->fetch($warehouse_id);
2485 if (($stock_warehouse->real > 0 || !getDolGlobalInt('STOCK_DISALLOW_NEGATIVE_TRANSFER')) && (!empty($stock_warehouse->detail_batch))) {
2486 foreach ($stock_warehouse->detail_batch as $dbatch) {
2487 $batchStock = +$dbatch->qty; // To get a numeric
2488 if (isset($alreadyQtyBatchSetted[$line->fk_product][$dbatch->batch][intval($warehouse_id)])) {
2489 $deliverableQty = min($quantityToBeDelivered, $batchStock - $alreadyQtyBatchSetted[$line->fk_product][$dbatch->batch][intval($warehouse_id)]);
2490 } else {
2491 if (!isset($alreadyQtyBatchSetted[$line->fk_product])) {
2492 $alreadyQtyBatchSetted[$line->fk_product] = array();
2493 }
2494
2495 if (!isset($alreadyQtyBatchSetted[$line->fk_product][$dbatch->batch])) {
2496 $alreadyQtyBatchSetted[$line->fk_product][$dbatch->batch] = array();
2497 }
2498
2499 $deliverableQty = min($quantityToBeDelivered, $batchStock);
2500 }
2501
2502 if ($deliverableQty < 0) {
2503 $deliverableQty = 0;
2504 }
2505
2506 $inputName = 'qtyl' . $indiceAsked . '_' . $subj;
2507 if (GETPOSTISSET($inputName)) {
2508 $deliverableQty = GETPOSTINT($inputName);
2509 }
2510
2511 $tooltipClass = $tooltipTitle = '';
2512 if (!empty($alreadyQtyBatchSetted[$line->fk_product][$dbatch->batch][intval($warehouse_id)])) {
2513 $tooltipClass = ' classfortooltip';
2514 $tooltipTitle = $langs->trans('StockQuantitiesAlreadyAllocatedOnPreviousLines') . ' : ' . $alreadyQtyBatchSetted[$line->fk_product][$dbatch->batch][intval($warehouse_id)];
2515 } else {
2516 $alreadyQtyBatchSetted[$line->fk_product][$dbatch->batch][intval($warehouse_id)] = 0;
2517 }
2518 $alreadyQtyBatchSetted[$line->fk_product][$dbatch->batch][intval($warehouse_id)] = $deliverableQty + $alreadyQtyBatchSetted[$line->fk_product][$dbatch->batch][intval($warehouse_id)];
2519
2520 print '<!-- subj=' . $subj . '/' . $nbofsuggested . ' --><tr ' . ((($subj + 1) == $nbofsuggested) ? 'oddeven' : '') . '><td colspan="3"></td><td class="center">';
2521 $qtylValue = $deliverableQty;
2522 if (getDolGlobalBool('SHIPMENT_DONT_PREFILL_QTY', false)) {
2523 $qtylValue = '';
2524 } elseif (is_numeric($qtylValue)) {
2525 $qtylValue = price($qtylValue);
2526 }
2527 print '<input class="qtyl right ' . $tooltipClass . '" title="' . $tooltipTitle . '" name="' . $inputName . '" id="' . $inputName . '" type="text" size="4" value="' . $qtylValue . '">';
2528 print '</td>';
2529
2530 print '<td class="left">';
2531
2532 print $tmpwarehouseObject->getNomUrl(0) . ' / ';
2533
2534 print '<!-- Show details of lot -->';
2535 print '<input name="batchl' . $indiceAsked . '_' . $subj . '" type="hidden" value="' . $dbatch->id . '">';
2536 print '<input name="entl' . $indiceAsked . '_'.$subj.'" type="hidden" value="' . $tmpwarehouseObject->id . '">';
2537
2538 //print '|'.$line->fk_product.'|'.$dbatch->batch.'|<br>';
2539 print $langs->trans("Batch") . ': ';
2540 $result = $productlotObject->fetch(0, $line->fk_product, $dbatch->batch);
2541 if ($result > 0) {
2542 print $productlotObject->getNomUrl(1);
2543 } else {
2544 print $langs->trans("TableLotIncompleteRunRepairWithParamStandardEqualConfirmed");
2545 }
2546 if (!getDolGlobalString('PRODUCT_DISABLE_SELLBY') && !empty($dbatch->sellby)) {
2547 print ' - ' . $langs->trans("SellByDate") . ': ' . dol_print_date($dbatch->sellby, "day");
2548 }
2549 if (!getDolGlobalString('PRODUCT_DISABLE_EATBY') && !empty($dbatch->eatby)) {
2550 print ' - ' . $langs->trans("EatByDate") . ': ' . dol_print_date($dbatch->eatby, "day");
2551 }
2552 print ' (' . $dbatch->qty . ')';
2553 $quantityToBeDelivered -= $deliverableQty;
2554 if ($quantityToBeDelivered < 0) {
2555 $quantityToBeDelivered = 0;
2556 }
2557 //dol_syslog('deliverableQty = '.$deliverableQty.' batchStock = '.$batchStock);
2558 $subj++;
2559 print '</td>';
2560 if (getDolGlobalString('SHIPPING_DISPLAY_STOCK_ENTRY_DATE')) {
2561 print '<td class="left">' . dol_print_date($dbatch->context['stock_entry_date'], 'day') . '</td>';
2562 }
2563 print '</tr>';
2564 }
2565 }
2566 }
2567 }
2568 if ($subj == 0) { // Line not shown yet, we show it
2569 $warehouse_selected_id = GETPOSTINT('entrepot_id');
2570
2571 print '<!-- line not shown yet, we show it -->';
2572 print '<tr class="oddeven"><td colspan="3"></td><td class="center">';
2573
2574 if ($line->product_type == Product::TYPE_PRODUCT || getDolGlobalString('STOCK_SUPPORTS_SERVICES')) {
2575 $disabled = '';
2576 $alt = '';
2577 if (isModEnabled('productbatch') && $product->hasbatch()) {
2578 $disabled = 'disabled="disabled"';
2579 $alt = 'Product need serial or batch number';
2580 }
2581 if ($warehouse_selected_id <= 0) { // We did not force a given warehouse, so we won't have no warehouse to change qty.
2582 $disabled = 'disabled="disabled"';
2583 }
2584 // finally we overwrite the input with the product status stockable_product if it's disabled
2585 if ($product->stockable_product == Product::ENABLED_STOCK) {
2586 $disabled = '';
2587 }
2588 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).'"' : '').'> ';
2589 if (empty($disabled) && (!getDolGlobalInt('STOCK_DISALLOW_NEGATIVE_TRANSFER') || $product->stockable_product == Product::DISABLED_STOCK)) {
2590 print '<input name="ent1' . $indiceAsked . '_' . $subj . '" type="hidden" value="' . $warehouse_selected_id . '">';
2591 }
2592 } elseif ($line->product_type == Product::TYPE_SERVICE && getDolGlobalString('SHIPMENT_SUPPORTS_SERVICES')) {
2593 $disabled = '';
2594 if (isModEnabled('productbatch') && $product->hasbatch()) {
2595 $disabled = 'disabled="disabled"';
2596 }
2597 if ($warehouse_selected_id <= 0) { // We did not force a given warehouse, so we won't have no warehouse to change qty.
2598 $disabled = 'disabled="disabled"';
2599 }
2600 print '<input class="qtyl right" name="qtyl'.$indiceAsked.'_'.$subj.'" id="qtyl'.$indiceAsked.'_'.$subj.'" type="text" size="4" value="'.$quantityToBeDelivered.'"'.($disabled ? ' '.$disabled : '').'> ';
2601 if (empty($disabled) && !getDolGlobalInt('STOCK_DISALLOW_NEGATIVE_TRANSFER')) {
2602 print '<input name="ent1' . $indiceAsked . '_' . $subj . '" type="hidden" value="' . $warehouse_selected_id . '">';
2603 }
2604 } else {
2605 print $langs->trans("NA");
2606 }
2607 print '</td>';
2608
2609 print '<td class="left">';
2610 if ($line->product_type == Product::TYPE_PRODUCT || getDolGlobalString('STOCK_SUPPORTS_SERVICES')) {
2611 // product may use stock management
2612 if (($warehouse_selected_id > 0 && $product->stockable_product == Product::ENABLED_STOCK)) {
2613 $warehouseObject = new Entrepot($db);
2614 $warehouseObject->fetch($warehouse_selected_id);
2615 print img_warning() . ' ' . $langs->trans("NoProductToShipFoundIntoStock", $warehouseObject->label);
2616 } else {
2617 if ($line->fk_product) {
2618 if ($product->stockable_product != Product::ENABLED_STOCK) {
2619 print img_warning() . ' ' . $langs->trans('StockDisabled');
2620 } else {
2621 print img_warning() . ' ' . $langs->trans('StockTooLow');
2622 }
2623 } else {
2624 print '';
2625 }
2626 }
2627 } else {
2628 print '<span class="opacitymedium">(' . $langs->trans("Service") . ')</span>';
2629 }
2630 print '</td>';
2631 if (getDolGlobalString('SHIPPING_DISPLAY_STOCK_ENTRY_DATE')) {
2632 print '<td></td>';
2633 } //StockEntrydate
2634 print '</tr>';
2635 }
2636 }
2637 } elseif (empty($reshook) && $line->special_code == SUBTOTALS_SPECIAL_CODE && !in_array($line->id, $title_lines_to_disable)) {
2638 require dol_buildpath('/core/tpl/subtotalline_select.tpl.php');
2639 }
2640
2641 $indiceAsked++;
2642 }
2643
2644 print "</table>";
2645 print '</div>';
2646
2647 print '<br>';
2648
2649 print $form->buttonsSaveCancel("Create");
2650
2651 print '</form>';
2652
2653 print '<br>';
2654 } else {
2656 }
2657 }
2658} elseif ($object->id > 0) {
2659 '@phan-var-force Expedition $object'; // Need to force it (type overridden earlier)
2660
2661 // Edit and view mode
2662
2663 $lines = $object->lines;
2664
2665 $num_prod = count($lines);
2666
2667 if (!empty($object->origin) && $object->origin_id > 0) {
2668 $typeobject = $object->origin;
2669 $origin = (string) $object->origin; // Cast to string because origin is type hinted as object too.
2670 $origin_id = $object->origin_id;
2671
2672 $object->fetch_origin(); // Load property $object->origin_object (old $object->commande, $object->propal, ...)
2673 }
2674
2675 $soc = new Societe($db);
2676 $soc->fetch($object->socid);
2677
2678 $res = $object->fetch_optionals();
2679
2680 $head = shipping_prepare_head($object);
2681 print dol_get_fiche_head($head, 'shipping', $langs->trans("Shipment"), -1, $object->picto);
2682
2683 $formconfirm = '';
2684
2685 // Confirm deletion
2686 if ($action == 'delete') {
2687 $formquestion = array();
2688 if ($object->status == Expedition::STATUS_CLOSED && getDolGlobalString('STOCK_CALCULATE_ON_SHIPMENT_CLOSE')) {
2689 $formquestion = array(
2690 array(
2691 'label' => $langs->trans('ShipmentIncrementStockOnDelete'),
2692 'name' => 'alsoUpdateStock',
2693 'type' => 'checkbox',
2694 'value' => 0
2695 ),
2696 );
2697 }
2698 $formconfirm = $form->formconfirm(
2699 $_SERVER['PHP_SELF'] . '?id=' . $object->id,
2700 $langs->trans('DeleteSending'),
2701 $langs->trans("ConfirmDeleteSending", $object->ref),
2702 'confirm_delete',
2703 $formquestion,
2704 0,
2705 1
2706 );
2707 }
2708
2709 // Confirm delete of subtotal line
2710 if ($action == 'ask_subtotal_deleteline') {
2711 $lineid = GETPOSTINT('lineid');
2712 $langs->load("subtotals");
2713 $title = "DeleteSubtotalLine";
2714 $question = "ConfirmDeleteSubtotalLine";
2715 if (GETPOST('type') == 'title') {
2716 $formconfirm = array(array('type' => 'checkbox', 'name' => 'deletecorrespondingsubtotalline', 'label' => $langs->trans("DeleteCorrespondingSubtotalLine"), 'value' => 0));
2717 $title = "DeleteTitleLine";
2718 $question = "ConfirmDeleteTitleLine";
2719 }
2720 $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"] . '?id=' . $object->id . '&lineid=' . $lineid, $langs->trans($title), $langs->trans($question), 'confirm_delete_subtotalline', $formconfirm, 'no', 1);
2721 }
2722
2723 // Confirm validation
2724 if ($action == 'valid') {
2725 $objectref = substr($object->ref, 1, 4);
2726 if ($objectref == 'PROV') {
2727 $numref = $object->getNextNumRef($soc);
2728 } else {
2729 $numref = (string) $object->ref;
2730 }
2731
2732 $text = $langs->trans("ConfirmValidateSending", $numref);
2733 if (getDolGlobalString('STOCK_CALCULATE_ON_SHIPMENT')) {
2734 $text .= '<br>' . img_picto('', 'movement', 'class="pictofixedwidth"') . $langs->trans("StockMovementWillBeRecorded") . '.';
2735 } elseif (getDolGlobalString('STOCK_CALCULATE_ON_SHIPMENT_CLOSE')) {
2736 $text .= '<br>' . img_picto('', 'movement', 'class="pictofixedwidth"') . $langs->trans("StockMovementNotYetRecorded") . '.';
2737 }
2738
2739 if (isModEnabled('notification')) {
2740 require_once DOL_DOCUMENT_ROOT . '/core/class/notify.class.php';
2741 $notify = new Notify($db);
2742 $text .= '<br>';
2743 $text .= $notify->confirmMessage('SHIPPING_VALIDATE', $object->socid, $object);
2744 }
2745
2746 $formconfirm = $form->formconfirm($_SERVER['PHP_SELF'].'?id='.$object->id, $langs->trans('ValidateSending'), $text, 'confirm_valid', '', 0, 1, 260);
2747 }
2748
2749 // Confirm cancellation
2750 if ($action == 'cancel') {
2751 $formconfirm = $form->formconfirm($_SERVER['PHP_SELF'] . '?id=' . $object->id, $langs->trans('CancelSending'), $langs->trans("ConfirmCancelSending", $object->ref), 'confirm_cancel', '', 0, 1);
2752 }
2753
2754 // Confirm sign
2755 if ($action == 'sign') {
2756 $text = $langs->trans('ConfirmSignShipping');
2757 if (isModEnabled('notification')) {
2758 require_once DOL_DOCUMENT_ROOT . '/core/class/notify.class.php';
2759 $notify = new Notify($db);
2760 $text .= '<br>';
2761 $text .= $notify->confirmMessage('SHIPPING_MODIFY', $object->socid, $object);
2762 }
2763 $formquestion = [];
2764 $formquestion[] = [
2765 'type' => 'select',
2766 'name' => 'signed_status',
2767 'select_show_empty' => 0,
2768 'label' => '<span class="fieldrequired">' . $langs->trans('SignStatus') . '</span>',
2769 'values' => $object->getSignedStatusLocalisedArray()
2770 ];
2771 $formconfirm = $form->formconfirm(dolBuildUrl($_SERVER["PHP_SELF"], ['id' => $object->id]), $langs->trans('SignShipping'), $text, 'confirm_sign', $formquestion, 0, 1);
2772 }
2773
2774 // Confirm unsign
2775 if ($action == 'unsign') {
2776 $text = $langs->trans('ConfirmUnsignShipping');
2777 if (isModEnabled('notification')) {
2778 require_once DOL_DOCUMENT_ROOT . '/core/class/notify.class.php';
2779 $notify = new Notify($db);
2780 $text .= '<br>';
2781 $text .= $notify->confirmMessage('SHIPPING_MODIFY', $object->socid, $object);
2782 }
2783 $formconfirm = $form->formconfirm(dolBuildUrl($_SERVER["PHP_SELF"], ['id' => $object->id]), $langs->trans('UnsignShipping'), $text, 'confirm_unsign', '', 0, 1);
2784 }
2785
2786 // Call Hook formConfirm
2787 $parameters = array('formConfirm' => $formconfirm);
2788 $reshook = $hookmanager->executeHooks('formConfirm', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
2789 if (empty($reshook)) {
2790 $formconfirm .= $hookmanager->resPrint;
2791 } elseif ($reshook > 0) {
2792 $formconfirm = $hookmanager->resPrint;
2793 }
2794
2795 // Print form confirm
2796 print $formconfirm;
2797
2798 // Calculate totalWeight and totalVolume for all products
2799 // by adding weight and volume of each product line.
2800 $tmparray = $object->getTotalWeightVolume();
2801 $totalWeight = $tmparray['weight'];
2802 $totalVolume = $tmparray['volume'];
2803
2804 if (!empty($typeobject) && $typeobject === 'commande' && is_object($object->origin_object) && $object->origin_object->id && isModEnabled('order')) {
2805 $objectsrc = new Commande($db);
2806 $objectsrc->fetch($object->origin_object->id);
2807 }
2808 if (!empty($typeobject) && $typeobject === 'propal' && is_object($object->origin_object) && $object->origin_object->id && isModEnabled("propal")) {
2809 $objectsrc = new Propal($db);
2810 $objectsrc->fetch($object->origin_object->id);
2811 }
2812
2813 // Shipment card
2814 $linkback = '<a href="' . DOL_URL_ROOT . '/expedition/list.php?restore_lastsearch_values=1' . (!empty($socid) ? '&socid=' . $socid : '') . '">' . $langs->trans("BackToList") . '</a>';
2815 $morehtmlref = '<div class="refidno">';
2816 // Ref customer shipment
2817 $morehtmlref .= $form->editfieldkey("RefCustomer", 'ref_customer', $object->ref_customer, $object, $user->hasRight('expedition', 'creer'), 'string', '', 0, 1);
2818 $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);
2819
2820 // Thirdparty
2821 $morehtmlref .= '<br>' . $object->thirdparty->getNomUrl(1);
2822
2823 // Project
2824 if ($origin && $origin_id > 0) {
2825 if (isModEnabled('project')) {
2826 $langs->load("projects");
2827 $morehtmlref .= '<br>';
2828 if (0) { // @phpstan-ignore-line Do not change on shipment
2829 $morehtmlref .= img_picto($langs->trans("Project"), 'project', 'class="pictofixedwidth"');
2830 if ($action != 'classify') {
2831 $morehtmlref .= '<a class="editfielda" href="'.$_SERVER['PHP_SELF'].'?action=classify&token='.newToken().'&id='.$object->id.'">'.img_edit($langs->transnoentitiesnoconv('SetProject')).'</a> ';
2832 }
2833 $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');
2834 } else {
2835 if (!empty($objectsrc) && !empty($objectsrc->fk_project)) {
2836 $proj = new Project($db);
2837 $proj->fetch($objectsrc->fk_project);
2838 $morehtmlref .= $proj->getNomUrl(1);
2839 if ($proj->title) {
2840 $morehtmlref .= '<span class="opacitymedium"> - '.dol_escape_htmltag($proj->title).'</span>';
2841 }
2842 }
2843 }
2844 }
2845 } elseif (!$origin && getDolGlobalString('SHIPMENT_STANDALONE')) {
2846 // Project
2847 if (isModEnabled('project')) {
2848 $langs->load("projects");
2849 $morehtmlref .= '<br>';
2850 if ($permissiontoadd) {
2851 $morehtmlref .= img_picto($langs->trans("Project"), 'project', 'class="pictofixedwidth"');
2852 if ($action != 'classify') {
2853 $morehtmlref .= '<a class="editfielda" href="' . $_SERVER['PHP_SELF'] . '?action=classify&token=' . newToken() . '&id=' . $object->id . '">' . img_edit($langs->transnoentitiesnoconv('SetProject')) . '</a> ';
2854 }
2855 $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');
2856 } else {
2857 if (!empty($object->fk_project)) {
2858 $proj = new Project($db);
2859 $proj->fetch($object->fk_project);
2860 $morehtmlref .= $proj->getNomUrl(1);
2861 if ($proj->title) {
2862 $morehtmlref .= '<span class="opacitymedium"> - ' . dol_escape_htmltag($proj->title) . '</span>';
2863 }
2864 }
2865 }
2866 }
2867 }
2868
2869 $morehtmlref .= '</div>';
2870 dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref);
2871
2872 print '<div class="fichecenter">';
2873 print '<div class="fichehalfleft">';
2874 print '<div class="underbanner clearboth"></div>';
2875
2876 print '<table class="border tableforfield centpercent">';
2877
2878 // Linked documents
2879 if (!empty($typeobject) && $typeobject == 'commande' && $object->origin_object->id && isModEnabled('order')) {
2880 print '<tr><td>';
2881 print $langs->trans("RefOrder") . '</td>';
2882 print '<td>';
2883 print $objectsrc->getNomUrl(1, 'commande');
2884 print "</td>\n";
2885 print '</tr>';
2886 }
2887 if (!empty($typeobject) && $typeobject == 'propal' && $object->origin_object->id && isModEnabled("propal")) {
2888 print '<tr><td>';
2889 print $langs->trans("RefProposal") . '</td>';
2890 print '<td>';
2891 print $objectsrc->getNomUrl(1, 'expedition');
2892 print "</td>\n";
2893 print '</tr>';
2894 }
2895
2896 // Date creation
2897 print '<tr><td class="titlefieldmiddle">' . $langs->trans("DateCreation") . '</td>';
2898 print '<td>' . dol_print_date($object->date_creation, "dayhour") . "</td>\n";
2899 print '</tr>';
2900
2901 // Delivery date planned
2902 print '<tr><td height="10">';
2903 print '<table class="nobordernopadding centpercent"><tr><td>';
2904 print $langs->trans('DateDeliveryPlanned');
2905 print '</td>';
2906 if ($action != 'editdate_livraison') {
2907 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>';
2908 }
2909 print '</tr></table>';
2910 print '</td><td>';
2911 if ($action == 'editdate_livraison') {
2912 print '<form name="setdate_livraison" action="' . $_SERVER["PHP_SELF"] . '?id=' . $object->id . '" method="post">';
2913 print '<input type="hidden" name="token" value="' . newToken() . '">';
2914 print '<input type="hidden" name="action" value="setdate_livraison">';
2915 print $form->selectDate($object->date_delivery ? $object->date_delivery : -1, 'liv_', 1, 1, 0, "setdate_livraison", 1, 0);
2916 print '<input type="submit" class="button button-edit smallpaddingimp" value="' . $langs->trans('Modify') . '">';
2917 print '</form>';
2918 } else {
2919 print $object->date_delivery ? dol_print_date($object->date_delivery, 'dayhour') : '&nbsp;';
2920 }
2921 print '</td>';
2922 print '</tr>';
2923
2924 // Delivery sending date
2925 print '<tr><td height="10">';
2926 print '<table class="nobordernopadding centpercent"><tr><td>';
2927 print $langs->trans('DateShipping');
2928 print '</td>';
2929 if ($action != 'editdate_shipping') {
2930 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>';
2931 }
2932 print '</tr></table>';
2933 print '</td><td>';
2934 if ($action == 'editdate_shipping') {
2935 print '<form name="setdate_shipping" action="' . $_SERVER["PHP_SELF"] . '?id=' . $object->id . '" method="post">';
2936 print '<input type="hidden" name="token" value="' . newToken() . '">';
2937 print '<input type="hidden" name="action" value="setdate_shipping">';
2938 print $form->selectDate($object->date_shipping ? $object->date_shipping : -1, 'ship_', 1, 1, 0, "setdate_shipping", 1, 0);
2939 print '<input type="submit" class="button button-edit smallpaddingimp" value="' . $langs->trans('Modify') . '">';
2940 print '</form>';
2941 } else {
2942 print $object->date_shipping ? dol_print_date($object->date_shipping, 'dayhour') : '&nbsp;';
2943 }
2944 print '</td>';
2945 print '</tr>';
2946
2947 // Weight
2948 print '<tr><td>';
2949 print $form->editfieldkey("Weight", 'trueWeight', $object->trueWeight, $object, $user->hasRight('expedition', 'creer'));
2950 print '</td><td>';
2951
2952 if ($action == 'edittrueWeight') {
2953 print '<form name="settrueweight" action="' . $_SERVER["PHP_SELF"] . '" method="post">';
2954 print '<input name="action" value="settrueWeight" type="hidden">';
2955 print '<input name="id" value="' . $object->id . '" type="hidden">';
2956 print '<input type="hidden" name="token" value="' . newToken() . '">';
2957 print '<input id="trueWeight" name="trueWeight" value="' . $object->trueWeight . '" type="text" class="width50 valignmiddle">';
2958 print $formproduct->selectMeasuringUnits("weight_units", "weight", (string) $object->weight_units, 0, 2, 'maxwidth125 valignmiddle');
2959 print ' <input class="button smallpaddingimp valignmiddle" name="modify" value="' . $langs->trans("Modify") . '" type="submit">';
2960 print ' <input class="button button-cancel smallpaddingimp valignmiddle" name="cancel" value="' . $langs->trans("Cancel") . '" type="submit">';
2961 print '</form>';
2962 } else {
2963 print $object->trueWeight;
2964 print ($object->trueWeight && $object->weight_units != '') ? ' ' . measuringUnitString(0, "weight", $object->weight_units) : '';
2965 }
2966
2967 // Calculated
2968 if ($totalWeight > 0) {
2969 if (!empty($object->trueWeight)) {
2970 print ' (' . $langs->trans("SumOfProductWeights") . ': ';
2971 }
2972 print showDimensionInBestUnit($totalWeight, 0, "weight", $langs, getDolGlobalInt('MAIN_WEIGHT_DEFAULT_ROUND', -1), getDolGlobalString('MAIN_WEIGHT_DEFAULT_UNIT', 'no'));
2973 if (!empty($object->trueWeight)) {
2974 print ')';
2975 }
2976 }
2977 print '</td></tr>';
2978
2979 // Width
2980 print '<tr><td>' . $form->editfieldkey("Width", 'trueWidth', $object->trueWidth, $object, $user->hasRight('expedition', 'creer')) . '</td><td>';
2981 print $form->editfieldval("Width", 'trueWidth', $object->trueWidth, $object, $user->hasRight('expedition', 'creer'));
2982 print ($object->trueWidth && $object->width_units != '') ? ' ' . measuringUnitString(0, "size", $object->width_units) : '';
2983 print '</td></tr>';
2984
2985 // Height
2986 print '<tr><td>' . $form->editfieldkey("Height", 'trueHeight', $object->trueHeight, $object, $user->hasRight('expedition', 'creer')) . '</td><td>';
2987 if ($action == 'edittrueHeight') {
2988 print '<form name="settrueHeight" action="' . $_SERVER["PHP_SELF"] . '" method="post">';
2989 print '<input name="action" value="settrueHeight" type="hidden">';
2990 print '<input name="id" value="' . $object->id . '" type="hidden">';
2991 print '<input type="hidden" name="token" value="' . newToken() . '">';
2992 print '<input id="trueHeight" name="trueHeight" value="' . $object->trueHeight . '" type="text" class="width50">';
2993 print $formproduct->selectMeasuringUnits("size_units", "size", $object->size_units, 0, 2);
2994 print ' <input class="button smallpaddingimp" name="modify" value="' . $langs->trans("Modify") . '" type="submit">';
2995 print ' <input class="button button-cancel smallpaddingimp" name="cancel" value="' . $langs->trans("Cancel") . '" type="submit">';
2996 print '</form>';
2997 } else {
2998 print $object->trueHeight;
2999 print ($object->trueHeight && $object->height_units != '') ? ' ' . measuringUnitString(0, "size", $object->height_units) : '';
3000 }
3001
3002 print '</td></tr>';
3003
3004 // Depth
3005 print '<tr><td>' . $form->editfieldkey("Depth", 'trueDepth', $object->trueDepth, $object, $user->hasRight('expedition', 'creer')) . '</td><td>';
3006 print $form->editfieldval("Depth", 'trueDepth', $object->trueDepth, $object, $user->hasRight('expedition', 'creer'));
3007 print ($object->trueDepth && $object->depth_units != '') ? ' ' . measuringUnitString(0, "size", $object->depth_units) : '';
3008 print '</td></tr>';
3009
3010 // Volume
3011 print '<tr><td>';
3012 print $langs->trans("Volume");
3013 print '</td>';
3014 print '<td>';
3015 $calculatedVolume = 0;
3016 $volumeUnit = 0;
3017 if ($object->trueWidth && $object->trueHeight && $object->trueDepth) {
3018 $calculatedVolume = ($object->trueWidth * $object->trueHeight * $object->trueDepth);
3019 $volumeUnit = $object->size_units * 3;
3020 }
3021 // If sending volume not defined we use sum of products
3022 if ($calculatedVolume > 0) {
3023 if ($volumeUnit < 50) {
3024 print showDimensionInBestUnit($calculatedVolume, $volumeUnit, "volume", $langs, getDolGlobalInt('MAIN_VOLUME_DEFAULT_ROUND', -1), getDolGlobalString('MAIN_VOLUME_DEFAULT_UNIT', 'no'));
3025 } else {
3026 print $calculatedVolume . ' ' . measuringUnitString(0, "volume", $volumeUnit);
3027 }
3028 }
3029 if ($totalVolume > 0) {
3030 if ($calculatedVolume) {
3031 print ' (' . $langs->trans("SumOfProductVolumes") . ': ';
3032 }
3033 print showDimensionInBestUnit($totalVolume, 0, "volume", $langs, getDolGlobalInt('MAIN_VOLUME_DEFAULT_ROUND', -1), getDolGlobalString('MAIN_VOLUME_DEFAULT_UNIT', 'no'));
3034 //if (empty($calculatedVolume)) print ' ('.$langs->trans("Calculated").')';
3035 if ($calculatedVolume) {
3036 print ')';
3037 }
3038 }
3039 print "</td>\n";
3040 print '</tr>';
3041
3042 // Other attributes
3043 //$cols = 2;
3044 include DOL_DOCUMENT_ROOT . '/core/tpl/extrafields_view.tpl.php';
3045
3046 print '</table>';
3047
3048 print '</div>';
3049 print '<div class="fichehalfright">';
3050 print '<div class="underbanner clearboth"></div>';
3051
3052 print '<table class="border centpercent tableforfield">';
3053
3054 // Sending method
3055 print '<tr><td>';
3056 print '<table class="nobordernopadding centpercent"><tr><td>';
3057 print $langs->trans('SendingMethod');
3058 print '</td>';
3059
3060 if ($action != 'editshipping_method_id' && $permissiontoadd) {
3061 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>';
3062 }
3063 print '</tr></table>';
3064 print '</td><td>';
3065 if ($action == 'editshipping_method_id') {
3066 print '<form name="setshipping_method_id" action="' . $_SERVER["PHP_SELF"] . '?id=' . $object->id . '" method="post">';
3067 print '<input type="hidden" name="token" value="' . newToken() . '">';
3068 print '<input type="hidden" name="action" value="setshipping_method_id">';
3069 $object->fetch_delivery_methods();
3070 print $form->selectarray("shipping_method_id", $object->meths, $object->shipping_method_id, 1, 0, 0, "", 1);
3071 if ($user->admin) {
3072 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
3073 }
3074 print '<input type="submit" class="button button-edit smallpaddingimp" value="' . $langs->trans('Modify') . '">';
3075 print '</form>';
3076 } else {
3077 if ($object->shipping_method_id > 0) {
3078 // Get code using getLabelFromKey
3079 $code = $langs->getLabelFromKey($db, (string) $object->shipping_method_id, 'c_shipment_mode', 'rowid', 'code');
3080 print $langs->trans("SendingMethod" . strtoupper($code));
3081 }
3082 }
3083 print '</td>';
3084 print '</tr>';
3085
3086 // Tracking Number
3087 print '<tr><td class="titlefieldmiddle">' . $form->editfieldkey("TrackingNumber", 'tracking_number', $object->tracking_number, $object, $user->hasRight('expedition', 'creer')) . '</td><td>';
3088 print $form->editfieldval("TrackingNumber", 'tracking_number', $object->tracking_url, $object, $user->hasRight('expedition', 'creer'), 'safehtmlstring', $object->tracking_number);
3089 print '</td></tr>';
3090
3091 // Incoterms
3092 if (isModEnabled('incoterm')) {
3093 print '<tr><td>';
3094 print '<table class="nobordernopadding centpercent"><tr><td>';
3095 print $langs->trans('IncotermLabel');
3096 print '<td><td class="right">';
3097 if ($permissiontoadd) {
3098 print '<a class="editfielda" href="' . DOL_URL_ROOT . '/expedition/card.php?id=' . $object->id . '&action=editincoterm&token=' . newToken() . '">' . img_edit() . '</a>';
3099 } else {
3100 print '&nbsp;';
3101 }
3102 print '</td></tr></table>';
3103 print '</td>';
3104 print '<td>';
3105 if ($action != 'editincoterm') {
3106 print $form->textwithpicto($object->display_incoterms(), $object->label_incoterms, 1);
3107 } else {
3108 print $form->select_incoterms((!empty($object->fk_incoterms) ? $object->fk_incoterms : ''), (!empty($object->location_incoterms) ? $object->location_incoterms : ''), $_SERVER['PHP_SELF'] . '?id=' . $object->id);
3109 }
3110 print '</td></tr>';
3111 }
3112
3113 // Other attributes
3114 $parameters = array();
3115 $reshook = $hookmanager->executeHooks('formObjectOptions', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
3116 print $hookmanager->resPrint;
3117
3118 print "</table>";
3119
3120 print '</div>';
3121 print '</div>';
3122
3123 print '<div class="clearboth"></div>';
3124
3125 print dol_get_fiche_end();
3126
3127
3128 /*
3129 * Lines of simple shipment
3130 */
3131 if (!$origin && getDolGlobalString('SHIPMENT_STANDALONE')) {
3132 if (!empty($object->table_element_line)) {
3133 // Show object lines
3134 $result = $object->getLinesArray();
3135
3136 print ' <form name="addproduct" id="addproduct" action="'.$_SERVER["PHP_SELF"].'?id='.$object->id.(($action != 'editline') ? '' : '#line_'.GETPOSTINT('lineid')).'" method="POST">
3137 <input type="hidden" name="token" value="' . newToken().'">
3138 <input type="hidden" name="action" value="' . (($action != 'editline') ? 'addline' : 'updateline').'">
3139 <input type="hidden" name="mode" value="">
3140 <input type="hidden" name="page_y" value="">
3141 <input type="hidden" name="id" value="' . $object->id.'">
3142 ';
3143
3144 if (!empty($conf->use_javascript_ajax) && $object->status == 0) {
3145 include DOL_DOCUMENT_ROOT.'/core/tpl/ajaxrow.tpl.php';
3146 }
3147
3148 print '<div class="div-table-responsive-no-min">';
3149 if (!empty($object->lines) || ($object->status == $object::STATUS_DRAFT && $permissiontoadd && $action != 'selectlines' && $action != 'editline')) {
3150 print '<table id="tablelines" class="noborder noshadow" width="100%">';
3151 }
3152
3153 if (!empty($object->lines)) {
3154 $object->printObjectLines($action, $mysoc, null, GETPOSTINT('lineid'), 1, '/expedition/tpl');
3155 }
3156
3157 // Form to add new line
3158 if ($object->status == 0 && $permissiontoadd && $action != 'selectlines') {
3159 if ($action != 'editline') {
3160 // Add products/services form
3161
3162 $parameters = array();
3163 $reshook = $hookmanager->executeHooks('formAddObjectLine', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
3164 if ($reshook < 0) {
3165 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
3166 }
3167 if (empty($reshook)) {
3168 $object->formAddObjectLine(1, $mysoc, $soc);
3169 }
3170 }
3171 }
3172
3173 if (!empty($object->lines) || ($object->status == $object::STATUS_DRAFT && $permissiontoadd && $action != 'selectlines' && $action != 'editline')) {
3174 print '</table>';
3175 }
3176 print '</div>';
3177
3178 print "</form>\n";
3179 }
3180 }
3181
3182 // Lines of products of origin
3183 if (!empty($object->origin) && $object->origin_id > 0) {
3184 if ($action == 'editline') {
3185 print ' <form name="updateline" id="updateline" action="' . $_SERVER["PHP_SELF"] . '?id=' . $object->id . '&amp;lineid=' . $line_id . '" method="POST">
3186 <input type="hidden" name="token" value="' . newToken() . '">
3187 <input type="hidden" name="action" value="updateline">
3188 <input type="hidden" name="mode" value="">
3189 <input type="hidden" name="id" value="' . $object->id . '">
3190 ';
3191 }
3192 print '<br>';
3193 if (!empty($conf->use_javascript_ajax) && $object->status == Expedition::STATUS_DRAFT && $usercancreate && $num_prod > 1) {
3194 include DOL_DOCUMENT_ROOT . '/core/tpl/ajaxrow.tpl.php';
3195 }
3196
3197 print '<div class="div-table-responsive-no-min">';
3198 print '<table class="noborder centpercent" id="tablelines" >';
3199 print '<thead>';
3200 print '<tr class="liste_titre">';
3201 // Adds a line numbering column
3202 if (getDolGlobalString('MAIN_VIEW_LINE_NUMBER')) {
3203 print '<td width="5" class="center linecolnum">&nbsp;</td>';
3204 }
3205 // Product/Service
3206 print '<td class="linecoldescription" >' . $langs->trans("Products") . '</td>';
3207 // Qty
3208 print '<td class="center linecolqty">' . $langs->trans("QtyOrdered") . '</td>';
3209 if ($origin_id > 0) {
3210 print '<td class="center linecolqtyinothershipments">' . $langs->trans("QtyInOtherShipments") . '</td>';
3211 }
3212 if ($action == 'editline') {
3213 $editColspan = 3;
3214 if (!isModEnabled('stock')) {
3215 $editColspan--;
3216 }
3217 if (!isModEnabled('productbatch')) {
3218 $editColspan--;
3219 }
3220 print '<td class="center linecoleditlineotherinfo" colspan="' . $editColspan . '">';
3221 if ($object->status <= 1) {
3222 print $langs->trans("QtyToShip");
3223 } else {
3224 print $langs->trans("QtyShipped");
3225 }
3226 if (isModEnabled('stock')) {
3227 print ' - ' . $langs->trans("WarehouseSource");
3228 }
3229 if (isModEnabled('productbatch')) {
3230 print ' - ' . $langs->trans("Batch");
3231 }
3232 print '</td>';
3233 } else {
3234 if ($object->status <= 1) {
3235 print '<td class="center linecolqtytoship">' . $langs->trans("QtyToShip") . '</td>';
3236 } else {
3237 print '<td class="center linecolqtyshipped">' . $langs->trans("QtyShipped") . '</td>';
3238 }
3239 if (isModEnabled('stock')) {
3240 print '<td class="left linecolwarehousesource">' . $langs->trans("WarehouseSource") . '</td>';
3241 }
3242
3243 if (isModEnabled('productbatch')) {
3244 print '<td class="left linecolbatch">' . $langs->trans("Batch") . '</td>';
3245 }
3246 }
3247 print '<td class="center linecolweight">' . $langs->trans("CalculatedWeight") . '</td>';
3248 print '<td class="center linecolvolume">' . $langs->trans("CalculatedVolume") . '</td>';
3249 //print '<td class="center">'.$langs->trans("Size").'</td>';
3250 if ($object->status == 0) {
3251 print '<td class="linecoledit"></td>';
3252 print '<td class="linecoldelete" width="10"></td>';
3253 print '<td class="linecolmove"></td>';
3254 }
3255 print "</tr>\n";
3256 print '</thead>';
3257
3258 $outputlangs = $langs;
3259
3260 if (getDolGlobalInt('MAIN_MULTILANGS') && getDolGlobalString('PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE')) {
3261 $object->fetch_thirdparty();
3262 $newlang = '';
3263 if (/* empty($newlang) && */GETPOST('lang_id', 'aZ09')) {
3264 $newlang = GETPOST('lang_id', 'aZ09');
3265 }
3266 if (empty($newlang)) {
3267 $newlang = $object->thirdparty->default_lang;
3268 }
3269 if (!empty($newlang)) {
3270 $outputlangs = new Translate("", $conf);
3271 $outputlangs->setDefaultLang($newlang);
3272 }
3273 }
3274
3275 // Get list of products already sent for same source object into $alreadysent
3276 $alreadysent = array();
3277 if ($origin_id > 0) {
3278 $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";
3279 $sql .= ", ed.rowid as shipmentline_id, ed.qty as qty_shipped, ed.fk_expedition as expedition_id, ed.fk_elementdet, ed.fk_entrepot";
3280 $sql .= ", e.rowid as shipment_id, e.ref as shipment_ref, e.date_creation, e.date_valid, e.date_delivery, e.date_expedition";
3281 $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';
3282 $sql .= ', p.description as product_desc';
3283 $sql .= " FROM " . MAIN_DB_PREFIX . "expeditiondet as ed";
3284 $sql .= ", " . MAIN_DB_PREFIX . "expedition as e";
3285 $sql .= ", " . MAIN_DB_PREFIX . $db->sanitize((string) $origin) . "det as obj";
3286 $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "product as p ON obj.fk_product = p.rowid";
3287 $sql .= " WHERE e.entity IN (" . getEntity('expedition') . ")";
3288 $sql .= " AND obj.fk_" . $db->sanitize((string) $origin) . " = " . ((int) $origin_id);
3289 $sql .= " AND obj.rowid = ed.fk_elementdet";
3290 $sql .= " AND ed.fk_expedition = e.rowid";
3291 //if ($filter) $sql.= $filter;
3292 $sql .= " ORDER BY obj.fk_product";
3293
3294 dol_syslog("expedition/card.php get list of shipment lines", LOG_DEBUG);
3295 $resql = $db->query($sql);
3296 if ($resql) {
3297 $num = $db->num_rows($resql);
3298 $i = 0;
3299
3300 while ($i < $num) {
3301 $obj = $db->fetch_object($resql);
3302 if ($obj) {
3303 // $obj->rowid is rowid in $origin."det" table
3304 $alreadysent[$obj->rowid][$obj->shipmentline_id] = array(
3305 'shipment_ref' => $obj->shipment_ref,
3306 'shipment_id' => $obj->shipment_id,
3307 'warehouse' => $obj->fk_entrepot,
3308 'qty_shipped' => $obj->qty_shipped,
3309 'product_tosell' => $obj->product_tosell,
3310 'product_tobuy' => $obj->product_tobuy,
3311 'product_tobatch' => $obj->product_tobatch,
3312 'date_valid' => $db->jdate($obj->date_valid),
3313 'date_delivery' => $db->jdate($obj->date_delivery));
3314 }
3315 $i++;
3316 }
3317 }
3318 //var_dump($alreadysent);
3319 }
3320
3321 print '<tbody>';
3322
3323 // Loop on each product to send/sent
3324 $conf->cache['product'] = array();
3325 $conf->cache['warehouse'] = array();
3326 for ($i = 0; $i < $num_prod; $i++) {
3327 $parameters = array('i' => $i, 'line' => $lines[$i], 'line_id' => $line_id, 'num' => $num_prod, 'alreadysent' => $alreadysent, 'editColspan' => !empty($editColspan) ? $editColspan : 0, 'outputlangs' => $outputlangs);
3328 $reshook = $hookmanager->executeHooks('printObjectLine', $parameters, $object, $action);
3329 if ($reshook < 0) {
3330 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
3331 }
3332
3333 if (empty($reshook) && $lines[$i]->product_type != "9") {
3334 print '<!-- origin line id = ' . $lines[$i]->origin_line_id . ' -->'; // id of order line
3335 print '<tr class="oddeven" id="row-' . $lines[$i]->id . '" data-id="' . $lines[$i]->id . '" data-element="' . $lines[$i]->element . '" >';
3336 $line = $lines[$i];
3337 $line->fetch_optionals();
3338
3339 // #
3340 if (getDolGlobalString('MAIN_VIEW_LINE_NUMBER')) {
3341 print '<td class="center linecolnum">' . ($i + 1) . '</td>';
3342 }
3343
3344 // Predefined product or service
3345 if ($lines[$i]->fk_product > 0) {
3346 // Define output language
3347 if (getDolGlobalInt('MAIN_MULTILANGS') && getDolGlobalString('PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE')) {
3348 $product_id = $lines[$i]->fk_product;
3349 if (!isset($conf->cache['product'][$product_id])) {
3350 $prod = new Product($db);
3351 $prod->fetch($product_id);
3352 $conf->cache['product'][$product_id] = $prod;
3353 } else {
3354 $prod = $conf->cache['product'][$product_id];
3355 }
3356 $label = (!empty($prod->multilangs[$outputlangs->defaultlang]["label"])) ? $prod->multilangs[$outputlangs->defaultlang]["label"] : $lines[$i]->product_label;
3357 } else {
3358 $label = (!empty($lines[$i]->label) ? $lines[$i]->label : $lines[$i]->product_label);
3359 }
3360
3361 print '<td class="linecoldescription">';
3362
3363 // Show product and description
3364 $product_static->type = $lines[$i]->fk_product_type;
3365 $product_static->id = $lines[$i]->fk_product;
3366 $product_static->ref = $lines[$i]->ref;
3367 $product_static->status = $lines[$i]->product_tosell;
3368 $product_static->status_buy = $lines[$i]->product_tobuy;
3369 $product_static->status_batch = $lines[$i]->product_tobatch;
3370
3371 $product_static->weight = $lines[$i]->weight;
3372 $product_static->weight_units = $lines[$i]->weight_units;
3373 $product_static->length = $lines[$i]->length;
3374 $product_static->length_units = $lines[$i]->length_units;
3375 $product_static->width = !empty($lines[$i]->width) ? $lines[$i]->width : 0;
3376 $product_static->width_units = !empty($lines[$i]->width_units) ? $lines[$i]->width_units : 0;
3377 $product_static->height = !empty($lines[$i]->height) ? $lines[$i]->height : 0;
3378 $product_static->height_units = !empty($lines[$i]->height_units) ? $lines[$i]->height_units : 0;
3379 $product_static->surface = $lines[$i]->surface;
3380 $product_static->surface_units = $lines[$i]->surface_units;
3381 $product_static->volume = $lines[$i]->volume;
3382 $product_static->volume_units = $lines[$i]->volume_units;
3383 $product_static->stockable_product = $lines[$i]->stockable_product;
3384
3385 $text = $product_static->getNomUrl(1);
3386 $text .= ' - ' . $label;
3387 $description = (getDolGlobalInt('PRODUIT_DESC_IN_FORM_ACCORDING_TO_DEVICE') ? '' : dol_htmlentitiesbr($lines[$i]->description));
3388 print $form->textwithtooltip($text, $description, 3, 0, '', (string) $i);
3389 print_date_range(!empty($lines[$i]->date_start) ? $lines[$i]->date_start : '', !empty($lines[$i]->date_end) ? $lines[$i]->date_end : '');
3390 if (getDolGlobalInt('PRODUIT_DESC_IN_FORM_ACCORDING_TO_DEVICE')) {
3391 print (!empty($lines[$i]->description) && $lines[$i]->description != $lines[$i]->product) ? '<br>' . dol_htmlentitiesbr($lines[$i]->description) : '';
3392 }
3393 $lineExtrafieldsHtml = $line->showOptionals($extrafields, ($action == 'editline' && $line->id == $line_id) ? 'edit' : 'view', array(), '', '', '1', 'line');
3394 if (!empty($lineExtrafieldsHtml)) {
3395 print '<div style="padding-top: 10px" id="extrafield_lines_area_' . $line->id . '" name="extrafield_lines_area_' . $line->id . '">';
3396 print $lineExtrafieldsHtml;
3397 print '</div>';
3398 }
3399 print "</td>\n";
3400 } else {
3401 print '<td class="linecoldescription" >';
3402 if ($lines[$i]->product_type == Product::TYPE_SERVICE) {
3403 $text = img_object($langs->trans('Service'), 'service');
3404 } else {
3405 $text = img_object($langs->trans('Product'), 'product');
3406 }
3407
3408 if (!empty($lines[$i]->label)) {
3409 $text .= ' <strong>' . $lines[$i]->label . '</strong>';
3410 print $form->textwithtooltip($text, $lines[$i]->description, 3, 0, '', (string) $i);
3411 } else {
3412 print $text . ' ' . nl2br($lines[$i]->description);
3413 }
3414
3415 print_date_range($lines[$i]->date_start, $lines[$i]->date_end);
3416 $lineExtrafieldsHtml = $line->showOptionals($extrafields, ($action == 'editline' && $line->id == $line_id) ? 'edit' : 'view', array(), '', '', '1', 'line');
3417 if (!empty($lineExtrafieldsHtml)) {
3418 print '<div style="padding-top: 10px" id="extrafield_lines_area_' . $line->id . '" name="extrafield_lines_area_' . $line->id . '">';
3419 print $lineExtrafieldsHtml;
3420 print '</div>';
3421 }
3422 print "</td>\n";
3423 }
3424
3425 $unit_order = '';
3426 if (getDolGlobalString('PRODUCT_USE_UNITS')) {
3427 $unit_order = measuringUnitString((int) $lines[$i]->fk_unit);
3428 }
3429
3430 // Qty ordered
3431 print '<td class="center linecolqty">' . $lines[$i]->qty_asked . ' ' . $unit_order . '</td>';
3432
3433 // Qty in other shipments (with shipment and warehouse used)
3434 if ($origin_id > 0) {
3435 print '<td class="linecolqtyinothershipments center nowrap">';
3436 $htmltooltip = '';
3437 $qtyalreadysent = 0;
3438 foreach ($alreadysent as $key => $val) {
3439 if ($lines[$i]->fk_elementdet == $key) {
3440 $j = 0;
3441 foreach ($val as $shipmentline_id => $shipmentline_var) {
3442 if ($shipmentline_var['shipment_id'] == $lines[$i]->fk_expedition) {
3443 continue; // We want to show only "other shipments"
3444 }
3445
3446 $j++;
3447 if ($j > 1) {
3448 $htmltooltip .= '<br>';
3449 }
3450 $shipment_static->fetch($shipmentline_var['shipment_id']);
3451 $htmltooltip .= $shipment_static->getNomUrl(1, '', 0, 0, 1);
3452 $htmltooltip .= ' - ' . $shipmentline_var['qty_shipped'];
3453 $htmltooltip .= ' - ' . $langs->trans("DateValidation") . ' : ' . (empty($shipmentline_var['date_valid']) ? $langs->trans("Draft") : dol_print_date($shipmentline_var['date_valid'], 'dayhour'));
3454 /*if (isModEnabled('stock') && $shipmentline_var['warehouse'] > 0) {
3455 $warehousestatic->fetch($shipmentline_var['warehouse']);
3456 $htmltext .= '<br>'.$langs->trans("FromLocation").' : '.$warehousestatic->getNomUrl(1, '', 0, 1);
3457 }*/
3458 //print ' '.$form->textwithpicto('', $htmltext, 1);
3459
3460 $qtyalreadysent += $shipmentline_var['qty_shipped'];
3461 }
3462 if ($j) {
3463 $htmltooltip = $langs->trans("QtyInOtherShipments") . '...<br><br>' . $htmltooltip . '<br><input type="submit" name="dummyhiddenbuttontogetfocus" style="display:none" autofocus>';
3464 }
3465 }
3466 }
3467 print $form->textwithpicto((string) $qtyalreadysent, $htmltooltip, 1, 'info', '', 0, 3, 'tooltip' . $lines[$i]->id);
3468 print '</td>';
3469 }
3470
3471 if ($action == 'editline' && $lines[$i]->id == $line_id) {
3472 // edit mode
3473 print '<td colspan="' . $editColspan . '" class="center"><table class="nobordernopadding centpercent">';
3474 if (is_array($lines[$i]->detail_batch) && count($lines[$i]->detail_batch) > 0) {
3475 print '<!-- case edit 1 -->';
3476 $line = new ExpeditionLigne($db);
3477 foreach ($lines[$i]->detail_batch as $detail_batch) {
3478 print '<tr>';
3479 // Qty to ship or shipped
3480 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>';
3481 // Batch number management
3482 if ($lines[$i]->entrepot_id == 0) {
3483 // only show lot numbers from src warehouse when shipping from multiple warehouses
3484 $line->fetch($detail_batch->fk_expeditiondet);
3485 }
3486 $entrepot_id = !empty($detail_batch->entrepot_id) ? $detail_batch->entrepot_id : $lines[$i]->entrepot_id;
3487 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>';
3488 print '</tr>';
3489 }
3490 // add a 0 qty lot row to be able to add a lot
3491 print '<tr>';
3492 // Qty to ship or shipped
3493 print '<td><input class="qtyl" name="qtyl' . $line_id . '_0" id="qtyl' . $line_id . '_0" type="text" size="4" value="0"></td>';
3494 // Batch number management
3495 print '<td>' . $formproduct->selectLotStock('', 'batchl' . $line_id . '_0', '', 1, 0, $lines[$i]->fk_product) . '</td>';
3496 print '</tr>';
3497 } elseif (isModEnabled('stock')) {
3498 if ($lines[$i]->fk_product > 0) {
3499 if ($lines[$i]->entrepot_id > 0) {
3500 print '<!-- case edit 2 -->';
3501 print '<tr>';
3502 // Qty to ship or shipped
3503 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>';
3504 // Warehouse source
3505 print '<td>' . $formproduct->selectWarehouses($lines[$i]->entrepot_id, 'entl' . $line_id, '', 1, 0, $lines[$i]->fk_product, '', 1, 0, array(), 'minwidth200') . '</td>';
3506 // Batch number management
3507 print '<td>';
3508 if (isModEnabled('productbatch')) {
3509 print ' - ' . $langs->trans("NA");
3510 }
3511 print '</td>';
3512 print '</tr>';
3513 } elseif (count($lines[$i]->details_entrepot) > 1) {
3514 print '<!-- case edit 3 -->';
3515 foreach ($lines[$i]->details_entrepot as $detail_entrepot) {
3516 print '<tr>';
3517 // Qty to ship or shipped
3518 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>';
3519 // Warehouse source
3520 print '<td>' . $formproduct->selectWarehouses($detail_entrepot->entrepot_id, 'entl' . $detail_entrepot->line_id, '', 1, 0, $lines[$i]->fk_product, '', 1, 0, array(), 'minwidth200') . '</td>';
3521 // Batch number management
3522 print '<td>';
3523 if (isModEnabled('productbatch')) {
3524 print ' - ' . $langs->trans("NA");
3525 }
3526 print '</td>';
3527 print '</tr>';
3528 }
3529 } elseif ($lines[$i]->product_type == Product::TYPE_SERVICE && getDolGlobalString('SHIPMENT_SUPPORTS_SERVICES')) {
3530 print '<!-- case edit 4 -->';
3531 print '<tr>';
3532 // Qty to ship or shipped
3533 print '<td><input class="qtyl right" name="qtyl' . $line_id . '" id="qtyl' . $line_id . '" type="text" size="4" value="' . $lines[$i]->qty_shipped . '"></td>';
3534 print '<td><span class="opacitymedium">(' . $langs->trans("Service") . ')</span></td>';
3535 print '<td></td>';
3536 print '</tr>';
3537 } else {
3538 print '<!-- case edit 5 -->';
3539 print '<tr><td colspan="3">' . $langs->trans("ErrorStockIsNotEnough") . '</td></tr>';
3540 }
3541 } else {
3542 print '<!-- case edit 6 -->';
3543 print '<tr>';
3544 // Qty to ship or shipped
3545 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>';
3546 // Warehouse source
3547 print '<td></td>';
3548 // Batch number management
3549 print '<td></td>';
3550 print '</tr>';
3551 }
3552 } else { // both product batch and stock are not activated.
3553 print '<!-- case edit 7 -->';
3554 print '<tr>';
3555 // Qty to ship or shipped
3556 print '<td><input class="qtyl right" name="qtyl' . $line_id . '" id="qtyl' . $line_id . '" type="text" size="4" value="' . $lines[$i]->qty_shipped . '"></td>';
3557 // Warehouse source
3558 print '<td></td>';
3559 // Batch number management
3560 print '<td></td>';
3561 print '</tr>';
3562 }
3563
3564 print '</table></td>';
3565 } else {
3566 // Qty to ship or shipped
3567 print '<td class="linecolqtytoship center">' . $lines[$i]->qty_shipped . ' ' . $unit_order . '</td>';
3568
3569 // Warehouse source
3570 if (isModEnabled('stock')) {
3571 print '<td class="linecolwarehousesource tdoverflowmax200">';
3572 if ($lines[$i]->product_type == Product::TYPE_SERVICE && getDolGlobalString('SHIPMENT_SUPPORTS_SERVICES')) {
3573 print '<span class="opacitymedium">(' . $langs->trans("Service") . ')</span>';
3574 } elseif ($lines[$i]->entrepot_id > 0 && $lines[$i]->stockable_product == Product::ENABLED_STOCK) {
3575 $warehouse_id = $lines[$i]->entrepot_id;
3576 if (!isset($conf->cache['warehouse'][$warehouse_id])) {
3577 $warehouse = new Entrepot($db);
3578 $warehouse->fetch($warehouse_id);
3579 $conf->cache['warehouse'][$warehouse_id] = $warehouse;
3580 } else {
3581 $warehouse = $conf->cache['warehouse'][$warehouse_id];
3582 }
3583 print $warehouse->getNomUrl(1);
3584 } elseif (count($lines[$i]->details_entrepot) > 1) {
3585 $detail = '';
3586 foreach ($lines[$i]->details_entrepot as $detail_entrepot) {
3587 $warehouse_id = $detail_entrepot->entrepot_id;
3588 if ($warehouse_id > 0) {
3589 if (!isset($conf->cache['warehouse'][$warehouse_id])) {
3590 $warehouse = new Entrepot($db);
3591 $warehouse->fetch($warehouse_id);
3592 $conf->cache['warehouse'][$warehouse_id] = $warehouse;
3593 } else {
3594 $warehouse = $conf->cache['warehouse'][$warehouse_id];
3595 }
3596 $detail .= $langs->trans("DetailWarehouseFormat", $warehouse->label, $detail_entrepot->qty_shipped) . '<br>';
3597 }
3598 }
3599 print $form->textwithtooltip(img_picto('', 'object_stock') . ' ' . $langs->trans("DetailWarehouseNumber"), $detail);
3600 } elseif (count($lines[$i]->detail_children ?? []) > 1) {
3601 $detail = '';
3602 foreach ($lines[$i]->detail_children as $child_product_id => $child_stock_list) {
3603 foreach ($child_stock_list as $warehouse_id => $total_qty) {
3604 // get product from cache
3605 $child_product_label = '';
3606 if (!isset($conf->cache['product'][$child_product_id])) {
3607 $child_product = new Product($db);
3608 $child_product->fetch($child_product_id);
3609 $conf->cache['product'][$child_product_id] = $child_product;
3610 } else {
3611 $child_product = $conf->cache['product'][$child_product_id];
3612 }
3613 $child_product_label = $child_product->ref . ' ' . $child_product->label;
3614
3615 // get warehouse from cache
3616 if (!isset($conf->cache['warehouse'][$warehouse_id])) {
3617 $child_warehouse = new Entrepot($db);
3618 $child_warehouse->fetch($warehouse_id);
3619 $conf->cache['warehouse'][$warehouse_id] = $child_warehouse;
3620 } else {
3621 $child_warehouse = $conf->cache['warehouse'][$warehouse_id];
3622 }
3623 $detail .= $langs->trans('DetailChildrenFormat', $child_product_label, $child_warehouse->label, price2num($total_qty, 'MS')) . '<br>';
3624 }
3625 }
3626 print $form->textwithtooltip(img_picto('', 'object_stock') . ' ' . $langs->trans('DetailWarehouseNumber'), $detail);
3627 }
3628 print '</td>';
3629 }
3630
3631 // Batch number management
3632 if (isModEnabled('productbatch')) {
3633 if (isset($lines[$i]->detail_batch)) {
3634 print '<!-- Detail of lot -->';
3635 print '<td class="linecolbatch">';
3636 if ($lines[$i]->product_tobatch) {
3637 $detail = '';
3638 foreach ($lines[$i]->detail_batch as $dbatch) { // $dbatch is instance of ExpeditionLineBatch
3639 $detail .= $langs->trans("Batch") . ': ' . $dbatch->batch;
3640 if (!getDolGlobalString('PRODUCT_DISABLE_SELLBY')) {
3641 $detail .= ' - ' . $langs->trans("SellByDate") . ': ' . dol_print_date($dbatch->sellby, "day");
3642 }
3643 if (!getDolGlobalString('PRODUCT_DISABLE_EATBY')) {
3644 $detail .= ' - ' . $langs->trans("EatByDate") . ': ' . dol_print_date($dbatch->eatby, "day");
3645 }
3646 $detail .= ' - ' . $langs->trans("Qty") . ': ' . $dbatch->qty;
3647 $detail .= '<br>';
3648 }
3649 print $form->textwithtooltip(img_picto('', 'object_barcode') . ' ' . $langs->trans("DetailBatchNumber"), $detail);
3650 } else {
3651 print $langs->trans("NA");
3652 }
3653 print '</td>';
3654 } else {
3655 print '<td class="linecolbatch" ></td>';
3656 }
3657 }
3658 }
3659
3660 // Weight
3661 print '<td class="center linecolweight">';
3662 if ($lines[$i]->fk_product_type == Product::TYPE_PRODUCT) {
3663 print $lines[$i]->weight * $lines[$i]->qty_shipped . ' ' . measuringUnitString(0, "weight", $lines[$i]->weight_units);
3664 } else {
3665 print '&nbsp;';
3666 }
3667 print '</td>';
3668
3669 // Volume
3670 print '<td class="center linecolvolume">';
3671 if ($lines[$i]->fk_product_type == Product::TYPE_PRODUCT) {
3672 print $lines[$i]->volume * $lines[$i]->qty_shipped . ' ' . measuringUnitString(0, "volume", $lines[$i]->volume_units);
3673 } else {
3674 print '&nbsp;';
3675 }
3676 print '</td>';
3677
3678 // Size
3679 //print '<td class="center">'.$lines[$i]->volume*$lines[$i]->qty_shipped.' '.measuringUnitString(0, "volume", $lines[$i]->volume_units).'</td>';
3680
3681 $showmovecol = ($object->status == Expedition::STATUS_DRAFT);
3682
3683 if ($action == 'editline' && $lines[$i]->id == $line_id) {
3684 print '<td class="center" colspan="2" valign="middle">';
3685 print '<input type="submit" class="button button-save" id="savelinebutton marginbottomonly" name="save" value="' . $langs->trans("Save") . '"><br>';
3686 print '<input type="submit" class="button button-cancel" id="cancellinebutton" name="cancel" value="' . $langs->trans("Cancel") . '"><br>';
3687 print '</td>';
3688 if ($showmovecol) {
3689 print '<td class="linecolmove tdlineupdown center"></td>';
3690 }
3691 } elseif ($showmovecol) {
3692 $edit_url = $_SERVER["PHP_SELF"] . '?id=' . $object->id . '&action=editline&token=' . newToken() . '&lineid=' . $lines[$i]->id;
3693 if (getDolGlobalInt('PRODUIT_SOUSPRODUITS')) {
3694 $product_id = $lines[$i]->fk_product;
3695 if (!isset($conf->cache['product'][$product_id])) {
3696 $product = new Product($db);
3697 $product->fetch($product_id);
3698 $conf->cache['product'][$product_id] = $product;
3699 } else {
3700 $product = $conf->cache['product'][$product_id];
3701 }
3702
3703 if ($product->hasFatherOrChild(1)) {
3704 $edit_url = dol_buildpath('/expedition/dispatch.php?id=' . $object->id, 1);
3705 }
3706 }
3707
3708 // edit-delete buttons
3709 print '<td class="linecoledit center">';
3710 print '<a class="editfielda reposition" href="' . $edit_url . '">' . img_edit() . '</a>';
3711 print '</td>';
3712 print '<td class="linecoldelete" width="10">';
3713 print '<a class="reposition" href="' . $_SERVER["PHP_SELF"] . '?id=' . $object->id . '&action=deleteline&token=' . newToken() . '&lineid=' . $lines[$i]->id . '">' . img_delete() . '</a>';
3714 print '</td>';
3715 print '<td class="linecolmove tdlineupdown center">';
3716 if ($usercancreate && $num_prod > 1) {
3717 if ($i > 0) {
3718 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>';
3719 }
3720 if ($i < $num_prod - 1) {
3721 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>';
3722 }
3723 }
3724 print '</td>';
3725 // Display lines extrafields
3726 if (!empty($rowExtrafieldsStart)) {
3727 print $rowExtrafieldsStart;
3728 print $rowExtrafieldsView;
3729 print $rowEnd;
3730 }
3731 }
3732 print "</tr>";
3733 } elseif (empty($reshook) && $lines[$i]->product_type == "9") {
3734 $objectsrc = new OrderLine($db);
3735 $objectsrc->fetch($lines[$i]->origin_line_id);
3736 if ($objectsrc->special_code == SUBTOTALS_SPECIAL_CODE) {
3737 $line = $lines[$i];
3738 require dol_buildpath('/core/tpl/subtotal_expedition_view.tpl.php');
3739 }
3740 }
3741 }
3742 // TODO Show also lines ordered but not delivered
3743 if (empty($num_prod)) {
3744 print '<tr><td colspan="8"><span class="opacitymedium">' . $langs->trans("NoLineGoOnTabToAddSome", $langs->transnoentitiesnoconv("ShipmentDistribution")) . '</span></td></tr>';
3745 }
3746
3747 print '</tbody>';
3748 print "</table>\n";
3749 print '</div>';
3750 if ($action == 'editline') {
3751 print "</form>\n";
3752 }
3753
3754 $object->fetchObjectLinked($object->id, $object->element);
3755 }
3756
3757 /*
3758 * Boutons actions
3759 */
3760
3761 if (($user->socid == 0) && ($action != 'presend')) {
3762 print '<div class="tabsAction">';
3763
3764 $parameters = array();
3765 $reshook = $hookmanager->executeHooks('addMoreActionsButtons', $parameters, $object, $action); // Note that $action and $object may have been
3766 // modified by hook
3767 if (empty($reshook)) {
3768 if ($object->status == Expedition::STATUS_DRAFT && $num_prod > 0) {
3769 if ((!getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && $user->hasRight('expedition', 'creer'))
3770 || (getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && $user->hasRight('expedition', 'shipping_advance', 'validate'))
3771 ) {
3772 print dolGetButtonAction('', $langs->trans('Validate'), 'default', $_SERVER["PHP_SELF"] . '?action=valid&token=' . newToken() . '&id=' . $object->id, '');
3773 } else {
3774 print dolGetButtonAction($langs->trans('NotAllowed'), $langs->trans('Validate'), 'default', $_SERVER['PHP_SELF'] . '#', '', false);
3775 }
3776 }
3777
3778 // 0=draft, 1=validated/delivered, 2=closed/delivered
3779 if ($object->status == Expedition::STATUS_VALIDATED && !getDolGlobalString('STOCK_CALCULATE_ON_SHIPMENT')) {
3780 if ($user->hasRight('expedition', 'creer')) {
3781 print dolGetButtonAction('', $langs->trans('SetToDraft'), 'default', $_SERVER["PHP_SELF"] . '?action=setdraft&token=' . newToken() . '&id=' . $object->id, '');
3782 }
3783 }
3784 if ($object->status == Expedition::STATUS_CLOSED) {
3785 if ($user->hasRight('expedition', 'creer')) {
3786 print dolGetButtonAction('', $langs->trans('ReOpen'), 'default', $_SERVER["PHP_SELF"] . '?action=reopen&token=' . newToken() . '&id=' . $object->id, '');
3787 }
3788 }
3789
3790 // Send
3791 if (empty($user->socid)) {
3792 if ($object->status > 0) {
3793 if (!getDolGlobalString('MAIN_USE_ADVANCED_PERMS') || $user->hasRight('expedition', 'shipping_advance', 'send')) {
3794 print dolGetButtonAction('', $langs->trans('SendMail'), 'email', $_SERVER["PHP_SELF"] . '?action=presend&token=' . newToken() . '&id=' . $object->id . '&mode=init#formmailbeforetitle', '');
3795 } else {
3796 print dolGetButtonAction('', $langs->trans('SendMail'), 'email', $_SERVER['PHP_SELF'] . '#', '', false);
3797 }
3798 }
3799 }
3800
3801 // This is just to generate a delivery receipt when option to do this is on
3802 //var_dump($object->linkedObjectsIds['delivery']);
3803 if (getDolGlobalInt('MAIN_SUBMODULE_DELIVERY') && ($object->status == Expedition::STATUS_VALIDATED || $object->status == Expedition::STATUS_CLOSED) && $user->hasRight('expedition', 'delivery', 'creer') && empty($object->linkedObjectsIds['delivery'])) {
3804 print dolGetButtonAction('', $langs->trans('CreateDeliveryOrder'), 'default', $_SERVER["PHP_SELF"] . '?action=create_delivery&token=' . newToken() . '&id=' . $object->id, '');
3805 }
3806
3807 // Sign (to set to status "Signed" without using the online signature page)
3808 if ($object->status > Expedition::STATUS_DRAFT) {
3809 if ($object->signed_status != Expedition::$SIGNED_STATUSES['STATUS_SIGNED_ALL']) {
3810 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>';
3811 } else {
3812 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>';
3813 }
3814 }
3815
3816 // Create bill
3817 if (isModEnabled('invoice') && ($object->status == Expedition::STATUS_VALIDATED || $object->status == Expedition::STATUS_CLOSED)) {
3818 if ($user->hasRight('facture', 'creer')) {
3819 if (getDolGlobalString('WORKFLOW_BILL_ON_SHIPMENT') !== '0') {
3820 print dolGetButtonAction('', $langs->trans('CreateBill'), 'default', DOL_URL_ROOT . '/compta/facture/card.php?action=create&origin=' . $object->element . '&originid=' . $object->id . '&socid=' . $object->socid, '');
3821 }
3822 }
3823 }
3824
3825 // Set Billed and Closed
3826 if ($object->status == Expedition::STATUS_VALIDATED) {
3827 if ($user->hasRight('expedition', 'creer') && $object->status > 0) {
3828 if (!$object->billed && getDolGlobalString('WORKFLOW_BILL_ON_SHIPMENT') !== '0') {
3829 print dolGetButtonAction('', $langs->trans('ClassifyBilled'), 'default', $_SERVER["PHP_SELF"] . '?action=classifybilled&token=' . newToken() . '&id=' . $object->id, '');
3830 }
3831 print dolGetButtonAction('', $langs->trans("Close"), 'default', $_SERVER["PHP_SELF"] . '?action=classifyclosed&token=' . newToken() . '&id=' . $object->id, '');
3832 }
3833 }
3834
3835 // Cancel
3836 if ($object->status == Expedition::STATUS_VALIDATED) {
3837 if ($user->hasRight('expedition', 'creer')) {
3838 print dolGetButtonAction('', $langs->trans('Cancel'), 'danger', $_SERVER["PHP_SELF"] . '?action=cancel&token=' . newToken() . '&id=' . $object->id . '&mode=init#formmailbeforetitle', '');
3839 }
3840 }
3841
3842 // Delete
3843 if ($user->hasRight('expedition', 'supprimer')) {
3844 print dolGetButtonAction('', $langs->trans('Delete'), 'delete', $_SERVER["PHP_SELF"] . '?action=delete&token=' . newToken() . '&id=' . $object->id, '');
3845 }
3846 }
3847
3848 print '</div>';
3849 }
3850
3851
3852 /*
3853 * Documents generated
3854 */
3855
3856 if ($action != 'presend' && $action != 'editline') {
3857 print '<div class="fichecenter"><div class="fichehalfleft">';
3858
3859 $objectref = dol_sanitizeFileName((string) $object->ref);
3860 $filedir = $conf->expedition->dir_output . "/sending/" . $objectref;
3861
3862 $urlsource = $_SERVER["PHP_SELF"] . "?id=" . $object->id;
3863
3864 $genallowed = $user->hasRight('expedition', 'lire');
3865 $delallowed = $user->hasRight('expedition', 'creer');
3866
3867 print $formfile->showdocuments('expedition', $objectref, $filedir, $urlsource, $genallowed, $delallowed, $object->model_pdf, 1, 0, 0, 28, 0, '', '', '', $soc->default_lang);
3868
3869
3870 // Show links to link elements
3871 $tmparray = $form->showLinkToObjectBlock($object, array(), array('shipping'), 1);
3872 $linktoelem = $tmparray['linktoelem'];
3873 $htmltoenteralink = $tmparray['htmltoenteralink'];
3874 print $htmltoenteralink;
3875
3876 $somethingshown = $form->showLinkedObjectBlock($object, $linktoelem);
3877
3878 // Show online signature link
3879 $useonlinesignature = getDolGlobalInt('EXPEDITION_ALLOW_ONLINESIGN');
3880
3881 if ($object->statut != Expedition::STATUS_DRAFT && $useonlinesignature) {
3882 print '<br><!-- Link to sign -->';
3883 require_once DOL_DOCUMENT_ROOT . '/core/lib/signature.lib.php';
3884 print showOnlineSignatureUrl('expedition', $object->ref, $object) . '<br>';
3885 }
3886
3887 print '</div><div class="fichehalfright">';
3888
3889
3890 // List of actions on element
3891 include_once DOL_DOCUMENT_ROOT . '/core/class/html.formactions.class.php';
3892 $formactions = new FormActions($db);
3893
3894 //button to go to messaging from the events box
3895 $MAXEVENT = 10;
3896 $morehtmlcenter = dolGetButtonTitle($langs->trans('FullConversation'), '', 'fa fa-comments imgforviewmode', DOL_URL_ROOT . '/expedition/messaging.php?id=' . $object->id);
3897
3898 $somethingshown = $formactions->showactions($object, 'shipping', $socid, 1, '', $MAXEVENT, '', $morehtmlcenter);
3899 print '</div></div>';
3900 }
3901
3902
3903 /*
3904 * Action presend
3905 */
3906
3907 //Select mail models is same action as presend
3908 if (GETPOST('modelselected')) {
3909 $action = 'presend';
3910 }
3911
3912 // Presend form
3913 $modelmail = 'shipping_send';
3914 $defaulttopic = 'SendShippingRef';
3915 $diroutput = $conf->expedition->dir_output . '/sending';
3916 $trackid = 'shi' . $object->id;
3917
3918 include DOL_DOCUMENT_ROOT . '/core/tpl/card_presend.tpl.php';
3919}
3920
3921// End of page
3922llxFooter();
3923$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.
info_admin($text, $infoonimgalt=0, $nodiv=0, $admin='1', $morecss='hideonsmartphone', $textfordropdown='', $picto='', $textonpictotooltip='')
Show information in HTML for admin users or standard users.
img_delete($titlealt='default', $other='class="pictodelete"', $morecss='')
Show delete logo.
GETPOSTINT($paramname, $method=0)
Return the value of a $_GET or $_POST supervariable, converted into integer.
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 '.
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.
GETPOSTFLOAT($paramname, $rounding='', $option=2)
Return the value of a $_GET or $_POST supervariable, converted into float.
dol_htmlcleanlastbr($stringtodecode)
This function remove all ending and br at end.
dol_concatdesc($text1, $text2, $forxml=false, $invert=false)
Concat 2 descriptions with a new line between them (second operand after first one with appropriate n...
dolPrintHTMLForAttribute($s, $escapeonlyhtmltags=0, $allowothertags=array())
Return a string ready to be output into an HTML attribute (alt, title, data-html, ....
print_date_range($date_start, $date_end, $format='', $outputlangs=null)
Format output for start and end date.
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
dol_buildpath($path, $type=0, $returnemptyifnotfound=0)
Return path of url or filesystem.
dol_clone($srcobject, $native=2)
Create a clone of instance of object (new instance with same value for each properties) With native =...
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs=null, $encodetooutput=false, $decorate=0)
Output date in a string format according to outputlangs (or langs if not defined).
getDolGlobalBool($key, $default=false)
Return a Dolibarr global constant boolean value.
dol_print_error($db=null, $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
load_fiche_titre($title, $morehtmlright='', $picto='generic', $pictoisfullpath=0, $id='', $morecssontable='', $morehtmlcenter='', $morecssonpicto='widthpictotitle')
Load a title with picto.
dol_htmlentitiesbr($stringtoencode, $nl2brmode=0, $pagecodefrom='UTF-8', $removelasteolbr=1)
This function is called to encode a string into a HTML string but differs from htmlentities because a...
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
isModEnabled($module)
Is Dolibarr module enabled.
img_edit($titlealt='default', $float=0, $other='')
Show logo edit/modify fiche.
img_up($titlealt='default', $selected=0, $moreclass='')
Show top arrow logo.
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.