dolibarr 18.0.6
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-2022 Frédéric France <frederic.france@netlogic.fr>
15 * Copyright (C) 2020 Lenin Rivas <lenin@leninrivas.com>
16 * Copyright (C) 2022 Josep Lluís Amador <joseplluis@lliuretic.cat>
17 *
18 * This program is free software; you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License as published by
20 * the Free Software Foundation; either version 3 of the License, or
21 * (at your option) any later version.
22 *
23 * This program is distributed in the hope that it will be useful,
24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 * GNU General Public License for more details.
27 *
28 * You should have received a copy of the GNU General Public License
29 * along with this program. If not, see <https://www.gnu.org/licenses/>.
30 */
31
38// Load Dolibarr environment
39require '../main.inc.php';
40require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php';
41require_once DOL_DOCUMENT_ROOT.'/expedition/class/expedition.class.php';
42require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php';
43require_once DOL_DOCUMENT_ROOT.'/core/lib/product.lib.php';
44require_once DOL_DOCUMENT_ROOT.'/core/lib/sendings.lib.php';
45require_once DOL_DOCUMENT_ROOT.'/core/modules/expedition/modules_expedition.php';
46require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
47require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
48require_once DOL_DOCUMENT_ROOT.'/product/stock/class/entrepot.class.php';
49require_once DOL_DOCUMENT_ROOT.'/product/stock/class/productlot.class.php';
50require_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php';
51if (isModEnabled("product") || isModEnabled("service")) {
52 require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
53}
54if (isModEnabled("propal")) {
55 require_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php';
56}
57if (isModEnabled('productbatch')) {
58 require_once DOL_DOCUMENT_ROOT.'/product/class/productbatch.class.php';
59}
60if (isModEnabled('project')) {
61 require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
62 require_once DOL_DOCUMENT_ROOT.'/core/class/html.formprojet.class.php';
63}
64
65// Load translation files required by the page
66$langs->loadLangs(array("sendings", "companies", "bills", 'deliveries', 'orders', 'stocks', 'other', 'propal'));
67
68if (isModEnabled('incoterm')) {
69 $langs->load('incoterm');
70}
71if (isModEnabled('productbatch')) {
72 $langs->load('productbatch');
73}
74
75$origin = GETPOST('origin', 'alpha') ?GETPOST('origin', 'alpha') : 'expedition'; // Example: commande, propal
76$origin_id = GETPOST('id', 'int') ?GETPOST('id', 'int') : '';
77$id = $origin_id;
78if (empty($origin_id)) {
79 $origin_id = GETPOST('origin_id', 'int'); // Id of order or propal
80}
81if (empty($origin_id)) {
82 $origin_id = GETPOST('object_id', 'int'); // Id of order or propal
83}
84$ref = GETPOST('ref', 'alpha');
85$line_id = GETPOST('lineid', 'int') ?GETPOST('lineid', 'int') : '';
86$facid = GETPOST('facid', 'int');
87
88$action = GETPOST('action', 'alpha');
89$confirm = GETPOST('confirm', 'alpha');
90$cancel = GETPOST('cancel', 'alpha');
91
92//PDF
93$hidedetails = (GETPOST('hidedetails', 'int') ? GETPOST('hidedetails', 'int') : (!empty($conf->global->MAIN_GENERATE_DOCUMENTS_HIDE_DETAILS) ? 1 : 0));
94$hidedesc = (GETPOST('hidedesc', 'int') ? GETPOST('hidedesc', 'int') : (!empty($conf->global->MAIN_GENERATE_DOCUMENTS_HIDE_DESC) ? 1 : 0));
95$hideref = (GETPOST('hideref', 'int') ? GETPOST('hideref', 'int') : (!empty($conf->global->MAIN_GENERATE_DOCUMENTS_HIDE_REF) ? 1 : 0));
96
97$object = new Expedition($db);
98$objectorder = new Commande($db);
99$extrafields = new ExtraFields($db);
100
101// fetch optionals attributes and labels
102$extrafields->fetch_name_optionals_label($object->table_element);
103$extrafields->fetch_name_optionals_label($object->table_element_line);
104$extrafields->fetch_name_optionals_label($objectorder->table_element_line);
105
106// Load object. Make an object->fetch
107include DOL_DOCUMENT_ROOT.'/core/actions_fetchobject.inc.php'; // Must be include, not include_once
108
109// Initialize technical object to manage hooks of page. Note that conf->hooks_modules contains array of hook context
110$hookmanager->initHooks(array('expeditioncard', 'globalcard'));
111
112$date_delivery = dol_mktime(GETPOST('date_deliveryhour', 'int'), GETPOST('date_deliverymin', 'int'), 0, GETPOST('date_deliverymonth', 'int'), GETPOST('date_deliveryday', 'int'), GETPOST('date_deliveryyear', 'int'));
113
114if ($id > 0 || !empty($ref)) {
115 $object->fetch($id, $ref);
116 $object->fetch_thirdparty();
117}
118
119// Security check
120$socid = '';
121if ($user->socid) {
122 $socid = $user->socid;
123}
124
125$result = restrictedArea($user, 'expedition', $object->id, '');
126
127$permissiondellink = $user->rights->expedition->delivery->creer; // Used by the include of actions_dellink.inc.php
128$permissiontoadd = $user->rights->expedition->creer;
129
130
131/*
132 * Actions
133 */
134
135$parameters = array();
136$reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
137if ($reshook < 0) {
138 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
139}
140
141if (empty($reshook)) {
142 if ($cancel) {
143 if ($origin && $origin_id > 0) {
144 if ($origin == 'commande') {
145 header("Location: ".DOL_URL_ROOT.'/expedition/shipment.php?id='.((int) $origin_id));
146 exit;
147 }
148 } else {
149 $action = '';
150 $object->fetch($id); // show shipment also after canceling modification
151 }
152 }
153
154 include DOL_DOCUMENT_ROOT.'/core/actions_dellink.inc.php'; // Must be include, not include_once
155
156 // Actions to build doc
157 $upload_dir = $conf->expedition->dir_output.'/sending';
158 include DOL_DOCUMENT_ROOT.'/core/actions_builddoc.inc.php';
159
160 // Back to draft
161 if ($action == 'setdraft' && $user->rights->expedition->creer) {
162 $object->fetch($id);
163 $result = $object->setDraft($user, 0);
164 if ($result < 0) {
165 setEventMessages($object->error, $object->errors, 'errors');
166 }
167 }
168 // Reopen
169 if ($action == 'reopen' && $user->rights->expedition->creer) {
170 $object->fetch($id);
171 $result = $object->reOpen();
172 if ($result < 0) {
173 setEventMessages($object->error, $object->errors, 'errors');
174 }
175 }
176
177 // Set incoterm
178 if ($action == 'set_incoterms' && isModEnabled('incoterm')) {
179 $result = $object->setIncoterms(GETPOST('incoterm_id', 'int'), GETPOST('location_incoterms', 'alpha'));
180 }
181
182 if ($action == 'setref_customer') {
183 $result = $object->fetch($id);
184 if ($result < 0) {
185 setEventMessages($object->error, $object->errors, 'errors');
186 }
187
188 $result = $object->setValueFrom('ref_customer', GETPOST('ref_customer', 'alpha'), '', null, 'text', '', $user, 'SHIPMENT_MODIFY');
189 if ($result < 0) {
190 setEventMessages($object->error, $object->errors, 'errors');
191 $action = 'editref_customer';
192 } else {
193 header("Location: ".$_SERVER['PHP_SELF']."?id=".$object->id);
194 exit;
195 }
196 }
197
198 if ($action == 'update_extras') {
199 $object->oldcopy = dol_clone($object);
200
201 // Fill array 'array_options' with data from update form
202 $ret = $extrafields->setOptionalsFromPost(null, $object, GETPOST('attribute', 'restricthtml'));
203 if ($ret < 0) {
204 $error++;
205 }
206
207 if (!$error) {
208 // Actions on extra fields
209 $result = $object->insertExtraFields('SHIPMENT_MODIFY');
210 if ($result < 0) {
211 setEventMessages($object->error, $object->errors, 'errors');
212 $error++;
213 }
214 }
215
216 if ($error) {
217 $action = 'edit_extras';
218 }
219 }
220
221 // Create shipment
222 if ($action == 'add' && $user->rights->expedition->creer) {
223 $error = 0;
224
225 $db->begin();
226
227 $object->note = GETPOST('note', 'restricthtml');
228 $object->note_private = GETPOST('note', 'restricthtml');
229 $object->origin = $origin;
230 $object->origin_id = $origin_id;
231 $object->fk_project = GETPOST('projectid', 'int');
232 $object->weight = GETPOST('weight', 'int') == '' ? "NULL" : GETPOST('weight', 'int');
233 $object->sizeH = GETPOST('sizeH', 'int') == '' ? "NULL" : GETPOST('sizeH', 'int');
234 $object->sizeW = GETPOST('sizeW', 'int') == '' ? "NULL" : GETPOST('sizeW', 'int');
235 $object->sizeS = GETPOST('sizeS', 'int') == '' ? "NULL" : GETPOST('sizeS', 'int');
236 $object->size_units = GETPOST('size_units', 'int');
237 $object->weight_units = GETPOST('weight_units', 'int');
238
239 $product = new Product($db);
240
241 // We will loop on each line of the original document to complete the shipping object with various info and quantity to deliver
242 $classname = ucfirst($object->origin);
243 $objectsrc = new $classname($db);
244 $objectsrc->fetch($object->origin_id);
245
246 $object->socid = $objectsrc->socid;
247 $object->ref_customer = GETPOST('ref_customer', 'alpha');
248 $object->model_pdf = GETPOST('model');
249 $object->date_delivery = $date_delivery; // Date delivery planed
250 $object->fk_delivery_address = $objectsrc->fk_delivery_address;
251 $object->shipping_method_id = GETPOST('shipping_method_id', 'int');
252 $object->tracking_number = GETPOST('tracking_number', 'alpha');
253 $object->note_private = GETPOST('note_private', 'restricthtml');
254 $object->note_public = GETPOST('note_public', 'restricthtml');
255 $object->fk_incoterms = GETPOST('incoterm_id', 'int');
256 $object->location_incoterms = GETPOST('location_incoterms', 'alpha');
257
258 $batch_line = array();
259 $stockLine = array();
260 $array_options = array();
261
262 $num = count($objectsrc->lines);
263 $totalqty = 0;
264
265 for ($i = 0; $i < $num; $i++) {
266 $idl = "idl".$i;
267
268 $sub_qty = array();
269 $subtotalqty = 0;
270
271 $j = 0;
272 $batch = "batchl".$i."_0";
273 $stockLocation = "ent1".$i."_0";
274 $qty = "qtyl".$i;
275
276 $is_batch_or_serial=0;
277 if (!empty($objectsrc->lines[$i]->fk_product)) {
278 $resultFetch = $product->fetch($objectsrc->lines[$i]->fk_product, '', '', '', 1, 1, 1);
279 if ($resultFetch < 0) {
280 setEventMessages($product->error, $product->errors, 'errors');
281 }
282 $is_batch_or_serial = $product->status_batch;
283 }
284
285 // If product need a batch or serial number
286 if (isModEnabled('productbatch') && $objectsrc->lines[$i]->product_tobatch) {
287 if (GETPOSTISSET($batch)) {
288 //shipment line with batch-enable product
289 $qty .= '_'.$j;
290 while (GETPOSTISSET($batch)) {
291 // save line of detail into sub_qty
292 $sub_qty[$j]['q'] = price2num(GETPOST($qty, 'alpha'), 'MS'); // the qty we want to move for this stock record
293 $sub_qty[$j]['id_batch'] = GETPOST($batch, 'int'); // the id into llx_product_batch of stock record to move
294 $subtotalqty += $sub_qty[$j]['q'];
295
296 //var_dump($qty);
297 //var_dump($batch);
298 //var_dump($sub_qty[$j]['q']);
299 //var_dump($sub_qty[$j]['id_batch']);
300
301 //var_dump($qty);var_dump($batch);var_dump($sub_qty[$j]['q']);var_dump($sub_qty[$j]['id_batch']);
302 if ($is_batch_or_serial==2 && $sub_qty[$j]['q']>1) {
303 setEventMessages($langs->trans("TooManyQtyForSerialNumber", $product->ref, ''), null, 'errors');
304 $totalqty=0;
305 break 2;
306 }
307 $j++;
308 $batch = "batchl".$i."_".$j;
309 $qty = "qtyl".$i.'_'.$j;
310 }
311
312 $batch_line[$i]['detail'] = $sub_qty; // array of details
313 $batch_line[$i]['qty'] = $subtotalqty;
314 $batch_line[$i]['ix_l'] = GETPOST($idl, 'int');
315
316 $totalqty += $subtotalqty;
317 } else {
318 // No detail were provided for lots, so if a qty was provided, we can throw an error.
319 if (GETPOST($qty)) {
320 // We try to set an amount
321 // Case we dont use the list of available qty for each warehouse/lot
322 // GUI does not allow this yet
323 setEventMessages($langs->trans("StockIsRequiredToChooseWhichLotToUse").' ('.$langs->trans("Line").' '.GETPOST($idl, 'int').')', null, 'errors');
324 $error++;
325 }
326 }
327 } elseif (GETPOSTISSET($stockLocation)) {
328 //shipment line from multiple stock locations
329 $qty .= '_'.$j;
330 while (GETPOSTISSET($stockLocation)) {
331 // save sub line of warehouse
332 $stockLine[$i][$j]['qty'] = price2num(GETPOST($qty, 'alpha'), 'MS');
333 $stockLine[$i][$j]['warehouse_id'] = GETPOST($stockLocation, 'int');
334 $stockLine[$i][$j]['ix_l'] = GETPOST($idl, 'int');
335
336 $totalqty += price2num(GETPOST($qty, 'alpha'), 'MS');
337
338 $j++;
339 $stockLocation = "ent1".$i."_".$j;
340 $qty = "qtyl".$i.'_'.$j;
341 }
342 } else {
343 //shipment line for product with no batch management and no multiple stock location
344 if (GETPOST($qty, 'int') > 0) {
345 $totalqty += price2num(GETPOST($qty, 'alpha'), 'MS');
346 }
347 }
348
349 // Extrafields
350 $array_options[$i] = $extrafields->getOptionalsFromPost($object->table_element_line, $i);
351 // Unset extrafield
352 if (isset($extrafields->attributes[$object->table_element_line]['label']) && is_array($extrafields->attributes[$object->table_element_line]['label'])) {
353 // Get extra fields
354 foreach ($extrafields->attributes[$object->table_element_line]['label'] as $key => $value) {
355 unset($_POST["options_".$key]);
356 }
357 }
358 }
359
360 //var_dump($batch_line[2]);
361 if (($totalqty > 0 || getDolGlobalString('SHIPMENT_GETS_ALL_ORDER_PRODUCTS')) && !$error) { // There is at least one thing to ship and no error
362 for ($i = 0; $i < $num; $i++) {
363 $qty = "qtyl".$i;
364
365 if (!isset($batch_line[$i])) {
366 // not batch mode
367 if (isset($stockLine[$i])) {
368 //shipment from multiple stock locations
369 $nbstockline = count($stockLine[$i]);
370 for ($j = 0; $j < $nbstockline; $j++) {
371 if ($stockLine[$i][$j]['qty'] > 0 || ($stockLine[$i][$j]['qty'] == 0 && getDolGlobalString('SHIPMENT_GETS_ALL_ORDER_PRODUCTS'))) {
372 $ret = $object->addline($stockLine[$i][$j]['warehouse_id'], $stockLine[$i][$j]['ix_l'], $stockLine[$i][$j]['qty'], $array_options[$i]);
373 if ($ret < 0) {
374 setEventMessages($object->error, $object->errors, 'errors');
375 $error++;
376 }
377 }
378 }
379 } else {
380 if (GETPOST($qty, 'int') > 0 || getDolGlobalString('SHIPMENT_GETS_ALL_ORDER_PRODUCTS')) {
381 $ent = "entl".$i;
382 $idl = "idl".$i;
383 $entrepot_id = is_numeric(GETPOST($ent, 'int')) ?GETPOST($ent, 'int') : GETPOST('entrepot_id', 'int');
384 if ($entrepot_id < 0) {
385 $entrepot_id = '';
386 }
387 if (!($objectsrc->lines[$i]->fk_product > 0)) {
388 $entrepot_id = 0;
389 }
390
391 $ret = $object->addline($entrepot_id, GETPOST($idl, 'int'), price2num(GETPOST($qty, 'alpha'), 'MS'), $array_options[$i]);
392 if ($ret < 0) {
393 setEventMessages($object->error, $object->errors, 'errors');
394 $error++;
395 }
396 }
397 }
398 } else {
399 // batch mode
400 if ($batch_line[$i]['qty'] > 0 || ($batch_line[$i]['qty'] == 0 && getDolGlobalString('SHIPMENT_GETS_ALL_ORDER_PRODUCTS'))) {
401 $ret = $object->addline_batch($batch_line[$i], $array_options[$i]);
402 if ($ret < 0) {
403 setEventMessages($object->error, $object->errors, 'errors');
404 $error++;
405 }
406 }
407 }
408 }
409 // Fill array 'array_options' with data from add form
410 $ret = $extrafields->setOptionalsFromPost(null, $object);
411 if ($ret < 0) {
412 $error++;
413 }
414
415 if (!$error) {
416 $ret = $object->create($user); // This create shipment (like Odoo picking) and lines of shipments. Stock movement will be done when validating or closing shipment.
417 if ($ret <= 0) {
418 setEventMessages($object->error, $object->errors, 'errors');
419 $error++;
420 }
421 }
422 } elseif (!$error) {
423 $labelfieldmissing = $langs->transnoentitiesnoconv("QtyToShip");
424 if (isModEnabled('stock')) {
425 $labelfieldmissing .= '/'.$langs->transnoentitiesnoconv("Warehouse");
426 }
427 setEventMessages($langs->trans("ErrorFieldRequired", $labelfieldmissing), null, 'errors');
428 $error++;
429 }
430
431 if (!$error) {
432 $db->commit();
433 header("Location: card.php?id=".$object->id);
434 exit;
435 } else {
436 $db->rollback();
437 $_GET["commande_id"] = GETPOST('commande_id', 'int');
438 $action = 'create';
439 }
440 } elseif ($action == 'create_delivery' && getDolGlobalInt('MAIN_SUBMODULE_DELIVERY') && $user->rights->expedition->delivery->creer) {
441 // Build a receiving receipt
442 $db->begin();
443
444 $result = $object->create_delivery($user);
445 if ($result > 0) {
446 $db->commit();
447
448 header("Location: ".DOL_URL_ROOT.'/delivery/card.php?action=create_delivery&id='.$result);
449 exit;
450 } else {
451 $db->rollback();
452
453 setEventMessages($object->error, $object->errors, 'errors');
454 }
455 } elseif ($action == 'confirm_valid' && $confirm == 'yes' &&
456 ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->expedition->creer))
457 || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->expedition->shipping_advance->validate)))
458 ) {
459 $object->fetch_thirdparty();
460
461 $result = $object->valid($user);
462
463 if ($result < 0) {
464 setEventMessages($object->error, $object->errors, 'errors');
465 } else {
466 // Define output language
467 if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE)) {
468 $outputlangs = $langs;
469 $newlang = '';
470 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && GETPOST('lang_id', 'aZ09')) {
471 $newlang = GETPOST('lang_id', 'aZ09');
472 }
473 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
474 $newlang = $object->thirdparty->default_lang;
475 }
476 if (!empty($newlang)) {
477 $outputlangs = new Translate("", $conf);
478 $outputlangs->setDefaultLang($newlang);
479 }
480 $model = $object->model_pdf;
481 $ret = $object->fetch($id); // Reload to get new records
482
483 $result = $object->generateDocument($model, $outputlangs, $hidedetails, $hidedesc, $hideref);
484 if ($result < 0) {
485 dol_print_error($db, $result);
486 }
487 }
488 }
489 } elseif ($action == 'confirm_cancel' && $confirm == 'yes' && $user->rights->expedition->supprimer) {
490 $also_update_stock = (GETPOST('alsoUpdateStock', 'alpha') ? 1 : 0);
491 $result = $object->cancel(0, $also_update_stock);
492 if ($result > 0) {
493 $result = $object->setStatut(-1);
494 } else {
495 setEventMessages($object->error, $object->errors, 'errors');
496 }
497 } elseif ($action == 'confirm_delete' && $confirm == 'yes' && $user->rights->expedition->supprimer) {
498 $also_update_stock = (GETPOST('alsoUpdateStock', 'alpha') ? 1 : 0);
499 $result = $object->delete(0, $also_update_stock);
500 if ($result > 0) {
501 header("Location: ".DOL_URL_ROOT.'/expedition/index.php');
502 exit;
503 } else {
504 setEventMessages($object->error, $object->errors, 'errors');
505 }
506 // TODO add alternative status
507 //} elseif ($action == 'reopen' && (!empty($user->rights->expedition->creer) || !empty($user->rights->expedition->shipping_advance->validate)))
508 //{
509 // $result = $object->setStatut(0);
510 // if ($result < 0)
511 // {
512 // setEventMessages($object->error, $object->errors, 'errors');
513 // }
514 //}
515 } elseif ($action == 'setdate_livraison' && !empty($user->rights->expedition->creer)) {
516 $datedelivery = dol_mktime(GETPOST('liv_hour', 'int'), GETPOST('liv_min', 'int'), 0, GETPOST('liv_month', 'int'), GETPOST('liv_day', 'int'), GETPOST('liv_year', 'int'));
517
518 $object->fetch($id);
519 $result = $object->setDeliveryDate($user, $datedelivery);
520 if ($result < 0) {
521 setEventMessages($object->error, $object->errors, 'errors');
522 }
523 } elseif (($action == 'settracking_number'
524 || $action == 'settracking_url'
525 || $action == 'settrueWeight'
526 || $action == 'settrueWidth'
527 || $action == 'settrueHeight'
528 || $action == 'settrueDepth'
529 || $action == 'setshipping_method_id')
530 && $user->rights->expedition->creer
531 ) {
532 // Action update
533 $error = 0;
534
535 if ($action == 'settracking_number') {
536 $object->tracking_number = trim(GETPOST('tracking_number', 'alpha'));
537 }
538 if ($action == 'settracking_url') {
539 $object->tracking_url = trim(GETPOST('tracking_url', 'int'));
540 }
541 if ($action == 'settrueWeight') {
542 $object->trueWeight = trim(GETPOST('trueWeight', 'int'));
543 $object->weight_units = GETPOST('weight_units', 'int');
544 }
545 if ($action == 'settrueWidth') {
546 $object->trueWidth = trim(GETPOST('trueWidth', 'int'));
547 }
548 if ($action == 'settrueHeight') {
549 $object->trueHeight = trim(GETPOST('trueHeight', 'int'));
550 $object->size_units = GETPOST('size_units', 'int');
551 }
552 if ($action == 'settrueDepth') {
553 $object->trueDepth = trim(GETPOST('trueDepth', 'int'));
554 }
555 if ($action == 'setshipping_method_id') {
556 $object->shipping_method_id = trim(GETPOST('shipping_method_id', 'int'));
557 }
558
559 if (!$error) {
560 if ($object->update($user) >= 0) {
561 header("Location: card.php?id=".$object->id);
562 exit;
563 }
564 setEventMessages($object->error, $object->errors, 'errors');
565 }
566
567 $action = "";
568 } elseif ($action == 'classifybilled') {
569 $object->fetch($id);
570 $result = $object->setBilled();
571 if ($result >= 0) {
572 header('Location: '.$_SERVER["PHP_SELF"].'?id='.$object->id);
573 exit();
574 }
575 setEventMessages($object->error, $object->errors, 'errors');
576 } elseif ($action == 'classifyclosed') {
577 $object->fetch($id);
578 $result = $object->setClosed();
579 if ($result >= 0) {
580 header('Location: '.$_SERVER["PHP_SELF"].'?id='.$object->id);
581 exit();
582 }
583 setEventMessages($object->error, $object->errors, 'errors');
584 } elseif ($action == 'deleteline' && !empty($line_id)) {
585 // delete a line
586 $object->fetch($id);
587 $lines = $object->lines;
588 $line = new ExpeditionLigne($db);
589 $line->fk_expedition = $object->id;
590
591 $num_prod = count($lines);
592 for ($i = 0; $i < $num_prod; $i++) {
593 if ($lines[$i]->id == $line_id) {
594 if (count($lines[$i]->details_entrepot) > 1) {
595 // delete multi warehouse lines
596 foreach ($lines[$i]->details_entrepot as $details_entrepot) {
597 $line->id = $details_entrepot->line_id;
598 if (!$error && $line->delete($user) < 0) {
599 $error++;
600 }
601 }
602 } else {
603 // delete single warehouse line
604 $line->id = $line_id;
605 if (!$error && $line->delete($user) < 0) {
606 $error++;
607 }
608 }
609 }
610 unset($_POST["lineid"]);
611 }
612
613 if (!$error) {
614 header('Location: '.$_SERVER["PHP_SELF"].'?id='.$object->id);
615 exit();
616 } else {
617 setEventMessages($line->error, $line->errors, 'errors');
618 }
619 } elseif ($action == 'updateline' && $user->rights->expedition->creer && GETPOST('save')) {
620 // Update a line
621 // Clean parameters
622 $qty = 0;
623 $entrepot_id = 0;
624 $batch_id = 0;
625
626 $lines = $object->lines;
627 $num_prod = count($lines);
628 for ($i = 0; $i < $num_prod; $i++) {
629 if ($lines[$i]->id == $line_id) { // we have found line to update
630 $update_done = false;
631 $line = new ExpeditionLigne($db);
632 $line->fk_expedition = $object->id;
633
634 // Extrafields Lines
635 $line->array_options = $extrafields->getOptionalsFromPost($object->table_element_line);
636 // Unset extrafield POST Data
637 if (is_array($extrafields->attributes[$object->table_element_line]['label'])) {
638 foreach ($extrafields->attributes[$object->table_element_line]['label'] as $key => $value) {
639 unset($_POST["options_".$key]);
640 }
641 }
642 $line->fk_product = $lines[$i]->fk_product;
643 if (is_array($lines[$i]->detail_batch) && count($lines[$i]->detail_batch) > 0) {
644 // line with lot
645 foreach ($lines[$i]->detail_batch as $detail_batch) {
646 $lotStock = new Productbatch($db);
647 $batch = "batchl".$detail_batch->fk_expeditiondet."_".$detail_batch->fk_origin_stock;
648 $qty = "qtyl".$detail_batch->fk_expeditiondet.'_'.$detail_batch->id;
649 $batch_id = GETPOST($batch, 'int');
650 $batch_qty = GETPOST($qty, 'int');
651 if (!empty($batch_id)) {
652 if ($lotStock->fetch($batch_id) > 0 && $line->fetch($detail_batch->fk_expeditiondet) > 0) { // $line is ExpeditionLine
653 if ($lines[$i]->entrepot_id != 0) {
654 // allow update line entrepot_id if not multi warehouse shipping
655 $line->entrepot_id = $lotStock->warehouseid;
656 }
657
658 // detail_batch can be an object with keys, or an array of ExpeditionLineBatch
659 if (empty($line->detail_batch)) {
660 $line->detail_batch = new stdClass();
661 }
662
663 $line->detail_batch->fk_origin_stock = $batch_id;
664 $line->detail_batch->batch = $lotStock->batch;
665 $line->detail_batch->id = $detail_batch->id;
666 $line->detail_batch->entrepot_id = $lotStock->warehouseid;
667 $line->detail_batch->qty = $batch_qty;
668 if ($line->update($user) < 0) {
669 setEventMessages($line->error, $line->errors, 'errors');
670 $error++;
671 } else {
672 $update_done=true;
673 }
674 } else {
675 setEventMessages($lotStock->error, $lotStock->errors, 'errors');
676 $error++;
677 }
678 }
679 unset($_POST[$batch]);
680 unset($_POST[$qty]);
681 }
682 // add new batch
683 $lotStock = new Productbatch($db);
684 $batch = "batchl".$line_id."_0";
685 $qty = "qtyl".$line_id."_0";
686 $batch_id = GETPOST($batch, 'int');
687 $batch_qty = GETPOST($qty, 'int');
688 $lineIdToAddLot = 0;
689 if ($batch_qty > 0 && !empty($batch_id)) {
690 if ($lotStock->fetch($batch_id) > 0) {
691 // check if lotStock warehouse id is same as line warehouse id
692 if ($lines[$i]->entrepot_id > 0) {
693 // single warehouse shipment line
694 if ($lines[$i]->entrepot_id == $lotStock->warehouseid) {
695 $lineIdToAddLot = $line_id;
696 }
697 } elseif (count($lines[$i]->details_entrepot) > 1) {
698 // multi warehouse shipment lines
699 foreach ($lines[$i]->details_entrepot as $detail_entrepot) {
700 if ($detail_entrepot->entrepot_id == $lotStock->warehouseid) {
701 $lineIdToAddLot = $detail_entrepot->line_id;
702 }
703 }
704 }
705 if ($lineIdToAddLot) {
706 // add lot to existing line
707 if ($line->fetch($lineIdToAddLot) > 0) {
708 $line->detail_batch->fk_origin_stock = $batch_id;
709 $line->detail_batch->batch = $lotStock->batch;
710 $line->detail_batch->entrepot_id = $lotStock->warehouseid;
711 $line->detail_batch->qty = $batch_qty;
712 if ($line->update($user) < 0) {
713 setEventMessages($line->error, $line->errors, 'errors');
714 $error++;
715 } else {
716 $update_done=true;
717 }
718 } else {
719 setEventMessages($line->error, $line->errors, 'errors');
720 $error++;
721 }
722 } else {
723 // create new line with new lot
724 $line->origin_line_id = $lines[$i]->origin_line_id;
725 $line->entrepot_id = $lotStock->warehouseid;
726 $line->detail_batch[0] = new ExpeditionLineBatch($db);
727 $line->detail_batch[0]->fk_origin_stock = $batch_id;
728 $line->detail_batch[0]->batch = $lotStock->batch;
729 $line->detail_batch[0]->entrepot_id = $lotStock->warehouseid;
730 $line->detail_batch[0]->qty = $batch_qty;
731 if ($object->create_line_batch($line, $line->array_options) < 0) {
732 setEventMessages($object->error, $object->errors, 'errors');
733 $error++;
734 } else {
735 $update_done=true;
736 }
737 }
738 } else {
739 setEventMessages($lotStock->error, $lotStock->errors, 'errors');
740 $error++;
741 }
742 }
743 } else {
744 if ($lines[$i]->fk_product > 0) {
745 // line without lot
746 if ($lines[$i]->entrepot_id > 0) {
747 // single warehouse shipment line
748 $stockLocation = "entl".$line_id;
749 $qty = "qtyl".$line_id;
750 $line->id = $line_id;
751 $line->entrepot_id = GETPOST($stockLocation, 'int');
752 $line->qty = GETPOST($qty, 'int');
753 if ($line->update($user) < 0) {
754 setEventMessages($line->error, $line->errors, 'errors');
755 $error++;
756 }
757 unset($_POST[$stockLocation]);
758 unset($_POST[$qty]);
759 } elseif (count($lines[$i]->details_entrepot) > 1) {
760 // multi warehouse shipment lines
761 foreach ($lines[$i]->details_entrepot as $detail_entrepot) {
762 if (!$error) {
763 $stockLocation = "entl".$detail_entrepot->line_id;
764 $qty = "qtyl".$detail_entrepot->line_id;
765 $warehouse = GETPOST($stockLocation, 'int');
766 if (!empty($warehouse)) {
767 $line->id = $detail_entrepot->line_id;
768 $line->entrepot_id = $warehouse;
769 $line->qty = GETPOST($qty, 'int');
770 if ($line->update($user) < 0) {
771 setEventMessages($line->error, $line->errors, 'errors');
772 $error++;
773 } else {
774 $update_done=true;
775 }
776 }
777 unset($_POST[$stockLocation]);
778 unset($_POST[$qty]);
779 }
780 }
781 } elseif (!isModEnabled('stock') && empty($conf->productbatch->enabled)) { // both product batch and stock are not activated.
782 $qty = "qtyl".$line_id;
783 $line->id = $line_id;
784 $line->qty = GETPOST($qty, 'int');
785 $line->entrepot_id = 0;
786 if ($line->update($user) < 0) {
787 setEventMessages($line->error, $line->errors, 'errors');
788 $error++;
789 } else {
790 $update_done=true;
791 }
792 unset($_POST[$qty]);
793 }
794 } else {
795 // Product no predefined
796 $qty = "qtyl".$line_id;
797 $line->id = $line_id;
798 $line->qty = GETPOST($qty, 'int');
799 $line->entrepot_id = 0;
800 if ($line->update($user) < 0) {
801 setEventMessages($line->error, $line->errors, 'errors');
802 $error++;
803 } else {
804 $update_done=true;
805 }
806 unset($_POST[$qty]);
807 }
808 }
809
810 if (empty($update_done)) {
811 $line->id = $lines[$i]->id;
812 $line->insertExtraFields();
813 }
814 }
815 }
816
817 unset($_POST["lineid"]);
818
819 if (!$error) {
820 if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE)) {
821 // Define output language
822 $outputlangs = $langs;
823 $newlang = '';
824 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && GETPOST('lang_id', 'aZ09')) {
825 $newlang = GETPOST('lang_id', 'aZ09');
826 }
827 if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
828 $newlang = $object->thirdparty->default_lang;
829 }
830 if (!empty($newlang)) {
831 $outputlangs = new Translate("", $conf);
832 $outputlangs->setDefaultLang($newlang);
833 }
834
835 $ret = $object->fetch($object->id); // Reload to get new records
836 $object->generateDocument($object->model_pdf, $outputlangs, $hidedetails, $hidedesc, $hideref);
837 }
838 } else {
839 header('Location: '.$_SERVER['PHP_SELF'].'?id='.$object->id); // To redisplay the form being edited
840 exit();
841 }
842 } elseif ($action == 'updateline' && $user->rights->expedition->creer && GETPOST('cancel', 'alpha') == $langs->trans("Cancel")) {
843 header('Location: '.$_SERVER['PHP_SELF'].'?id='.$object->id); // To redisplay the form being edited
844 exit();
845 }
846
847 include DOL_DOCUMENT_ROOT.'/core/actions_printing.inc.php';
848
849 // Actions to send emails
850 if (empty($id)) {
851 $id = $facid;
852 }
853 $triggersendname = 'SHIPPING_SENTBYMAIL';
854 $paramname = 'id';
855 $mode = 'emailfromshipment';
856 $trackid = 'shi'.$object->id;
857 include DOL_DOCUMENT_ROOT.'/core/actions_sendmails.inc.php';
858}
859
860
861/*
862 * View
863 */
864
865$title = $object->ref.' - '.$langs->trans("Shipment");
866if ($action == 'create2') {
867 $title = $langs->trans("CreateShipment");
868}
869$help_url = 'EN:Module_Shipments|FR:Module_Expéditions|ES:M&oacute;dulo_Expediciones|DE:Modul_Lieferungen';
870
871llxHeader('', $title, $help_url);
872
873if (empty($action)) {
874 $action = 'view';
875}
876
877$form = new Form($db);
878$formfile = new FormFile($db);
879$formproduct = new FormProduct($db);
880if (isModEnabled('project')) {
881 $formproject = new FormProjets($db);
882}
883
884$product_static = new Product($db);
885$shipment_static = new Expedition($db);
886$warehousestatic = new Entrepot($db);
887
888if ($action == 'create2') {
889 print load_fiche_titre($langs->trans("CreateShipment"), '', 'dolly');
890
891 print '<br>'.$langs->trans("ShipmentCreationIsDoneFromOrder");
892 $action = ''; $id = ''; $ref = '';
893}
894
895// Mode creation.
896if ($action == 'create') {
897 $expe = new Expedition($db);
898
899 print load_fiche_titre($langs->trans("CreateShipment"), '', 'dolly');
900
901 if (!$origin) {
902 setEventMessages($langs->trans("ErrorBadParameters"), null, 'errors');
903 }
904
905 if ($origin) {
906 $classname = ucfirst($origin);
907
908 $object = new $classname($db);
909 if ($object->fetch($origin_id)) { // This include the fetch_lines
910 $soc = new Societe($db);
911 $soc->fetch($object->socid);
912
913 $author = new User($db);
914 $author->fetch($object->user_author_id);
915
916 if (isModEnabled('stock')) {
917 $entrepot = new Entrepot($db);
918 }
919
920 print '<form action="'.$_SERVER["PHP_SELF"].'" method="post">';
921 print '<input type="hidden" name="token" value="'.newToken().'">';
922 print '<input type="hidden" name="action" value="add">';
923 print '<input type="hidden" name="origin" value="'.$origin.'">';
924 print '<input type="hidden" name="origin_id" value="'.$object->id.'">';
925 if (GETPOST('entrepot_id', 'int')) {
926 print '<input type="hidden" name="entrepot_id" value="'.GETPOST('entrepot_id', 'int').'">';
927 }
928
929 print dol_get_fiche_head('');
930
931 print '<table class="border centpercent">';
932
933 // Ref
934 print '<tr><td class="titlefieldcreate fieldrequired">';
935 if ($origin == 'commande' && isModEnabled('commande')) {
936 print $langs->trans("RefOrder");
937 }
938 if ($origin == 'propal' && isModEnabled("propal")) {
939 print $langs->trans("RefProposal");
940 }
941 print '</td><td colspan="3">';
942 print $object->getNomUrl(1);
943 print '</td>';
944 print "</tr>\n";
945
946 // Ref client
947 print '<tr><td>';
948 if ($origin == 'commande') {
949 print $langs->trans('RefCustomerOrder');
950 } elseif ($origin == 'propal') {
951 print $langs->trans('RefCustomerOrder');
952 } else {
953 print $langs->trans('RefCustomer');
954 }
955 print '</td><td colspan="3">';
956 print '<input type="text" name="ref_customer" value="'.$object->ref_client.'" />';
957 print '</td>';
958 print '</tr>';
959
960 // Tiers
961 print '<tr><td class="titlefieldcreate fieldrequired">'.$langs->trans('Company').'</td>';
962 print '<td colspan="3">'.$soc->getNomUrl(1).'</td>';
963 print '</tr>';
964
965 // Project
966 if (isModEnabled('project')) {
967 $projectid = GETPOST('projectid', 'int') ?GETPOST('projectid', 'int') : 0;
968 if (empty($projectid) && !empty($object->fk_project)) {
969 $projectid = $object->fk_project;
970 }
971 if ($origin == 'project') {
972 $projectid = ($originid ? $originid : 0);
973 }
974
975 $langs->load("projects");
976 print '<tr>';
977 print '<td>'.$langs->trans("Project").'</td><td colspan="2">';
978 print img_picto('', 'project', 'class="pictofixedwidth"');
979 $numprojet = $formproject->select_projects($soc->id, $projectid, 'projectid', 0);
980 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>';
981 print '</td>';
982 print '</tr>';
983 }
984
985 // Date delivery planned
986 print '<tr><td>'.$langs->trans("DateDeliveryPlanned").'</td>';
987 print '<td colspan="3">';
988 print img_picto('', 'action', 'class="pictofixedwidth"');
989 $date_delivery = ($date_delivery ? $date_delivery : $object->delivery_date); // $date_delivery comes from GETPOST
990 print $form->selectDate($date_delivery ? $date_delivery : -1, 'date_delivery', 1, 1, 1);
991 print "</td>\n";
992 print '</tr>';
993
994 // Note Public
995 print '<tr><td>'.$langs->trans("NotePublic").'</td>';
996 print '<td colspan="3">';
997 $doleditor = new DolEditor('note_public', $object->note_public, '', 60, 'dolibarr_notes', 'In', 0, false, empty($conf->global->FCKEDITOR_ENABLE_NOTE_PUBLIC) ? 0 : 1, ROWS_3, '90%');
998 print $doleditor->Create(1);
999 print "</td></tr>";
1000
1001 // Note Private
1002 if ($object->note_private && !$user->socid) {
1003 print '<tr><td>'.$langs->trans("NotePrivate").'</td>';
1004 print '<td colspan="3">';
1005 $doleditor = new DolEditor('note_private', $object->note_private, '', 60, 'dolibarr_notes', 'In', 0, false, empty($conf->global->FCKEDITOR_ENABLE_NOTE_PRIVATE) ? 0 : 1, ROWS_3, '90%');
1006 print $doleditor->Create(1);
1007 print "</td></tr>";
1008 }
1009
1010 // Weight
1011 print '<tr><td>';
1012 print $langs->trans("Weight");
1013 print '</td><td colspan="3">';
1014 print img_picto('', 'fa-balance-scale', 'class="pictofixedwidth"');
1015 print '<input name="weight" size="4" value="'.GETPOST('weight', 'int').'"> ';
1016 $text = $formproduct->selectMeasuringUnits("weight_units", "weight", GETPOST('weight_units', 'int'), 0, 2);
1017 $htmltext = $langs->trans("KeepEmptyForAutoCalculation");
1018 print $form->textwithpicto($text, $htmltext);
1019 print '</td></tr>';
1020 // Dim
1021 print '<tr><td>';
1022 print $langs->trans("Width").' x '.$langs->trans("Height").' x '.$langs->trans("Depth");
1023 print ' </td><td colspan="3">';
1024 print img_picto('', 'fa-ruler', 'class="pictofixedwidth"');
1025 print '<input name="sizeW" size="4" value="'.GETPOST('sizeW', 'int').'">';
1026 print ' x <input name="sizeH" size="4" value="'.GETPOST('sizeH', 'int').'">';
1027 print ' x <input name="sizeS" size="4" value="'.GETPOST('sizeS', 'int').'">';
1028 print ' ';
1029 $text = $formproduct->selectMeasuringUnits("size_units", "size", GETPOST('size_units', 'int'), 0, 2);
1030 $htmltext = $langs->trans("KeepEmptyForAutoCalculation");
1031 print $form->textwithpicto($text, $htmltext);
1032 print '</td></tr>';
1033
1034 // Delivery method
1035 print "<tr><td>".$langs->trans("DeliveryMethod")."</td>";
1036 print '<td colspan="3">';
1037 $expe->fetch_delivery_methods();
1038 print img_picto('', 'dolly', 'class="pictofixedwidth"');
1039 print $form->selectarray("shipping_method_id", $expe->meths, GETPOST('shipping_method_id', 'int'), 1, 0, 0, "", 1);
1040 if ($user->admin) {
1041 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
1042 }
1043 print "</td></tr>\n";
1044
1045 // Tracking number
1046 print "<tr><td>".$langs->trans("TrackingNumber")."</td>";
1047 print '<td colspan="3">';
1048 print img_picto('', 'barcode', 'class="pictofixedwidth"');
1049 print '<input name="tracking_number" size="20" value="'.GETPOST('tracking_number', 'alpha').'">';
1050 print "</td></tr>\n";
1051
1052 // Other attributes
1053 $parameters = array('objectsrc' => isset($objectsrc) ? $objectsrc : '', 'colspan' => ' colspan="3"', 'cols' => '3', 'socid' => $socid);
1054 $reshook = $hookmanager->executeHooks('formObjectOptions', $parameters, $expe, $action); // Note that $action and $object may have been modified by hook
1055 print $hookmanager->resPrint;
1056
1057 if (empty($reshook)) {
1058 // copy from order
1059 if ($object->fetch_optionals() > 0) {
1060 $expe->array_options = array_merge($expe->array_options, $object->array_options);
1061 }
1062 print $expe->showOptionals($extrafields, 'edit', $parameters);
1063 }
1064
1065
1066 // Incoterms
1067 if (isModEnabled('incoterm')) {
1068 print '<tr>';
1069 print '<td><label for="incoterm_id">'.$form->textwithpicto($langs->trans("IncotermLabel"), $object->label_incoterms, 1).'</label></td>';
1070 print '<td colspan="3" class="maxwidthonsmartphone">';
1071 print img_picto('', 'incoterm', 'class="pictofixedwidth"');
1072 print $form->select_incoterms((!empty($object->fk_incoterms) ? $object->fk_incoterms : ''), (!empty($object->location_incoterms) ? $object->location_incoterms : ''));
1073 print '</td></tr>';
1074 }
1075
1076 // Document model
1077 include_once DOL_DOCUMENT_ROOT.'/core/modules/expedition/modules_expedition.php';
1079 if (count($list) > 1) {
1080 print "<tr><td>".$langs->trans("DefaultModel")."</td>";
1081 print '<td colspan="3">';
1082 print img_picto('', 'pdf', 'class="pictofixedwidth"');
1083 print $form->selectarray('model', $list, $conf->global->EXPEDITION_ADDON_PDF);
1084 print "</td></tr>\n";
1085 }
1086
1087 print "</table>";
1088
1089 print dol_get_fiche_end();
1090
1091
1092 // Shipment lines
1093
1094 $numAsked = count($object->lines);
1095
1096 print '<script type="text/javascript">'."\n";
1097 print 'jQuery(document).ready(function() {'."\n";
1098 print 'jQuery("#autofill").click(function() {';
1099 $i = 0;
1100 while ($i < $numAsked) {
1101 print 'jQuery("#qtyl'.$i.'").val(jQuery("#qtyasked'.$i.'").val() - jQuery("#qtydelivered'.$i.'").val());'."\n";
1102 if (isModEnabled('productbatch')) {
1103 print 'jQuery("#qtyl'.$i.'_'.$i.'").val(jQuery("#qtyasked'.$i.'").val() - jQuery("#qtydelivered'.$i.'").val());'."\n";
1104 }
1105 $i++;
1106 }
1107 print 'return false; });'."\n";
1108 print 'jQuery("#autoreset").click(function() { console.log("Reset values to 0"); jQuery(".qtyl").val(0);'."\n";
1109 print 'return false; });'."\n";
1110 print '});'."\n";
1111 print '</script>'."\n";
1112
1113 print '<br>';
1114
1115 print '<table class="noborder centpercent">';
1116
1117 // Load shipments already done for same order
1118 $object->loadExpeditions();
1119
1120
1121 $alreadyQtyBatchSetted = $alreadyQtySetted = array();
1122
1123 if ($numAsked) {
1124 print '<tr class="liste_titre">';
1125 print '<td>'.$langs->trans("Description").'</td>';
1126 print '<td class="center">'.$langs->trans("QtyOrdered").'</td>';
1127 print '<td class="center">'.$langs->trans("QtyShipped").'</td>';
1128 print '<td class="center">'.$langs->trans("QtyToShip");
1129 if (empty($conf->productbatch->enabled)) {
1130 print '<br><a href="#" id="autofill" class="opacitymedium link cursor cursorpointer">'.img_picto($langs->trans("Autofill"), 'autofill', 'class="paddingrightonly"').'</a>';
1131 print ' / ';
1132 } else {
1133 print '<br>';
1134 }
1135 print '<span id="autoreset" class="opacitymedium link cursor cursorpointer">'.img_picto($langs->trans("Reset"), 'eraser').'</span>';
1136 print '</td>';
1137 if (isModEnabled('stock')) {
1138 if (empty($conf->productbatch->enabled)) {
1139 print '<td class="left">'.$langs->trans("Warehouse").' ('.$langs->trans("Stock").')</td>';
1140 } else {
1141 print '<td class="left">'.$langs->trans("Warehouse").' / '.$langs->trans("Batch").' ('.$langs->trans("Stock").')</td>';
1142 }
1143 }
1144 print "</tr>\n";
1145 }
1146
1147 $warehouse_id = GETPOST('entrepot_id', 'int');
1148 $warehousePicking = array();
1149 // get all warehouse children for picking
1150 if ($warehouse_id > 0) {
1151 $warehousePicking[] = $warehouse_id;
1152 $warehouseObj = new Entrepot($db);
1153 $warehouseObj->get_children_warehouses($warehouse_id, $warehousePicking);
1154 }
1155
1156 $indiceAsked = 0;
1157 while ($indiceAsked < $numAsked) {
1158 $product = new Product($db);
1159
1160 $line = $object->lines[$indiceAsked];
1161
1162 $parameters = array('i' => $indiceAsked, 'line' => $line, 'num' => $numAsked);
1163 $reshook = $hookmanager->executeHooks('printObjectLine', $parameters, $object, $action);
1164 if ($reshook < 0) {
1165 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
1166 }
1167
1168 if (empty($reshook)) {
1169 // Show product and description
1170 $type = $line->product_type ? $line->product_type : $line->fk_product_type;
1171 // Try to enhance type detection using date_start and date_end for free lines where type
1172 // was not saved.
1173 if (!empty($line->date_start)) {
1174 $type = 1;
1175 }
1176 if (!empty($line->date_end)) {
1177 $type = 1;
1178 }
1179
1180 print '<!-- line for order line '.$line->id.' -->'."\n";
1181 print '<tr class="oddeven" id="row-'.$line->id.'">'."\n";
1182
1183 // Product label
1184 if ($line->fk_product > 0) { // If predefined product
1185 $res = $product->fetch($line->fk_product);
1186 if ($res < 0) {
1187 dol_print_error($db, $product->error, $product->errors);
1188 }
1189 $product->load_stock('warehouseopen'); // Load all $product->stock_warehouse[idwarehouse]->detail_batch
1190 //var_dump($product->stock_warehouse[1]);
1191
1192 print '<td>';
1193 print '<a name="'.$line->id.'"></a>'; // ancre pour retourner sur la ligne
1194
1195 // Show product and description
1196 $product_static->type = $line->fk_product_type;
1197 $product_static->id = $line->fk_product;
1198 $product_static->ref = $line->ref;
1199 $product_static->status = $line->product_tosell;
1200 $product_static->status_buy = $line->product_tobuy;
1201 $product_static->status_batch = $line->product_tobatch;
1202
1203 $showdescinproductdesc = getDolGlobalString('PRODUIT_DESC_IN_FORM_ACCORDING_TO_DEVICE');
1204
1205 $text = $product_static->getNomUrl(1);
1206 $text .= ' - '.(!empty($line->label) ? $line->label : $line->product_label);
1207 $description = ($showdescinproductdesc ? '' : dol_htmlentitiesbr($line->desc));
1208
1209 print $form->textwithtooltip($text, $description, 3, '', '', $i);
1210
1211 // Show range
1212 print_date_range($db->jdate($line->date_start), $db->jdate($line->date_end));
1213
1214 // Add description in form
1215 if ($showdescinproductdesc) {
1216 print ($line->desc && $line->desc != $line->product_label) ? '<br>'.dol_htmlentitiesbr($line->desc) : '';
1217 }
1218
1219 print '</td>';
1220 } else {
1221 print "<td>";
1222 if ($type == 1) {
1223 $text = img_object($langs->trans('Service'), 'service');
1224 } else {
1225 $text = img_object($langs->trans('Product'), 'product');
1226 }
1227
1228 if (!empty($line->label)) {
1229 $text .= ' <strong>'.$line->label.'</strong>';
1230 print $form->textwithtooltip($text, $line->desc, 3, '', '', $i);
1231 } else {
1232 print $text.' '.nl2br($line->desc);
1233 }
1234
1235 // Show range
1236 print_date_range($db->jdate($line->date_start), $db->jdate($line->date_end));
1237 print "</td>\n";
1238 }
1239
1240 // unit of order
1241 $unit_order = '';
1242 if (!empty($conf->global->PRODUCT_USE_UNITS)) {
1243 $unit_order = measuringUnitString($line->fk_unit);
1244 }
1245
1246 // Qty
1247 print '<td class="center">'.$line->qty;
1248 print '<input name="qtyasked'.$indiceAsked.'" id="qtyasked'.$indiceAsked.'" type="hidden" value="'.$line->qty.'">';
1249 print ''.$unit_order.'</td>';
1250 $qtyProdCom = $line->qty;
1251
1252 // Qty already shipped
1253 print '<td class="center">';
1254 $quantityDelivered = isset($object->expeditions[$line->id]) ? $object->expeditions[$line->id] : '';
1255 print $quantityDelivered;
1256 print '<input name="qtydelivered'.$indiceAsked.'" id="qtydelivered'.$indiceAsked.'" type="hidden" value="'.$quantityDelivered.'">';
1257 print ''.$unit_order.'</td>';
1258
1259 // Qty to ship
1260 $quantityAsked = $line->qty;
1261 if ($line->product_type == 1 && empty($conf->global->STOCK_SUPPORTS_SERVICES)) {
1262 $quantityToBeDelivered = 0;
1263 } else {
1264 if (is_numeric($quantityDelivered)) {
1265 $quantityToBeDelivered = $quantityAsked - $quantityDelivered;
1266 } else {
1267 $quantityToBeDelivered = $quantityAsked;
1268 }
1269 }
1270
1271 $warehouseObject = null;
1272 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
1273 print '<!-- Case warehouse already known or product not a predefined product -->';
1274 //ship from preselected location
1275 $stock = + (isset($product->stock_warehouse[$warehouse_id]->real) ? $product->stock_warehouse[$warehouse_id]->real : 0); // Convert to number
1276 $deliverableQty = min($quantityToBeDelivered, $stock);
1277 if ($deliverableQty < 0) {
1278 $deliverableQty = 0;
1279 }
1280 if (empty($conf->productbatch->enabled) || !$product->hasbatch()) {
1281 // Quantity to send
1282 print '<td class="center">';
1283 if ($line->product_type == Product::TYPE_PRODUCT || !empty($conf->global->STOCK_SUPPORTS_SERVICES)) {
1284 if (GETPOST('qtyl'.$indiceAsked, 'int')) {
1285 $deliverableQty = GETPOST('qtyl'.$indiceAsked, 'int');
1286 }
1287 print '<input name="idl'.$indiceAsked.'" type="hidden" value="'.$line->id.'">';
1288 print '<input name="qtyl'.$indiceAsked.'" id="qtyl'.$indiceAsked.'" class="qtyl center" type="text" size="4" value="'.$deliverableQty.'">';
1289 } else {
1290 if (getDolGlobalString('SHIPMENT_GETS_ALL_ORDER_PRODUCTS')) {
1291 print '<input name="idl'.$indiceAsked.'" type="hidden" value="'.$line->id.'">';
1292 print '<input name="qtyl'.$indiceAsked.'" id="qtyl'.$indiceAsked.'" type="hidden" value="0">';
1293 }
1294
1295 print $langs->trans("NA");
1296 }
1297 print '</td>';
1298
1299 // Stock
1300 if (isModEnabled('stock')) {
1301 print '<td class="left">';
1302 if ($line->product_type == Product::TYPE_PRODUCT || !empty($conf->global->STOCK_SUPPORTS_SERVICES)) { // Type of product need stock change ?
1303 // Show warehouse combo list
1304 $ent = "entl".$indiceAsked;
1305 $idl = "idl".$indiceAsked;
1306 $tmpentrepot_id = is_numeric(GETPOST($ent, 'int')) ?GETPOST($ent, 'int') : $warehouse_id;
1307 if ($line->fk_product > 0) {
1308 print '<!-- Show warehouse selection -->';
1309
1310 $stockMin = false;
1311 if (!getDolGlobalInt('STOCK_ALLOW_NEGATIVE_TRANSFER')) {
1312 $stockMin = 0;
1313 }
1314 print $formproduct->selectWarehouses($tmpentrepot_id, 'entl'.$indiceAsked, '', 1, 0, $line->fk_product, '', 1, 0, array(), 'minwidth200', '', 1, $stockMin, 'stock DESC, e.ref');
1315
1316 if ($tmpentrepot_id > 0 && $tmpentrepot_id == $warehouse_id) {
1317 //print $stock.' '.$quantityToBeDelivered;
1318 if ($stock < $quantityToBeDelivered) {
1319 print ' '.img_warning($langs->trans("StockTooLow")); // Stock too low for this $warehouse_id but you can change warehouse
1320 }
1321 }
1322 }
1323 } else {
1324 print $langs->trans("Service");
1325 }
1326 print '</td>';
1327 }
1328
1329 print "</tr>\n";
1330
1331 // Show subproducts of product
1332 if (!empty($conf->global->PRODUIT_SOUSPRODUITS) && $line->fk_product > 0) {
1333 $product->get_sousproduits_arbo();
1334 $prods_arbo = $product->get_arbo_each_prod($qtyProdCom);
1335 if (count($prods_arbo) > 0) {
1336 foreach ($prods_arbo as $key => $value) {
1337 //print $value[0];
1338 $img = '';
1339 if ($value['stock'] < $value['stock_alert']) {
1340 $img = img_warning($langs->trans("StockTooLow"));
1341 }
1342 print "<tr class=\"oddeven\"><td>&nbsp; &nbsp; &nbsp; ->
1343 <a href=\"".DOL_URL_ROOT."/product/card.php?id=".$value['id']."\">".$value['fullpath']."
1344 </a> (".$value['nb'].")</td><td class=\"center\"> ".$value['nb_total']."</td><td>&nbsp;</td><td>&nbsp;</td>
1345 <td class=\"center\">".$value['stock']." ".$img."</td></tr>";
1346 }
1347 }
1348 }
1349 } else {
1350 // Product need lot
1351 print '<td></td><td></td></tr>'; // end line and start a new one for lot/serial
1352 print '<!-- Case product need lot -->';
1353
1354 $staticwarehouse = new Entrepot($db);
1355 if ($warehouse_id > 0) {
1356 $staticwarehouse->fetch($warehouse_id);
1357 }
1358
1359 $subj = 0;
1360 // Define nb of lines suggested for this order line
1361 $nbofsuggested = 0;
1362 if (is_object($product->stock_warehouse[$warehouse_id]) && count($product->stock_warehouse[$warehouse_id]->detail_batch)) {
1363 foreach ($product->stock_warehouse[$warehouse_id]->detail_batch as $dbatch) {
1364 $nbofsuggested++;
1365 }
1366 }
1367 print '<input name="idl'.$indiceAsked.'" type="hidden" value="'.$line->id.'">';
1368 if (is_object($product->stock_warehouse[$warehouse_id]) && count($product->stock_warehouse[$warehouse_id]->detail_batch)) {
1369 foreach ($product->stock_warehouse[$warehouse_id]->detail_batch as $dbatch) { // $dbatch is instance of Productbatch
1370 //var_dump($dbatch);
1371 $batchStock = + $dbatch->qty; // To get a numeric
1372 $deliverableQty = min($quantityToBeDelivered, $batchStock);
1373
1374 // Now we will check if we have to reduce the deliverableQty by taking into account the qty already suggested in previous line
1375 if (isset($alreadyQtyBatchSetted[$line->fk_product][$dbatch->batch][intval($warehouse_id)])) {
1376 $deliverableQty = min($quantityToBeDelivered, $batchStock - $alreadyQtyBatchSetted[$line->fk_product][$dbatch->batch][intval($warehouse_id)]);
1377 } else {
1378 if (!isset($alreadyQtyBatchSetted[$line->fk_product])) {
1379 $alreadyQtyBatchSetted[$line->fk_product] = array();
1380 }
1381
1382 if (!isset($alreadyQtyBatchSetted[$line->fk_product][$dbatch->batch])) {
1383 $alreadyQtyBatchSetted[$line->fk_product][$dbatch->batch] = array();
1384 }
1385
1386 $deliverableQty = min($quantityToBeDelivered, $batchStock);
1387 }
1388
1389 if ($deliverableQty < 0) $deliverableQty = 0;
1390
1391 $inputName = 'qtyl'.$indiceAsked.'_'.$subj;
1392 if (GETPOSTISSET($inputName)) {
1393 $deliverableQty = GETPOST($inputName, 'int');
1394 }
1395
1396 $tooltipClass = $tooltipTitle = '';
1397 if (!empty($alreadyQtyBatchSetted[$line->fk_product][$dbatch->batch][intval($warehouse_id)])) {
1398 $tooltipClass = ' classfortooltip';
1399 $tooltipTitle = $langs->trans('StockQuantitiesAlreadyAllocatedOnPreviousLines').' : '.$alreadyQtyBatchSetted[$line->fk_product][$dbatch->batch][intval($warehouse_id)];
1400 } else {
1401 $alreadyQtyBatchSetted[$line->fk_product][$dbatch->batch][intval($warehouse_id)] = 0 ;
1402 }
1403 $alreadyQtyBatchSetted[$line->fk_product][$dbatch->batch][intval($warehouse_id)] = $deliverableQty + $alreadyQtyBatchSetted[$line->fk_product][$dbatch->batch][intval($warehouse_id)];
1404
1405 print '<!-- subj='.$subj.'/'.$nbofsuggested.' --><tr '.((($subj + 1) == $nbofsuggested) ? 'oddeven' : '').'>';
1406 print '<td colspan="3" ></td><td class="center">';
1407
1408 print '<input class="qtyl '.$tooltipClass.'" title="'.$tooltipTitle.'" name="qtyl'.$indiceAsked.'_'.$subj.'" id="qtyl'.$indiceAsked.'_'.$subj.'" type="text" size="4" value="'.$deliverableQty.'">';
1409 print '</td>';
1410
1411 print '<!-- Show details of lot -->';
1412 print '<td class="left">';
1413
1414 print $staticwarehouse->getNomUrl(0).' / ';
1415
1416 print '<input name="batchl'.$indiceAsked.'_'.$subj.'" type="hidden" value="'.$dbatch->id.'">';
1417
1418 $detail = '';
1419 $detail .= $langs->trans("Batch").': '.$dbatch->batch;
1420 if (empty($conf->global->PRODUCT_DISABLE_SELLBY) && !empty($dbatch->sellby)) {
1421 $detail .= ' - '.$langs->trans("SellByDate").': '.dol_print_date($dbatch->sellby, "day");
1422 }
1423 if (empty($conf->global->PRODUCT_DISABLE_EATBY) && !empty($dbatch->eatby)) {
1424 $detail .= ' - '.$langs->trans("EatByDate").': '.dol_print_date($dbatch->eatby, "day");
1425 }
1426 $detail .= ' - '.$langs->trans("Qty").': '.$dbatch->qty;
1427 $detail .= '<br>';
1428 print $detail;
1429
1430 $quantityToBeDelivered -= $deliverableQty;
1431 if ($quantityToBeDelivered < 0) {
1432 $quantityToBeDelivered = 0;
1433 }
1434 $subj++;
1435 print '</td></tr>';
1436 }
1437 } else {
1438 print '<!-- Case there is no details of lot at all -->';
1439 print '<tr class="oddeven"><td colspan="3"></td><td class="center">';
1440 print '<input class="qtyl" name="qtyl'.$indiceAsked.'_'.$subj.'" id="qtyl'.$indiceAsked.'_'.$subj.'" type="text" size="4" value="0" disabled="disabled"> ';
1441 print '</td>';
1442
1443 print '<td class="left">';
1444 print img_warning().' '.$langs->trans("NoProductToShipFoundIntoStock", $staticwarehouse->label);
1445 print '</td></tr>';
1446 }
1447 }
1448 } else {
1449 // ship from multiple locations
1450 if (empty($conf->productbatch->enabled) || !$product->hasbatch()) {
1451 print '<!-- Case warehouse not already known and product does not need lot -->';
1452 print '<td></td><td></td></tr>'."\n"; // end line and start a new one for each warehouse
1453
1454 print '<input name="idl'.$indiceAsked.'" type="hidden" value="'.$line->id.'">';
1455 $subj = 0;
1456 // Define nb of lines suggested for this order line
1457 $nbofsuggested = 0;
1458
1459 foreach ($product->stock_warehouse as $warehouse_id => $stock_warehouse) {
1460 if ($stock_warehouse->real > 0 || !empty($conf->global->STOCK_ALLOW_NEGATIVE_TRANSFER)) {
1461 $nbofsuggested++;
1462 }
1463 }
1464 $tmpwarehouseObject = new Entrepot($db);
1465 foreach ($product->stock_warehouse as $warehouse_id => $stock_warehouse) { // $stock_warehouse is product_stock
1466 $var = $subj % 2;
1467 if (!empty($warehousePicking) && !in_array($warehouse_id, $warehousePicking)) {
1468 // if a warehouse was selected by user, picking is limited to this warehouse and his children
1469 continue;
1470 }
1471
1472 $tmpwarehouseObject->fetch($warehouse_id);
1473 if ($stock_warehouse->real > 0 || !empty($conf->global->STOCK_ALLOW_NEGATIVE_TRANSFER)) {
1474 $stock = + $stock_warehouse->real; // Convert it to number
1475 $deliverableQty = min($quantityToBeDelivered, $stock);
1476 $deliverableQty = max(0, $deliverableQty);
1477 // Quantity to send
1478 print '<!-- subj='.$subj.'/'.$nbofsuggested.' --><tr '.((($subj + 1) == $nbofsuggested) ? 'oddeven' : '').'>';
1479 print '<td colspan="3" ></td><td class="center"><!-- qty to ship (no lot management for product line indiceAsked='.$indiceAsked.') -->';
1480 if ($line->product_type == Product::TYPE_PRODUCT || !empty($conf->global->STOCK_SUPPORTS_SERVICES)) {
1481 if (isset($alreadyQtySetted[$line->fk_product][intval($warehouse_id)])) {
1482 $deliverableQty = min($quantityToBeDelivered, $stock - $alreadyQtySetted[$line->fk_product][intval($warehouse_id)]);
1483 } else {
1484 if (!isset($alreadyQtySetted[$line->fk_product])) {
1485 $alreadyQtySetted[$line->fk_product] = array();
1486 }
1487
1488 $deliverableQty = min($quantityToBeDelivered, $stock);
1489 }
1490
1491 if ($deliverableQty < 0) $deliverableQty = 0;
1492
1493 $tooltipClass = $tooltipTitle = '';
1494 if (!empty($alreadyQtySetted[$line->fk_product][intval($warehouse_id)])) {
1495 $tooltipClass = ' classfortooltip';
1496 $tooltipTitle = $langs->trans('StockQuantitiesAlreadyAllocatedOnPreviousLines').' : '.$alreadyQtySetted[$line->fk_product][intval($warehouse_id)];
1497 } else {
1498 $alreadyQtySetted[$line->fk_product][intval($warehouse_id)] = 0;
1499 }
1500
1501 $alreadyQtySetted[$line->fk_product][intval($warehouse_id)] = $deliverableQty + $alreadyQtySetted[$line->fk_product][intval($warehouse_id)];
1502
1503 $inputName = 'qtyl'.$indiceAsked.'_'.$subj;
1504 if (GETPOSTISSET($inputName)) {
1505 $deliverableQty = GETPOST($inputName, 'int');
1506 }
1507
1508 print '<input class="qtyl'.$tooltipClass.'" title="'.$tooltipTitle.'" name="qtyl'.$indiceAsked.'_'.$subj.'" id="qtyl'.$indiceAsked.'" type="text" size="4" value="'.$deliverableQty.'">';
1509 print '<input name="ent1'.$indiceAsked.'_'.$subj.'" type="hidden" value="'.$warehouse_id.'">';
1510 } else {
1511 if (getDolGlobalString('SHIPMENT_GETS_ALL_ORDER_PRODUCTS')) {
1512 print '<input name="qtyl'.$indiceAsked.'_'.$subj.'" id="qtyl'.$indiceAsked.'" type="hidden" value="0">';
1513 }
1514
1515 print $langs->trans("NA");
1516 }
1517 print '</td>';
1518
1519 // Stock
1520 if (isModEnabled('stock')) {
1521 print '<td class="left">';
1522 if ($line->product_type == Product::TYPE_PRODUCT || !empty($conf->global->STOCK_SUPPORTS_SERVICES)) {
1523 print $tmpwarehouseObject->getNomUrl(0).' ';
1524
1525 print '<!-- Show details of stock -->';
1526 print '('.$stock.')';
1527 } else {
1528 print $langs->trans("Service");
1529 }
1530 print '</td>';
1531 }
1532 $quantityToBeDelivered -= $deliverableQty;
1533 if ($quantityToBeDelivered < 0) {
1534 $quantityToBeDelivered = 0;
1535 }
1536 $subj++;
1537 print "</tr>\n";
1538 }
1539 }
1540 // Show subproducts of product (not recommanded)
1541 if (!empty($conf->global->PRODUIT_SOUSPRODUITS) && $line->fk_product > 0) {
1542 $product->get_sousproduits_arbo();
1543 $prods_arbo = $product->get_arbo_each_prod($qtyProdCom);
1544 if (count($prods_arbo) > 0) {
1545 foreach ($prods_arbo as $key => $value) {
1546 //print $value[0];
1547 $img = '';
1548 if ($value['stock'] < $value['stock_alert']) {
1549 $img = img_warning($langs->trans("StockTooLow"));
1550 }
1551 print '<tr class"oddeven"><td>';
1552 print "&nbsp; &nbsp; &nbsp; ->
1553 <a href=\"".DOL_URL_ROOT."/product/card.php?id=".$value['id']."\">".$value['fullpath']."
1554 </a> (".$value['nb'].")</td><td class=\"center\"> ".$value['nb_total']."</td><td>&nbsp;</td><td>&nbsp;</td>
1555 <td class=\"center\">".$value['stock']." ".$img."</td>";
1556 print "</tr>";
1557 }
1558 }
1559 }
1560 } else {
1561 print '<!-- Case warehouse not already known and product need lot -->';
1562 print '<td></td><td></td></tr>'; // end line and start a new one for lot/serial
1563
1564 $subj = 0;
1565 print '<input name="idl'.$indiceAsked.'" type="hidden" value="'.$line->id.'">';
1566
1567 $tmpwarehouseObject = new Entrepot($db);
1568 $productlotObject = new Productlot($db);
1569
1570 // Define nb of lines suggested for this order line
1571 $nbofsuggested = 0;
1572 foreach ($product->stock_warehouse as $warehouse_id => $stock_warehouse) {
1573 if (($stock_warehouse->real > 0 || !empty($conf->global->STOCK_ALLOW_NEGATIVE_TRANSFER)) && (count($stock_warehouse->detail_batch))) {
1574 $nbofsuggested+=count($stock_warehouse->detail_batch);
1575 }
1576 }
1577
1578 foreach ($product->stock_warehouse as $warehouse_id => $stock_warehouse) {
1579 $var = $subj % 2;
1580 if (!empty($warehousePicking) && !in_array($warehouse_id, $warehousePicking)) {
1581 // if a warehouse was selected by user, picking is limited to this warehouse and his children
1582 continue;
1583 }
1584
1585 $tmpwarehouseObject->fetch($warehouse_id);
1586 if (($stock_warehouse->real > 0 || !empty($conf->global->STOCK_ALLOW_NEGATIVE_TRANSFER)) && (count($stock_warehouse->detail_batch))) {
1587 foreach ($stock_warehouse->detail_batch as $dbatch) {
1588 $batchStock = + $dbatch->qty; // To get a numeric
1589 if (isset($alreadyQtyBatchSetted[$line->fk_product][$dbatch->batch][intval($warehouse_id)])) {
1590 $deliverableQty = min($quantityToBeDelivered, $batchStock - $alreadyQtyBatchSetted[$line->fk_product][$dbatch->batch][intval($warehouse_id)]);
1591 } else {
1592 if (!isset($alreadyQtyBatchSetted[$line->fk_product])) {
1593 $alreadyQtyBatchSetted[$line->fk_product] = array();
1594 }
1595
1596 if (!isset($alreadyQtyBatchSetted[$line->fk_product][$dbatch->batch])) {
1597 $alreadyQtyBatchSetted[$line->fk_product][$dbatch->batch] = array();
1598 }
1599
1600 $deliverableQty = min($quantityToBeDelivered, $batchStock);
1601 }
1602
1603 if ($deliverableQty < 0) $deliverableQty = 0;
1604
1605 $inputName = 'qtyl'.$indiceAsked.'_'.$subj;
1606 if (GETPOSTISSET($inputName)) {
1607 $deliverableQty = GETPOST($inputName, 'int');
1608 }
1609
1610 $tooltipClass = $tooltipTitle = '';
1611 if (!empty($alreadyQtyBatchSetted[$line->fk_product][$dbatch->batch][intval($warehouse_id)])) {
1612 $tooltipClass = ' classfortooltip';
1613 $tooltipTitle = $langs->trans('StockQuantitiesAlreadyAllocatedOnPreviousLines').' : '.$alreadyQtyBatchSetted[$line->fk_product][$dbatch->batch][intval($warehouse_id)];
1614 } else {
1615 $alreadyQtyBatchSetted[$line->fk_product][$dbatch->batch][intval($warehouse_id)] = 0 ;
1616 }
1617 $alreadyQtyBatchSetted[$line->fk_product][$dbatch->batch][intval($warehouse_id)] = $deliverableQty + $alreadyQtyBatchSetted[$line->fk_product][$dbatch->batch][intval($warehouse_id)];
1618
1619 print '<!-- subj='.$subj.'/'.$nbofsuggested.' --><tr '.((($subj + 1) == $nbofsuggested) ?'oddeven' : '').'><td colspan="3"></td><td class="center">';
1620 print '<input class="qtyl '.$tooltipClass.'" title="'.$tooltipTitle.'" name="'.$inputName.'" id="'.$inputName.'" type="text" size="4" value="'.$deliverableQty.'">';
1621 print '</td>';
1622
1623 print '<td class="left">';
1624
1625 print $tmpwarehouseObject->getNomUrl(0).' / ';
1626
1627 print '<!-- Show details of lot -->';
1628 print '<input name="batchl'.$indiceAsked.'_'.$subj.'" type="hidden" value="'.$dbatch->id.'">';
1629
1630 //print '|'.$line->fk_product.'|'.$dbatch->batch.'|<br>';
1631 print $langs->trans("Batch").': ';
1632 $result = $productlotObject->fetch(0, $line->fk_product, $dbatch->batch);
1633 if ($result > 0) {
1634 print $productlotObject->getNomUrl(1);
1635 } else {
1636 print 'TableLotIncompleteRunRepairWithParamStandardEqualConfirmed';
1637 }
1638 if (empty($conf->global->PRODUCT_DISABLE_SELLBY) && !empty($dbatch->sellby)) {
1639 print ' - '.$langs->trans("SellByDate").': '.dol_print_date($dbatch->sellby, "day");
1640 }
1641 if (empty($conf->global->PRODUCT_DISABLE_EATBY) && !empty($dbatch->eatby)) {
1642 print ' - '.$langs->trans("EatByDate").': '.dol_print_date($dbatch->eatby, "day");
1643 }
1644 print ' ('.$dbatch->qty.')';
1645 $quantityToBeDelivered -= $deliverableQty;
1646 if ($quantityToBeDelivered < 0) {
1647 $quantityToBeDelivered = 0;
1648 }
1649 //dol_syslog('deliverableQty = '.$deliverableQty.' batchStock = '.$batchStock);
1650 $subj++;
1651 print '</td></tr>';
1652 }
1653 }
1654 }
1655 }
1656 if ($subj == 0) { // Line not shown yet, we show it
1657 $warehouse_selected_id = GETPOST('entrepot_id', 'int');
1658
1659 print '<!-- line not shown yet, we show it -->';
1660 print '<tr class="oddeven"><td colspan="3"></td><td class="center">';
1661
1662 if ($line->product_type == Product::TYPE_PRODUCT || !empty($conf->global->STOCK_SUPPORTS_SERVICES)) {
1663 $disabled = '';
1664 if (isModEnabled('productbatch') && $product->hasbatch()) {
1665 $disabled = 'disabled="disabled"';
1666 }
1667 if ($warehouse_selected_id <= 0) { // We did not force a given warehouse, so we won't have no warehouse to change qty.
1668 $disabled = 'disabled="disabled"';
1669 }
1670 print '<input class="qtyl" name="qtyl'.$indiceAsked.'_'.$subj.'" id="qtyl'.$indiceAsked.'_'.$subj.'" type="text" size="4" value="0"'.($disabled ? ' '.$disabled : '').'> ';
1671 if (empty($disabled) && !empty($conf->global->STOCK_ALLOW_NEGATIVE_TRANSFER)) {
1672 print '<input name="ent1' . $indiceAsked . '_' . $subj . '" type="hidden" value="' . $warehouse_selected_id . '">';
1673 }
1674 } else {
1675 print $langs->trans("NA");
1676 }
1677 print '</td>';
1678
1679 print '<td class="left">';
1680 if ($line->product_type == Product::TYPE_PRODUCT || !empty($conf->global->STOCK_SUPPORTS_SERVICES)) {
1681 if ($warehouse_selected_id > 0) {
1682 $warehouseObject = new Entrepot($db);
1683 $warehouseObject->fetch($warehouse_selected_id);
1684 print img_warning().' '.$langs->trans("NoProductToShipFoundIntoStock", $warehouseObject->label);
1685 } else {
1686 if ($line->fk_product) {
1687 print img_warning().' '.$langs->trans("StockTooLow");
1688 } else {
1689 print '';
1690 }
1691 }
1692 } else {
1693 print $langs->trans("Service");
1694 }
1695 print '</td>';
1696 print '</tr>';
1697 }
1698 }
1699
1700 // Display lines for extrafields of the Shipment line
1701 // $line is a 'Order line'
1702 if (!empty($extrafields)) {
1703 //var_dump($line);
1704 $colspan = 5;
1705 $expLine = new ExpeditionLigne($db);
1706
1707 $srcLine = new OrderLine($db);
1708 $srcLine->id = $line->id;
1709 $srcLine->fetch_optionals(); // fetch extrafields also available in orderline
1710
1711 $expLine->array_options = array_merge($expLine->array_options, $srcLine->array_options);
1712
1713 print $expLine->showOptionals($extrafields, 'edit', array('style'=>'class="drag drop oddeven"', 'colspan'=>$colspan), $indiceAsked, '', 1);
1714 }
1715 }
1716
1717 $indiceAsked++;
1718 }
1719
1720 print "</table>";
1721
1722 print '<br>';
1723
1724 print $form->buttonsSaveCancel("Create");
1725
1726 print '</form>';
1727
1728 print '<br>';
1729 } else {
1730 dol_print_error($db);
1731 }
1732 }
1733} elseif ($object->id > 0) {
1734 /* *************************************************************************** */
1735 /* */
1736 /* Edit and view mode */
1737 /* */
1738 /* *************************************************************************** */
1739 $lines = $object->lines;
1740
1741 $num_prod = count($lines);
1742
1743 if (!empty($object->origin) && $object->origin_id > 0) {
1744 $typeobject = $object->origin;
1745 $origin = $object->origin;
1746 $origin_id = $object->origin_id;
1747 $object->fetch_origin(); // Load property $object->commande, $object->propal, ...
1748 }
1749
1750 $soc = new Societe($db);
1751 $soc->fetch($object->socid);
1752
1753 $res = $object->fetch_optionals();
1754
1755 $head = shipping_prepare_head($object);
1756 print dol_get_fiche_head($head, 'shipping', $langs->trans("Shipment"), -1, $object->picto);
1757
1758 $formconfirm = '';
1759
1760 // Confirm deleteion
1761 if ($action == 'delete') {
1762 $formquestion = array();
1763 if ($object->statut == Expedition::STATUS_CLOSED && !empty($conf->global->STOCK_CALCULATE_ON_SHIPMENT_CLOSE)) {
1764 $formquestion = array(
1765 array(
1766 'label' => $langs->trans('ShipmentIncrementStockOnDelete'),
1767 'name' => 'alsoUpdateStock',
1768 'type' => 'checkbox',
1769 'value' => 0
1770 ),
1771 );
1772 }
1773 $formconfirm = $form->formconfirm(
1774 $_SERVER['PHP_SELF'].'?id='.$object->id,
1775 $langs->trans('DeleteSending'),
1776 $langs->trans("ConfirmDeleteSending", $object->ref),
1777 'confirm_delete',
1778 $formquestion,
1779 0,
1780 1
1781 );
1782 }
1783
1784 // Confirmation validation
1785 if ($action == 'valid') {
1786 $objectref = substr($object->ref, 1, 4);
1787 if ($objectref == 'PROV') {
1788 $numref = $object->getNextNumRef($soc);
1789 } else {
1790 $numref = $object->ref;
1791 }
1792
1793 $text = $langs->trans("ConfirmValidateSending", $numref);
1794 if (getDolGlobalString('STOCK_CALCULATE_ON_SHIPMENT')) {
1795 $text .= '<br>'.img_picto('', 'movement', 'class="pictofixedwidth"').$langs->trans("StockMovementWillBeRecorded").'.';
1796 } elseif (getDolGlobalString('STOCK_CALCULATE_ON_SHIPMENT_CLOSE')) {
1797 $text .= '<br>'.img_picto('', 'movement', 'class="pictofixedwidth"').$langs->trans("StockMovementNotYetRecorded").'.';
1798 }
1799
1800 if (isModEnabled('notification')) {
1801 require_once DOL_DOCUMENT_ROOT.'/core/class/notify.class.php';
1802 $notify = new Notify($db);
1803 $text .= '<br>';
1804 $text .= $notify->confirmMessage('SHIPPING_VALIDATE', $object->socid, $object);
1805 }
1806
1807 $formconfirm = $form->formconfirm($_SERVER['PHP_SELF'].'?id='.$object->id, $langs->trans('ValidateSending'), $text, 'confirm_valid', '', 0, 1, 250);
1808 }
1809 // Confirm cancelation
1810 if ($action == 'cancel') {
1811 $formconfirm = $form->formconfirm($_SERVER['PHP_SELF'].'?id='.$object->id, $langs->trans('CancelSending'), $langs->trans("ConfirmCancelSending", $object->ref), 'confirm_cancel', '', 0, 1);
1812 }
1813
1814 // Call Hook formConfirm
1815 $parameters = array('formConfirm' => $formconfirm);
1816 $reshook = $hookmanager->executeHooks('formConfirm', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
1817 if (empty($reshook)) {
1818 $formconfirm .= $hookmanager->resPrint;
1819 } elseif ($reshook > 0) {
1820 $formconfirm = $hookmanager->resPrint;
1821 }
1822
1823 // Print form confirm
1824 print $formconfirm;
1825
1826 // Calculate totalWeight and totalVolume for all products
1827 // by adding weight and volume of each product line.
1828 $tmparray = $object->getTotalWeightVolume();
1829 $totalWeight = $tmparray['weight'];
1830 $totalVolume = $tmparray['volume'];
1831
1832
1833 if ($typeobject == 'commande' && $object->$typeobject->id && isModEnabled('commande')) {
1834 $objectsrc = new Commande($db);
1835 $objectsrc->fetch($object->$typeobject->id);
1836 }
1837 if ($typeobject == 'propal' && $object->$typeobject->id && isModEnabled("propal")) {
1838 $objectsrc = new Propal($db);
1839 $objectsrc->fetch($object->$typeobject->id);
1840 }
1841
1842 // Shipment card
1843 $linkback = '<a href="'.DOL_URL_ROOT.'/expedition/list.php?restore_lastsearch_values=1'.(!empty($socid) ? '&socid='.$socid : '').'">'.$langs->trans("BackToList").'</a>';
1844 $morehtmlref = '<div class="refidno">';
1845 // Ref customer shipment
1846 $morehtmlref .= $form->editfieldkey("RefCustomer", 'ref_customer', $object->ref_customer, $object, $user->rights->expedition->creer, 'string', '', 0, 1);
1847 $morehtmlref .= $form->editfieldval("RefCustomer", 'ref_customer', $object->ref_customer, $object, $user->rights->expedition->creer, 'string'.(isset($conf->global->THIRDPARTY_REF_INPUT_SIZE) ? ':'.$conf->global->THIRDPARTY_REF_INPUT_SIZE : ''), '', null, null, '', 1);
1848 // Thirdparty
1849 $morehtmlref .= '<br>'.$object->thirdparty->getNomUrl(1);
1850 // Project
1851 if (isModEnabled('project')) {
1852 $langs->load("projects");
1853 $morehtmlref .= '<br>';
1854 if (0) { // Do not change on shipment
1855 $morehtmlref .= img_picto($langs->trans("Project"), 'project', 'class="pictofixedwidth"');
1856 if ($action != 'classify') {
1857 $morehtmlref .= '<a class="editfielda" href="'.$_SERVER['PHP_SELF'].'?action=classify&token='.newToken().'&id='.$object->id.'">'.img_edit($langs->transnoentitiesnoconv('SetProject')).'</a> ';
1858 }
1859 $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'].'?id='.$object->id, $objectsrc->socid, $objectsrc->fk_project, ($action == 'classify' ? 'projectid' : 'none'), 0, 0, 0, 1, '', 'maxwidth300');
1860 } else {
1861 if (!empty($objectsrc) && !empty($objectsrc->fk_project)) {
1862 $proj = new Project($db);
1863 $proj->fetch($objectsrc->fk_project);
1864 $morehtmlref .= $proj->getNomUrl(1);
1865 if ($proj->title) {
1866 $morehtmlref .= '<span class="opacitymedium"> - '.dol_escape_htmltag($proj->title).'</span>';
1867 }
1868 }
1869 }
1870 }
1871 $morehtmlref .= '</div>';
1872
1873
1874 dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref);
1875
1876
1877 print '<div class="fichecenter">';
1878 print '<div class="fichehalfleft">';
1879 print '<div class="underbanner clearboth"></div>';
1880
1881 print '<table class="border tableforfield" width="100%">';
1882
1883 // Linked documents
1884 if ($typeobject == 'commande' && $object->$typeobject->id && isModEnabled('commande')) {
1885 print '<tr><td>';
1886 print $langs->trans("RefOrder").'</td>';
1887 print '<td colspan="3">';
1888 print $objectsrc->getNomUrl(1, 'commande');
1889 print "</td>\n";
1890 print '</tr>';
1891 }
1892 if ($typeobject == 'propal' && $object->$typeobject->id && isModEnabled("propal")) {
1893 print '<tr><td>';
1894 print $langs->trans("RefProposal").'</td>';
1895 print '<td colspan="3">';
1896 print $objectsrc->getNomUrl(1, 'expedition');
1897 print "</td>\n";
1898 print '</tr>';
1899 }
1900
1901 // Date creation
1902 print '<tr><td class="titlefield">'.$langs->trans("DateCreation").'</td>';
1903 print '<td colspan="3">'.dol_print_date($object->date_creation, "dayhour")."</td>\n";
1904 print '</tr>';
1905
1906 // Delivery date planned
1907 print '<tr><td height="10">';
1908 print '<table class="nobordernopadding" width="100%"><tr><td>';
1909 print $langs->trans('DateDeliveryPlanned');
1910 print '</td>';
1911
1912 if ($action != 'editdate_livraison') {
1913 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>';
1914 }
1915 print '</tr></table>';
1916 print '</td><td colspan="2">';
1917 if ($action == 'editdate_livraison') {
1918 print '<form name="setdate_livraison" action="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'" method="post">';
1919 print '<input type="hidden" name="token" value="'.newToken().'">';
1920 print '<input type="hidden" name="action" value="setdate_livraison">';
1921 print $form->selectDate($object->date_delivery ? $object->date_delivery : -1, 'liv_', 1, 1, '', "setdate_livraison", 1, 0);
1922 print '<input type="submit" class="button button-edit smallpaddingimp" value="'.$langs->trans('Modify').'">';
1923 print '</form>';
1924 } else {
1925 print $object->date_delivery ? dol_print_date($object->date_delivery, 'dayhour') : '&nbsp;';
1926 }
1927 print '</td>';
1928 print '</tr>';
1929
1930 // Weight
1931 print '<tr><td>';
1932 print $form->editfieldkey("Weight", 'trueWeight', $object->trueWeight, $object, $user->rights->expedition->creer);
1933 print '</td><td colspan="3">';
1934
1935 if ($action == 'edittrueWeight') {
1936 print '<form name="settrueweight" action="'.$_SERVER["PHP_SELF"].'" method="post">';
1937 print '<input name="action" value="settrueWeight" type="hidden">';
1938 print '<input name="id" value="'.$object->id.'" type="hidden">';
1939 print '<input type="hidden" name="token" value="'.newToken().'">';
1940 print '<input id="trueWeight" name="trueWeight" value="'.$object->trueWeight.'" type="text" class="width50 valignmiddle">';
1941 print $formproduct->selectMeasuringUnits("weight_units", "weight", $object->weight_units, 0, 2, 'maxwidth125 valignmiddle');
1942 print ' <input class="button smallpaddingimp valignmiddle" name="modify" value="'.$langs->trans("Modify").'" type="submit">';
1943 print ' <input class="button button-cancel smallpaddingimp valignmiddle" name="cancel" value="'.$langs->trans("Cancel").'" type="submit">';
1944 print '</form>';
1945 } else {
1946 print $object->trueWeight;
1947 print ($object->trueWeight && $object->weight_units != '') ? ' '.measuringUnitString(0, "weight", $object->weight_units) : '';
1948 }
1949
1950 // Calculated
1951 if ($totalWeight > 0) {
1952 if (!empty($object->trueWeight)) {
1953 print ' ('.$langs->trans("SumOfProductWeights").': ';
1954 }
1955 print showDimensionInBestUnit($totalWeight, 0, "weight", $langs, isset($conf->global->MAIN_WEIGHT_DEFAULT_ROUND) ? $conf->global->MAIN_WEIGHT_DEFAULT_ROUND : -1, isset($conf->global->MAIN_WEIGHT_DEFAULT_UNIT) ? $conf->global->MAIN_WEIGHT_DEFAULT_UNIT : 'no');
1956 if (!empty($object->trueWeight)) {
1957 print ')';
1958 }
1959 }
1960 print '</td></tr>';
1961
1962 // Width
1963 print '<tr><td>'.$form->editfieldkey("Width", 'trueWidth', $object->trueWidth, $object, $user->rights->expedition->creer).'</td><td colspan="3">';
1964 print $form->editfieldval("Width", 'trueWidth', $object->trueWidth, $object, $user->rights->expedition->creer);
1965 print ($object->trueWidth && $object->width_units != '') ? ' '.measuringUnitString(0, "size", $object->width_units) : '';
1966 print '</td></tr>';
1967
1968 // Height
1969 print '<tr><td>'.$form->editfieldkey("Height", 'trueHeight', $object->trueHeight, $object, $user->rights->expedition->creer).'</td><td colspan="3">';
1970 if ($action == 'edittrueHeight') {
1971 print '<form name="settrueHeight" action="'.$_SERVER["PHP_SELF"].'" method="post">';
1972 print '<input name="action" value="settrueHeight" type="hidden">';
1973 print '<input name="id" value="'.$object->id.'" type="hidden">';
1974 print '<input type="hidden" name="token" value="'.newToken().'">';
1975 print '<input id="trueHeight" name="trueHeight" value="'.$object->trueHeight.'" type="text" class="width50">';
1976 print $formproduct->selectMeasuringUnits("size_units", "size", $object->size_units, 0, 2);
1977 print ' <input class="button smallpaddingimp" name="modify" value="'.$langs->trans("Modify").'" type="submit">';
1978 print ' <input class="button button-cancel smallpaddingimp" name="cancel" value="'.$langs->trans("Cancel").'" type="submit">';
1979 print '</form>';
1980 } else {
1981 print $object->trueHeight;
1982 print ($object->trueHeight && $object->height_units != '') ? ' '.measuringUnitString(0, "size", $object->height_units) : '';
1983 }
1984
1985 print '</td></tr>';
1986
1987 // Depth
1988 print '<tr><td>'.$form->editfieldkey("Depth", 'trueDepth', $object->trueDepth, $object, $user->rights->expedition->creer).'</td><td colspan="3">';
1989 print $form->editfieldval("Depth", 'trueDepth', $object->trueDepth, $object, $user->rights->expedition->creer);
1990 print ($object->trueDepth && $object->depth_units != '') ? ' '.measuringUnitString(0, "size", $object->depth_units) : '';
1991 print '</td></tr>';
1992
1993 // Volume
1994 print '<tr><td>';
1995 print $langs->trans("Volume");
1996 print '</td>';
1997 print '<td colspan="3">';
1998 $calculatedVolume = 0;
1999 $volumeUnit = 0;
2000 if ($object->trueWidth && $object->trueHeight && $object->trueDepth) {
2001 $calculatedVolume = ($object->trueWidth * $object->trueHeight * $object->trueDepth);
2002 $volumeUnit = $object->size_units * 3;
2003 }
2004 // If sending volume not defined we use sum of products
2005 if ($calculatedVolume > 0) {
2006 if ($volumeUnit < 50) {
2007 print showDimensionInBestUnit($calculatedVolume, $volumeUnit, "volume", $langs, isset($conf->global->MAIN_VOLUME_DEFAULT_ROUND) ? $conf->global->MAIN_VOLUME_DEFAULT_ROUND : -1, isset($conf->global->MAIN_VOLUME_DEFAULT_UNIT) ? $conf->global->MAIN_VOLUME_DEFAULT_UNIT : 'no');
2008 } else {
2009 print $calculatedVolume.' '.measuringUnitString(0, "volume", $volumeUnit);
2010 }
2011 }
2012 if ($totalVolume > 0) {
2013 if ($calculatedVolume) {
2014 print ' ('.$langs->trans("SumOfProductVolumes").': ';
2015 }
2016 print showDimensionInBestUnit($totalVolume, 0, "volume", $langs, isset($conf->global->MAIN_VOLUME_DEFAULT_ROUND) ? $conf->global->MAIN_VOLUME_DEFAULT_ROUND : -1, isset($conf->global->MAIN_VOLUME_DEFAULT_UNIT) ? $conf->global->MAIN_VOLUME_DEFAULT_UNIT : 'no');
2017 //if (empty($calculatedVolume)) print ' ('.$langs->trans("Calculated").')';
2018 if ($calculatedVolume) {
2019 print ')';
2020 }
2021 }
2022 print "</td>\n";
2023 print '</tr>';
2024
2025 // Other attributes
2026 $cols = 2;
2027 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_view.tpl.php';
2028
2029 print '</table>';
2030
2031 print '</div>';
2032 print '<div class="fichehalfright">';
2033 print '<div class="underbanner clearboth"></div>';
2034
2035 print '<table class="border centpercent tableforfield">';
2036
2037 // Sending method
2038 print '<tr><td height="10">';
2039 print '<table class="nobordernopadding" width="100%"><tr><td>';
2040 print $langs->trans('SendingMethod');
2041 print '</td>';
2042
2043 if ($action != 'editshipping_method_id') {
2044 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>';
2045 }
2046 print '</tr></table>';
2047 print '</td><td colspan="2">';
2048 if ($action == 'editshipping_method_id') {
2049 print '<form name="setshipping_method_id" action="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'" method="post">';
2050 print '<input type="hidden" name="token" value="'.newToken().'">';
2051 print '<input type="hidden" name="action" value="setshipping_method_id">';
2052 $object->fetch_delivery_methods();
2053 print $form->selectarray("shipping_method_id", $object->meths, $object->shipping_method_id, 1, 0, 0, "", 1);
2054 if ($user->admin) {
2055 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
2056 }
2057 print '<input type="submit" class="button button-edit smallpaddingimp" value="'.$langs->trans('Modify').'">';
2058 print '</form>';
2059 } else {
2060 if ($object->shipping_method_id > 0) {
2061 // Get code using getLabelFromKey
2062 $code = $langs->getLabelFromKey($db, $object->shipping_method_id, 'c_shipment_mode', 'rowid', 'code');
2063 print $langs->trans("SendingMethod".strtoupper($code));
2064 }
2065 }
2066 print '</td>';
2067 print '</tr>';
2068
2069 // Tracking Number
2070 print '<tr><td class="titlefield">'.$form->editfieldkey("TrackingNumber", 'tracking_number', $object->tracking_number, $object, $user->rights->expedition->creer).'</td><td colspan="3">';
2071 print $form->editfieldval("TrackingNumber", 'tracking_number', $object->tracking_url, $object, $user->rights->expedition->creer, 'safehtmlstring', $object->tracking_number);
2072 print '</td></tr>';
2073
2074 // Incoterms
2075 if (isModEnabled('incoterm')) {
2076 print '<tr><td>';
2077 print '<table width="100%" class="nobordernopadding"><tr><td>';
2078 print $langs->trans('IncotermLabel');
2079 print '<td><td class="right">';
2080 if ($user->rights->expedition->creer) {
2081 print '<a class="editfielda" href="'.DOL_URL_ROOT.'/expedition/card.php?id='.$object->id.'&action=editincoterm&token='.newToken().'">'.img_edit().'</a>';
2082 } else {
2083 print '&nbsp;';
2084 }
2085 print '</td></tr></table>';
2086 print '</td>';
2087 print '<td colspan="3">';
2088 if ($action != 'editincoterm') {
2089 print $form->textwithpicto($object->display_incoterms(), $object->label_incoterms, 1);
2090 } else {
2091 print $form->select_incoterms((!empty($object->fk_incoterms) ? $object->fk_incoterms : ''), (!empty($object->location_incoterms) ? $object->location_incoterms : ''), $_SERVER['PHP_SELF'].'?id='.$object->id);
2092 }
2093 print '</td></tr>';
2094 }
2095
2096 // Other attributes
2097 $parameters = array('colspan' => ' colspan="3"', 'cols' => '3');
2098 $reshook = $hookmanager->executeHooks('formObjectOptions', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
2099 print $hookmanager->resPrint;
2100
2101 print "</table>";
2102
2103 print '</div>';
2104 print '</div>';
2105
2106 print '<div class="clearboth"></div>';
2107
2108
2109 // Lines of products
2110
2111 if ($action == 'editline') {
2112 print ' <form name="updateline" id="updateline" action="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&amp;lineid='.$line_id.'" method="POST">
2113 <input type="hidden" name="token" value="' . newToken().'">
2114 <input type="hidden" name="action" value="updateline">
2115 <input type="hidden" name="mode" value="">
2116 <input type="hidden" name="id" value="' . $object->id.'">
2117 ';
2118 }
2119 print '<br>';
2120
2121 print '<div class="div-table-responsive-no-min">';
2122 print '<table class="noborder" width="100%" id="tablelines" >';
2123 print '<thead>';
2124 print '<tr class="liste_titre">';
2125 // Adds a line numbering column
2126 if (!empty($conf->global->MAIN_VIEW_LINE_NUMBER)) {
2127 print '<td width="5" class="center linecolnum">&nbsp;</td>';
2128 }
2129 // Product/Service
2130 print '<td class="linecoldescription" >'.$langs->trans("Products").'</td>';
2131 // Qty
2132 print '<td class="center linecolqty">'.$langs->trans("QtyOrdered").'</td>';
2133 if ($origin && $origin_id > 0) {
2134 print '<td class="center linecolqtyinothershipments">'.$langs->trans("QtyInOtherShipments").'</td>';
2135 }
2136 if ($action == 'editline') {
2137 $editColspan = 3;
2138 if (!isModEnabled('stock')) {
2139 $editColspan--;
2140 }
2141 if (empty($conf->productbatch->enabled)) {
2142 $editColspan--;
2143 }
2144 print '<td class="center linecoleditlineotherinfo" colspan="'.$editColspan.'">';
2145 if ($object->statut <= 1) {
2146 print $langs->trans("QtyToShip").' - ';
2147 } else {
2148 print $langs->trans("QtyShipped").' - ';
2149 }
2150 if (isModEnabled('stock')) {
2151 print $langs->trans("WarehouseSource").' - ';
2152 }
2153 if (isModEnabled('productbatch')) {
2154 print $langs->trans("Batch");
2155 }
2156 print '</td>';
2157 } else {
2158 if ($object->statut <= 1) {
2159 print '<td class="center linecolqtytoship">'.$langs->trans("QtyToShip").'</td>';
2160 } else {
2161 print '<td class="center linecolqtyshipped">'.$langs->trans("QtyShipped").'</td>';
2162 }
2163 if (isModEnabled('stock')) {
2164 print '<td class="left linecolwarehousesource">'.$langs->trans("WarehouseSource").'</td>';
2165 }
2166
2167 if (isModEnabled('productbatch')) {
2168 print '<td class="left linecolbatch">'.$langs->trans("Batch").'</td>';
2169 }
2170 }
2171 print '<td class="center linecolweight">'.$langs->trans("CalculatedWeight").'</td>';
2172 print '<td class="center linecolvolume">'.$langs->trans("CalculatedVolume").'</td>';
2173 //print '<td class="center">'.$langs->trans("Size").'</td>';
2174 if ($object->statut == 0) {
2175 print '<td class="linecoledit"></td>';
2176 print '<td class="linecoldelete" width="10"></td>';
2177 }
2178 print "</tr>\n";
2179 print '</thead>';
2180
2181 $outputlangs = $langs;
2182
2183 if (getDolGlobalInt('MAIN_MULTILANGS') && !empty($conf->global->PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE)) {
2184 $object->fetch_thirdparty();
2185 $newlang = '';
2186 if (empty($newlang) && GETPOST('lang_id', 'aZ09')) {
2187 $newlang = GETPOST('lang_id', 'aZ09');
2188 }
2189 if (empty($newlang)) {
2190 $newlang = $object->thirdparty->default_lang;
2191 }
2192 if (!empty($newlang)) {
2193 $outputlangs = new Translate("", $conf);
2194 $outputlangs->setDefaultLang($newlang);
2195 }
2196 }
2197
2198 // Get list of products already sent for same source object into $alreadysent
2199 $alreadysent = array();
2200 if ($origin && $origin_id > 0) {
2201 $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";
2202 $sql .= ", ed.rowid as shipmentline_id, ed.qty as qty_shipped, ed.fk_expedition as expedition_id, ed.fk_origin_line, ed.fk_entrepot";
2203 $sql .= ", e.rowid as shipment_id, e.ref as shipment_ref, e.date_creation, e.date_valid, e.date_delivery, e.date_expedition";
2204 //if (getDolGlobalInt('MAIN_SUBMODULE_DELIVERY')) $sql .= ", l.rowid as livraison_id, l.ref as livraison_ref, l.date_delivery, ld.qty as qty_received";
2205 $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';
2206 $sql .= ', p.description as product_desc';
2207 $sql .= " FROM ".MAIN_DB_PREFIX."expeditiondet as ed";
2208 $sql .= ", ".MAIN_DB_PREFIX."expedition as e";
2209 $sql .= ", ".MAIN_DB_PREFIX.$origin."det as obj";
2210 //if (getDolGlobalInt('MAIN_SUBMODULE_DELIVERY')) $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."delivery as l ON l.fk_expedition = e.rowid LEFT JOIN ".MAIN_DB_PREFIX."deliverydet as ld ON ld.fk_delivery = l.rowid AND obj.rowid = ld.fk_origin_line";
2211 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product as p ON obj.fk_product = p.rowid";
2212 $sql .= " WHERE e.entity IN (".getEntity('expedition').")";
2213 $sql .= " AND obj.fk_".$origin." = ".((int) $origin_id);
2214 $sql .= " AND obj.rowid = ed.fk_origin_line";
2215 $sql .= " AND ed.fk_expedition = e.rowid";
2216 //if ($filter) $sql.= $filter;
2217 $sql .= " ORDER BY obj.fk_product";
2218
2219 dol_syslog("expedition/card.php get list of shipment lines", LOG_DEBUG);
2220 $resql = $db->query($sql);
2221 if ($resql) {
2222 $num = $db->num_rows($resql);
2223 $i = 0;
2224
2225 while ($i < $num) {
2226 $obj = $db->fetch_object($resql);
2227 if ($obj) {
2228 // $obj->rowid is rowid in $origin."det" table
2229 $alreadysent[$obj->rowid][$obj->shipmentline_id] = array(
2230 'shipment_ref'=>$obj->shipment_ref, 'shipment_id'=>$obj->shipment_id, 'warehouse'=>$obj->fk_entrepot, 'qty_shipped'=>$obj->qty_shipped,
2231 'product_tosell'=>$obj->product_tosell, 'product_tobuy'=>$obj->product_tobuy, 'product_tobatch'=>$obj->product_tobatch,
2232 'date_valid'=>$db->jdate($obj->date_valid), 'date_delivery'=>$db->jdate($obj->date_delivery));
2233 }
2234 $i++;
2235 }
2236 }
2237 //var_dump($alreadysent);
2238 }
2239
2240 print '<tbody>';
2241
2242 // Loop on each product to send/sent
2243 for ($i = 0; $i < $num_prod; $i++) {
2244 $parameters = array('i' => $i, 'line' => $lines[$i], 'line_id' => $line_id, 'num' => $num_prod, 'alreadysent' => $alreadysent, 'editColspan' => !empty($editColspan) ? $editColspan : 0, 'outputlangs' => $outputlangs);
2245 $reshook = $hookmanager->executeHooks('printObjectLine', $parameters, $object, $action);
2246 if ($reshook < 0) {
2247 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
2248 }
2249
2250 if (empty($reshook)) {
2251 print '<!-- origin line id = '.$lines[$i]->origin_line_id.' -->'; // id of order line
2252 print '<tr class="oddeven" id="row-'.$lines[$i]->id.'" data-id="'.$lines[$i]->id.'" data-element="'.$lines[$i]->element.'" >';
2253
2254 // #
2255 if (!empty($conf->global->MAIN_VIEW_LINE_NUMBER)) {
2256 print '<td class="center linecolnum">'.($i + 1).'</td>';
2257 }
2258
2259 // Predefined product or service
2260 if ($lines[$i]->fk_product > 0) {
2261 // Define output language
2262 if (getDolGlobalInt('MAIN_MULTILANGS') && !empty($conf->global->PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE)) {
2263 $prod = new Product($db);
2264 $prod->fetch($lines[$i]->fk_product);
2265 $label = (!empty($prod->multilangs[$outputlangs->defaultlang]["label"])) ? $prod->multilangs[$outputlangs->defaultlang]["label"] : $lines[$i]->product_label;
2266 } else {
2267 $label = (!empty($lines[$i]->label) ? $lines[$i]->label : $lines[$i]->product_label);
2268 }
2269
2270 print '<td class="linecoldescription">';
2271
2272 // Show product and description
2273 $product_static->type = $lines[$i]->fk_product_type;
2274 $product_static->id = $lines[$i]->fk_product;
2275 $product_static->ref = $lines[$i]->ref;
2276 $product_static->status = $lines[$i]->product_tosell;
2277 $product_static->status_buy = $lines[$i]->product_tobuy;
2278 $product_static->status_batch = $lines[$i]->product_tobatch;
2279
2280 $product_static->weight = $lines[$i]->weight;
2281 $product_static->weight_units = $lines[$i]->weight_units;
2282 $product_static->length = $lines[$i]->length;
2283 $product_static->length_units = $lines[$i]->length_units;
2284 $product_static->width = !empty($lines[$i]->width) ? $lines[$i]->width : 0;
2285 $product_static->width_units = !empty($lines[$i]->width_units) ? $lines[$i]->width_units : 0;
2286 $product_static->height = !empty($lines[$i]->height) ? $lines[$i]->height : 0;
2287 $product_static->height_units = !empty($lines[$i]->height_units) ? $lines[$i]->height_units : 0;
2288 $product_static->surface = $lines[$i]->surface;
2289 $product_static->surface_units = $lines[$i]->surface_units;
2290 $product_static->volume = $lines[$i]->volume;
2291 $product_static->volume_units = $lines[$i]->volume_units;
2292
2293 $text = $product_static->getNomUrl(1);
2294 $text .= ' - '.$label;
2295 $description = (getDolGlobalInt('PRODUIT_DESC_IN_FORM_ACCORDING_TO_DEVICE') ? '' : dol_htmlentitiesbr($lines[$i]->description));
2296 print $form->textwithtooltip($text, $description, 3, '', '', $i);
2297 print_date_range(!empty($lines[$i]->date_start) ? $lines[$i]->date_start : '', !empty($lines[$i]->date_end) ? $lines[$i]->date_end : '');
2298 if (getDolGlobalInt('PRODUIT_DESC_IN_FORM_ACCORDING_TO_DEVICE')) {
2299 print (!empty($lines[$i]->description) && $lines[$i]->description != $lines[$i]->product) ? '<br>'.dol_htmlentitiesbr($lines[$i]->description) : '';
2300 }
2301 print "</td>\n";
2302 } else {
2303 print '<td class="linecoldescription" >';
2304 if ($lines[$i]->product_type == Product::TYPE_SERVICE) {
2305 $text = img_object($langs->trans('Service'), 'service');
2306 } else {
2307 $text = img_object($langs->trans('Product'), 'product');
2308 }
2309
2310 if (!empty($lines[$i]->label)) {
2311 $text .= ' <strong>'.$lines[$i]->label.'</strong>';
2312 print $form->textwithtooltip($text, $lines[$i]->description, 3, '', '', $i);
2313 } else {
2314 print $text.' '.nl2br($lines[$i]->description);
2315 }
2316
2317 print_date_range($lines[$i]->date_start, $lines[$i]->date_end);
2318 print "</td>\n";
2319 }
2320
2321 $unit_order = '';
2322 if (!empty($conf->global->PRODUCT_USE_UNITS)) {
2323 $unit_order = measuringUnitString($lines[$i]->fk_unit);
2324 }
2325
2326 // Qty ordered
2327 print '<td class="center linecolqty">'.$lines[$i]->qty_asked.' '.$unit_order.'</td>';
2328
2329 // Qty in other shipments (with shipment and warehouse used)
2330 if ($origin && $origin_id > 0) {
2331 print '<td class="linecolqtyinothershipments center nowrap">';
2332 $htmltooltip = '';
2333 $qtyalreadysent = 0;
2334 foreach ($alreadysent as $key => $val) {
2335 if ($lines[$i]->fk_origin_line == $key) {
2336 $j = 0;
2337 foreach ($val as $shipmentline_id => $shipmentline_var) {
2338 if ($shipmentline_var['shipment_id'] == $lines[$i]->fk_expedition) {
2339 continue; // We want to show only "other shipments"
2340 }
2341
2342 $j++;
2343 if ($j > 1) {
2344 $htmltooltip .= '<br>';
2345 }
2346 $shipment_static->fetch($shipmentline_var['shipment_id']);
2347 $htmltooltip .= $shipment_static->getNomUrl(1, '', 0, 0, 1);
2348 $htmltooltip .= ' - '.$shipmentline_var['qty_shipped'];
2349 $htmltooltip .= ' - '.$langs->trans("DateValidation").' : '.(empty($shipmentline_var['date_valid']) ? $langs->trans("Draft") : dol_print_date($shipmentline_var['date_valid'], 'dayhour'));
2350 /*if (isModEnabled('stock') && $shipmentline_var['warehouse'] > 0) {
2351 $warehousestatic->fetch($shipmentline_var['warehouse']);
2352 $htmltext .= '<br>'.$langs->trans("FromLocation").' : '.$warehousestatic->getNomUrl(1, '', 0, 1);
2353 }*/
2354 //print ' '.$form->textwithpicto('', $htmltext, 1);
2355
2356 $qtyalreadysent += $shipmentline_var['qty_shipped'];
2357 }
2358 if ($j) {
2359 $htmltooltip = $langs->trans("QtyInOtherShipments").'...<br><br>'.$htmltooltip.'<br><input type="submit" name="dummyhiddenbuttontogetfocus" style="display:none" autofocus>';
2360 }
2361 }
2362 }
2363 print $form->textwithpicto($qtyalreadysent, $htmltooltip, 1, 'info', '', 0, 3, 'tooltip'.$lines[$i]->id);
2364 print '</td>';
2365 }
2366
2367 if ($action == 'editline' && $lines[$i]->id == $line_id) {
2368 // edit mode
2369 print '<td colspan="'.$editColspan.'" class="center"><table class="nobordernopadding centpercent">';
2370 if (is_array($lines[$i]->detail_batch) && count($lines[$i]->detail_batch) > 0) {
2371 print '<!-- case edit 1 -->';
2372 $line = new ExpeditionLigne($db);
2373 foreach ($lines[$i]->detail_batch as $detail_batch) {
2374 print '<tr>';
2375 // Qty to ship or shipped
2376 print '<td><input class="qtyl" 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>';
2377 // Batch number managment
2378 if ($lines[$i]->entrepot_id == 0) {
2379 // only show lot numbers from src warehouse when shipping from multiple warehouses
2380 $line->fetch($detail_batch->fk_expeditiondet);
2381 }
2382 $entrepot_id = !empty($detail_batch->entrepot_id)?$detail_batch->entrepot_id:$lines[$i]->entrepot_id;
2383 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>';
2384 print '</tr>';
2385 }
2386 // add a 0 qty lot row to be able to add a lot
2387 print '<tr>';
2388 // Qty to ship or shipped
2389 print '<td><input class="qtyl" name="qtyl'.$line_id.'_0" id="qtyl'.$line_id.'_0" type="text" size="4" value="0"></td>';
2390 // Batch number managment
2391 print '<td>'.$formproduct->selectLotStock('', 'batchl'.$line_id.'_0', '', 1, 0, $lines[$i]->fk_product).'</td>';
2392 print '</tr>';
2393 } elseif (isModEnabled('stock')) {
2394 if ($lines[$i]->fk_product > 0) {
2395 if ($lines[$i]->entrepot_id > 0) {
2396 print '<!-- case edit 2 -->';
2397 print '<tr>';
2398 // Qty to ship or shipped
2399 print '<td><input class="qtyl" name="qtyl'.$line_id.'" id="qtyl'.$line_id.'" type="text" size="4" value="'.$lines[$i]->qty_shipped.'">'.$unit_order.'</td>';
2400 // Warehouse source
2401 print '<td>'.$formproduct->selectWarehouses($lines[$i]->entrepot_id, 'entl'.$line_id, '', 1, 0, $lines[$i]->fk_product, '', 1).'</td>';
2402 // Batch number managment
2403 print '<td> - '.$langs->trans("NA").'</td>';
2404 print '</tr>';
2405 } elseif (count($lines[$i]->details_entrepot) > 1) {
2406 print '<!-- case edit 3 -->';
2407 foreach ($lines[$i]->details_entrepot as $detail_entrepot) {
2408 print '<tr>';
2409 // Qty to ship or shipped
2410 print '<td><input class="qtyl" name="qtyl'.$detail_entrepot->line_id.'" id="qtyl'.$detail_entrepot->line_id.'" type="text" size="4" value="'.$detail_entrepot->qty_shipped.'">'.$unit_order.'</td>';
2411 // Warehouse source
2412 print '<td>'.$formproduct->selectWarehouses($detail_entrepot->entrepot_id, 'entl'.$detail_entrepot->line_id, '', 1, 0, $lines[$i]->fk_product, '', 1).'</td>';
2413 // Batch number managment
2414 print '<td> - '.$langs->trans("NA").'</td>';
2415 print '</tr>';
2416 }
2417 } else {
2418 print '<!-- case edit 4 -->';
2419 print '<tr><td colspan="3">'.$langs->trans("NotEnoughStock").'</td></tr>';
2420 }
2421 } else {
2422 print '<!-- case edit 5 -->';
2423 print '<tr>';
2424 // Qty to ship or shipped
2425 print '<td><input class="qtyl" name="qtyl'.$line_id.'" id="qtyl'.$line_id.'" type="text" size="4" value="'.$lines[$i]->qty_shipped.'">'.$unit_order.'</td>';
2426 // Warehouse source
2427 print '<td></td>';
2428 // Batch number managment
2429 print '<td></td>';
2430 print '</tr>';
2431 }
2432 } elseif (!isModEnabled('stock') && empty($conf->productbatch->enabled)) { // both product batch and stock are not activated.
2433 print '<!-- case edit 6 -->';
2434 print '<tr>';
2435 // Qty to ship or shipped
2436 print '<td><input class="qtyl" name="qtyl'.$line_id.'" id="qtyl'.$line_id.'" type="text" size="4" value="'.$lines[$i]->qty_shipped.'"></td>';
2437 // Warehouse source
2438 print '<td></td>';
2439 // Batch number managment
2440 print '<td></td>';
2441 print '</tr>';
2442 }
2443
2444 print '</table></td>';
2445 } else {
2446 // Qty to ship or shipped
2447 print '<td class="linecolqtytoship center">'.$lines[$i]->qty_shipped.' '.$unit_order.'</td>';
2448
2449 // Warehouse source
2450 if (isModEnabled('stock')) {
2451 print '<td class="linecolwarehousesource left">';
2452 if ($lines[$i]->entrepot_id > 0) {
2453 $entrepot = new Entrepot($db);
2454 $entrepot->fetch($lines[$i]->entrepot_id);
2455 print $entrepot->getNomUrl(1);
2456 } elseif (count($lines[$i]->details_entrepot) > 1) {
2457 $detail = '';
2458 foreach ($lines[$i]->details_entrepot as $detail_entrepot) {
2459 if ($detail_entrepot->entrepot_id > 0) {
2460 $entrepot = new Entrepot($db);
2461 $entrepot->fetch($detail_entrepot->entrepot_id);
2462 $detail .= $langs->trans("DetailWarehouseFormat", $entrepot->label, $detail_entrepot->qty_shipped).'<br>';
2463 }
2464 }
2465 print $form->textwithtooltip(img_picto('', 'object_stock').' '.$langs->trans("DetailWarehouseNumber"), $detail);
2466 }
2467 print '</td>';
2468 }
2469
2470 // Batch number managment
2471 if (isModEnabled('productbatch')) {
2472 if (isset($lines[$i]->detail_batch)) {
2473 print '<!-- Detail of lot -->';
2474 print '<td class="linecolbatch">';
2475 if ($lines[$i]->product_tobatch) {
2476 $detail = '';
2477 foreach ($lines[$i]->detail_batch as $dbatch) { // $dbatch is instance of ExpeditionLineBatch
2478 $detail .= $langs->trans("Batch").': '.$dbatch->batch;
2479 if (empty($conf->global->PRODUCT_DISABLE_SELLBY)) {
2480 $detail .= ' - '.$langs->trans("SellByDate").': '.dol_print_date($dbatch->sellby, "day");
2481 }
2482 if (empty($conf->global->PRODUCT_DISABLE_EATBY)) {
2483 $detail .= ' - '.$langs->trans("EatByDate").': '.dol_print_date($dbatch->eatby, "day");
2484 }
2485 $detail .= ' - '.$langs->trans("Qty").': '.$dbatch->qty;
2486 $detail .= '<br>';
2487 }
2488 print $form->textwithtooltip(img_picto('', 'object_barcode').' '.$langs->trans("DetailBatchNumber"), $detail);
2489 } else {
2490 print $langs->trans("NA");
2491 }
2492 print '</td>';
2493 } else {
2494 print '<td class="linecolbatch" ></td>';
2495 }
2496 }
2497 }
2498
2499 // Weight
2500 print '<td class="center linecolweight">';
2501 if ($lines[$i]->fk_product_type == Product::TYPE_PRODUCT) {
2502 print $lines[$i]->weight * $lines[$i]->qty_shipped.' '.measuringUnitString(0, "weight", $lines[$i]->weight_units);
2503 } else {
2504 print '&nbsp;';
2505 }
2506 print '</td>';
2507
2508 // Volume
2509 print '<td class="center linecolvolume">';
2510 if ($lines[$i]->fk_product_type == Product::TYPE_PRODUCT) {
2511 print $lines[$i]->volume * $lines[$i]->qty_shipped.' '.measuringUnitString(0, "volume", $lines[$i]->volume_units);
2512 } else {
2513 print '&nbsp;';
2514 }
2515 print '</td>';
2516
2517 // Size
2518 //print '<td class="center">'.$lines[$i]->volume*$lines[$i]->qty_shipped.' '.measuringUnitString(0, "volume", $lines[$i]->volume_units).'</td>';
2519
2520 if ($action == 'editline' && $lines[$i]->id == $line_id) {
2521 print '<td class="center" colspan="2" valign="middle">';
2522 print '<input type="submit" class="button button-save" id="savelinebutton marginbottomonly" name="save" value="'.$langs->trans("Save").'"><br>';
2523 print '<input type="submit" class="button button-cancel" id="cancellinebutton" name="cancel" value="'.$langs->trans("Cancel").'"><br>';
2524 print '</td>';
2525 } elseif ($object->statut == Expedition::STATUS_DRAFT) {
2526 // edit-delete buttons
2527 print '<td class="linecoledit center">';
2528 print '<a class="editfielda reposition" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=editline&token='.newToken().'&lineid='.$lines[$i]->id.'">'.img_edit().'</a>';
2529 print '</td>';
2530 print '<td class="linecoldelete" width="10">';
2531 print '<a class="reposition" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=deleteline&token='.newToken().'&lineid='.$lines[$i]->id.'">'.img_delete().'</a>';
2532 print '</td>';
2533
2534 // Display lines extrafields
2535 if (!empty($rowExtrafieldsStart)) {
2536 print $rowExtrafieldsStart;
2537 print $rowExtrafieldsView;
2538 print $rowEnd;
2539 }
2540 }
2541 print "</tr>";
2542
2543 // Display lines extrafields.
2544 // $line is a line of shipment
2545 if (!empty($extrafields)) {
2546 $colspan = 6;
2547 if ($origin && $origin_id > 0) {
2548 $colspan++;
2549 }
2550 if (isModEnabled('productbatch')) {
2551 $colspan++;
2552 }
2553 if (isModEnabled('stock')) {
2554 $colspan++;
2555 }
2556
2557 $line = $lines[$i];
2558 $line->fetch_optionals();
2559
2560 // TODO Show all in same line by setting $display_type = 'line'
2561 if ($action == 'editline' && $line->id == $line_id) {
2562 print $lines[$i]->showOptionals($extrafields, 'edit', array('colspan'=>$colspan), !empty($indiceAsked) ? $indiceAsked : '', '', 0, 'card');
2563 } else {
2564 print $lines[$i]->showOptionals($extrafields, 'view', array('colspan'=>$colspan), !empty($indiceAsked) ? $indiceAsked : '', '', 0, 'card');
2565 }
2566 }
2567 }
2568 }
2569
2570 // TODO Show also lines ordered but not delivered
2571
2572 if (empty($num_prod)) {
2573 print '<tr><td colspan="8"><span class="opacitymedium">'.$langs->trans("NoLineGoOnTabToAddSome", $langs->transnoentitiesnoconv("ShipmentDistribution")).'</span></td></tr>';
2574 }
2575
2576 print "</table>\n";
2577 print '</tbody>';
2578 print '</div>';
2579
2580
2581 print dol_get_fiche_end();
2582
2583
2584 $object->fetchObjectLinked($object->id, $object->element);
2585
2586
2587 /*
2588 * Boutons actions
2589 */
2590
2591 if (($user->socid == 0) && ($action != 'presend')) {
2592 print '<div class="tabsAction">';
2593
2594 $parameters = array();
2595 $reshook = $hookmanager->executeHooks('addMoreActionsButtons', $parameters, $object, $action); // Note that $action and $object may have been
2596 // modified by hook
2597 if (empty($reshook)) {
2598 if ($object->statut == Expedition::STATUS_DRAFT && $num_prod > 0) {
2599 if ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->expedition->creer))
2600 || (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->expedition->shipping_advance->validate))) {
2601 print dolGetButtonAction('', $langs->trans('Validate'), 'default', $_SERVER["PHP_SELF"].'?action=valid&token='.newToken().'&id='.$object->id, '');
2602 } else {
2603 print dolGetButtonAction($langs->trans('NotAllowed'), $langs->trans('Validate'), 'default', $_SERVER['PHP_SELF']. '#', '', false);
2604 }
2605 }
2606
2607 // 0=draft, 1=validated/delivered, 2=closed/delivered
2608 // If WORKFLOW_BILL_ON_SHIPMENT: 0=draft, 1=validated, 2=billed (no status delivered)
2609 if ($object->statut == Expedition::STATUS_VALIDATED && !getDolGlobalString('STOCK_CALCULATE_ON_SHIPMENT')) {
2610 if ($user->hasRight('expedition', 'creer')) {
2611 print dolGetButtonAction('', $langs->trans('SetToDraft'), 'default', $_SERVER["PHP_SELF"].'?action=setdraft&token='.newToken().'&id='.$object->id, '');
2612 }
2613 }
2614 if ($object->statut == Expedition::STATUS_CLOSED) {
2615 if ($user->hasRight('expedition', 'creer')) {
2616 if (isModEnabled('facture') && !empty($conf->global->WORKFLOW_BILL_ON_SHIPMENT)) { // Quand l'option est on, il faut avoir le bouton en plus et non en remplacement du Close ?
2617 print dolGetButtonAction('', $langs->trans('ClassifyUnbilled'), 'default', $_SERVER["PHP_SELF"].'?action=reopen&token='.newToken().'&id='.$object->id, '');
2618 } else {
2619 print dolGetButtonAction('', $langs->trans('ReOpen'), 'default', $_SERVER["PHP_SELF"].'?action=reopen&token='.newToken().'&id='.$object->id, '');
2620 }
2621 }
2622 }
2623
2624 // Send
2625 if (empty($user->socid)) {
2626 if ($object->statut > 0) {
2627 if (empty($conf->global->MAIN_USE_ADVANCED_PERMS) || $user->rights->expedition->shipping_advance->send) {
2628 print dolGetButtonAction('', $langs->trans('SendMail'), 'default', $_SERVER["PHP_SELF"].'?action=presend&token='.newToken().'&id='.$object->id.'&mode=init#formmailbeforetitle', '');
2629 } else {
2630 print dolGetButtonAction('', $langs->trans('SendMail'), 'default', $_SERVER['PHP_SELF']. '#', '', false);
2631 }
2632 }
2633 }
2634
2635 // Create bill
2636 if (isModEnabled('facture') && ($object->statut == Expedition::STATUS_VALIDATED || $object->statut == Expedition::STATUS_CLOSED)) {
2637 if ($user->hasRight('facture', 'creer')) {
2638 // TODO show button only if (!empty($conf->global->WORKFLOW_BILL_ON_SHIPMENT))
2639 // If we do that, we must also make this option official.
2640 print dolGetButtonAction('', $langs->trans('CreateBill'), 'default', DOL_URL_ROOT.'/compta/facture/card.php?action=create&origin='.$object->element.'&originid='.$object->id.'&socid='.$object->socid, '');
2641 }
2642 }
2643
2644 // This is just to generate a delivery receipt
2645 //var_dump($object->linkedObjectsIds['delivery']);
2646 if (getDolGlobalInt('MAIN_SUBMODULE_DELIVERY') && ($object->statut == Expedition::STATUS_VALIDATED || $object->statut == Expedition::STATUS_CLOSED) && $user->rights->expedition->delivery->creer && empty($object->linkedObjectsIds['delivery'])) {
2647 print dolGetButtonAction('', $langs->trans('CreateDeliveryOrder'), 'default', $_SERVER["PHP_SELF"].'?action=create_delivery&token='.newToken().'&id='.$object->id, '');
2648 }
2649 // Close
2650 if ($object->statut == Expedition::STATUS_VALIDATED) {
2651 if ($user->rights->expedition->creer && $object->statut > 0 && !$object->billed) {
2652 $label = "Close"; $paramaction = 'classifyclosed'; // = Transferred/Received
2653 // Label here should be "Close" or "ClassifyBilled" if we decided to make bill on shipments instead of orders
2654 if (isModEnabled('facture') && !empty($conf->global->WORKFLOW_BILL_ON_SHIPMENT)) { // Quand l'option est on, il faut avoir le bouton en plus et non en remplacement du Close ?
2655 $label = "ClassifyBilled";
2656 $paramaction = 'classifybilled';
2657 }
2658 print dolGetButtonAction('', $langs->trans($label), 'default', $_SERVER["PHP_SELF"].'?action='. $paramaction .'&token='.newToken().'&id='.$object->id, '');
2659 }
2660 }
2661
2662 // Cancel
2663 if ($object->statut == Expedition::STATUS_VALIDATED) {
2664 if ($user->rights->expedition->supprimer) {
2665 print dolGetButtonAction('', $langs->trans('Cancel'), 'danger', $_SERVER["PHP_SELF"].'?action=cancel&token='.newToken().'&id='.$object->id.'&mode=init#formmailbeforetitle', '');
2666 }
2667 }
2668
2669 // Delete
2670 if ($user->rights->expedition->supprimer) {
2671 print dolGetButtonAction('', $langs->trans('Delete'), 'delete', $_SERVER["PHP_SELF"].'?action=delete&token='.newToken().'&id='.$object->id, '');
2672 }
2673 }
2674
2675 print '</div>';
2676 }
2677
2678
2679 /*
2680 * Documents generated
2681 */
2682
2683 if ($action != 'presend' && $action != 'editline') {
2684 print '<div class="fichecenter"><div class="fichehalfleft">';
2685
2686 $objectref = dol_sanitizeFileName($object->ref);
2687 $filedir = $conf->expedition->dir_output."/sending/".$objectref;
2688
2689 $urlsource = $_SERVER["PHP_SELF"]."?id=".$object->id;
2690
2691 $genallowed = $user->rights->expedition->lire;
2692 $delallowed = $user->rights->expedition->creer;
2693
2694 print $formfile->showdocuments('expedition', $objectref, $filedir, $urlsource, $genallowed, $delallowed, $object->model_pdf, 1, 0, 0, 28, 0, '', '', '', $soc->default_lang);
2695
2696
2697 // Show links to link elements
2698 $linktoelem = $form->showLinkToObjectBlock($object, null, array('shipping'));
2699 $somethingshown = $form->showLinkedObjectBlock($object, $linktoelem);
2700
2701
2702 print '</div><div class="fichehalfright">';
2703
2704 // List of actions on element
2705 include_once DOL_DOCUMENT_ROOT.'/core/class/html.formactions.class.php';
2706 $formactions = new FormActions($db);
2707 $somethingshown = $formactions->showactions($object, 'shipping', $socid, 1);
2708
2709 print '</div></div>';
2710 }
2711
2712
2713 /*
2714 * Action presend
2715 */
2716
2717 //Select mail models is same action as presend
2718 if (GETPOST('modelselected')) {
2719 $action = 'presend';
2720 }
2721
2722 // Presend form
2723 $modelmail = 'shipping_send';
2724 $defaulttopic = $langs->trans('SendShippingRef');
2725 $diroutput = $conf->expedition->dir_output.'/sending';
2726 $trackid = 'shi'.$object->id;
2727
2728 include DOL_DOCUMENT_ROOT.'/core/tpl/card_presend.tpl.php';
2729}
2730
2731// End of page
2732llxFooter();
2733$db->close();
if(preg_match('/set_([a-z0-9_\-]+)/i', $action, $reg)) if(preg_match('/del_([a-z0-9_\-]+)/i', $action, $reg)) if($action=='set') elseif( $action=='specimen') elseif($action=='setmodel') elseif( $action=='del') elseif($action=='setdoc') $formactions
View.
if(!defined('NOREQUIRESOC')) if(!defined( 'NOREQUIRETRAN')) if(!defined('NOTOKENRENEWAL')) if(!defined( 'NOREQUIREMENU')) if(!defined('NOREQUIREHTML')) if(!defined( 'NOREQUIREAJAX')) llxHeader()
Empty header.
Definition wrapper.php:56
llxFooter()
Empty footer.
Definition wrapper.php:70
Class to manage customers orders.
Class to manage a WYSIWYG editor.
Class to manage warehouses.
Class to manage shipments.
const STATUS_DRAFT
Draft status.
const STATUS_CLOSED
Closed status.
const STATUS_VALIDATED
Validated status.
Classe to manage lines of shipment.
CRUD class for batch number management within shipment.
Class to manage standard extra fields.
Class to manage building of HTML components.
Class to offer components to list and upload files.
Class to manage generation of HTML components Only common components must be here.
Class with static methods for building HTML components related to products Only components common to ...
Class to manage building of HTML components.
static liste_modeles($db, $maxfilenamelength=0)
Return list of active generation models.
Class to manage notifications.
Class to manage order lines.
Class to manage products or services.
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.
print $script_file $mode $langs defaultlang(is_numeric($duration_value) ? " delay=". $duration_value :"").(is_numeric($duration_value2) ? " after cd cd cd description as description
Only used if Module[ID]Desc translation string is not found.
dol_banner_tab($object, $paramid, $morehtml='', $shownav=1, $fieldid='rowid', $fieldref='ref', $morehtmlref='', $moreparam='', $nodbprefix=0, $morehtmlleft='', $morehtmlstatus='', $onlybanner=0, $morehtmlright='')
Show tab footer of a card.
dol_mktime($hour, $minute, $second, $month, $day, $year, $gm='auto', $check=1)
Return a timestamp date built from detailed informations (by default a local PHP server timestamp) Re...
load_fiche_titre($titre, $morehtmlright='', $picto='generic', $pictoisfullpath=0, $id='', $morecssontable='', $morehtmlcenter='')
Load a title with picto.
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)
Show tabs of a record.
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
dol_print_error($db='', $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
img_object($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0)
Show a picto called object_picto (generic function)
dol_get_fiche_end($notab=0)
Return tab footer of a card.
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs='', $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
getDolGlobalInt($key, $default=0)
Return dolibarr global constant int value.
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2)
Show picto whatever it's its name (generic function)
showDimensionInBestUnit($dimension, $unit, $type, $outputlangs, $round=-1, $forceunitoutput='no', $use_short_label=0)
Output a dimension with best unit.
dol_clone($object, $native=0)
Create a clone of instance of object (new instance with same value for each properties) With native =...
dolGetButtonAction($label, $text='', $actionType='default', $url='', $id='', $userRight=1, $params=array())
Function dolGetButtonAction.
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
info_admin($text, $infoonimgalt=0, $nodiv=0, $admin='1', $morecss='hideonsmartphone', $textfordropdown='')
Show information for admin users or standard users.
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='', $noduplicate=0)
Set event messages in dol_events session object.
dol_sanitizeFileName($str, $newstr='_', $unaccent=1)
Clean a string to use it as a file name.
print_date_range($date_start, $date_end, $format='', $outputlangs='')
Format output for start and end date.
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 dolibarr global constant string value.
img_edit($titlealt='default', $float=0, $other='')
Show logo editer/modifier fiche.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
measuringUnitString($unit, $measuring_style='', $scale='', $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.