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