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