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