dolibarr 18.0.6
dispatch.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2004-2006 Rodolphe Quiedeville <rodolphe@quiedeville.org>
3 * Copyright (C) 2004-2016 Laurent Destailleur <eldy@users.sourceforge.net>
4 * Copyright (C) 2005 Eric Seigne <eric.seigne@ryxeo.com>
5 * Copyright (C) 2005-2009 Regis Houssin <regis.houssin@inodbox.com>
6 * Copyright (C) 2010-2021 Juanjo Menent <jmenent@2byte.es>
7 * Copyright (C) 2014 Cedric Gross <c.gross@kreiz-it.fr>
8 * Copyright (C) 2016 Florian Henry <florian.henry@atm-consulting.fr>
9 * Copyright (C) 2017-2022 Ferran Marcet <fmarcet@2byte.es>
10 * Copyright (C) 2018-2022 Frédéric France <frederic.france@netlogic.fr>
11 * Copyright (C) 2019-2020 Christophe Battarel <christophe@altairis.fr>
12 *
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 3 of the License, or
16 * (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program. If not, see <https://www.gnu.org/licenses/>.
25 */
26
33// Load Dolibarr environment
34require '../main.inc.php';
35require_once DOL_DOCUMENT_ROOT.'/core/modules/supplier_order/modules_commandefournisseur.php';
36require_once DOL_DOCUMENT_ROOT.'/product/stock/class/entrepot.class.php';
37require_once DOL_DOCUMENT_ROOT.'/core/lib/fourn.lib.php';
38require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.commande.class.php';
39require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.commande.dispatch.class.php';
40require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php';
41require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
42require_once DOL_DOCUMENT_ROOT.'/core/lib/sendings.lib.php';
43if (isModEnabled('project')) {
44 require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
45}
46
47// Load translation files required by the page
48$langs->loadLangs(array("sendings", "companies", "bills", 'deliveries', 'orders', 'stocks', 'other', 'propal', 'receptions'));
49
50if (isModEnabled('productbatch')) {
51 $langs->load('productbatch');
52}
53
54 // Security check
55$id = GETPOST("id", 'int');
56$ref = GETPOST('ref');
57$lineid = GETPOST('lineid', 'int');
58$action = GETPOST('action', 'aZ09');
59$fk_default_warehouse = GETPOST('fk_default_warehouse', 'int');
60$cancel = GETPOST('cancel', 'alpha');
61$confirm = GETPOST('confirm', 'alpha');
62
63$error = 0;
64$errors = array();
65
66if ($user->socid) {
67 $socid = $user->socid;
68}
69
70$hookmanager->initHooks(array('expeditiondispatch'));
71
72// Recuperation de l'id de projet
73$projectid = 0;
74if (GETPOSTISSET("projectid")) {
75 $projectid = GETPOST("projectid", 'int');
76}
77
78$object = new Expedition($db);
79$objectorder = new Commande($db);
80
81
82if ($id > 0 || !empty($ref)) {
83 $result = $object->fetch($id, $ref);
84 if ($result <= 0) {
85 setEventMessages($object->error, $object->errors, 'errors');
86 }
87 $result = $object->fetch_thirdparty();
88 if ($result < 0) {
89 setEventMessages($object->error, $object->errors, 'errors');
90 }
91 if (!empty($object->origin)) {
92 $origin = $object->origin;
93
94 $object->fetch_origin();
95 $typeobject = $object->origin;
96 }
97}
98
99// $id is id of a purchase order.
100$result = restrictedArea($user, 'expedition', $object, '');
101
102if (!isModEnabled('stock')) {
103 accessforbidden('Module stock disabled');
104}
105
106$usercancreate = $user->hasRight('expedition', 'creer');
107$permissiontoadd = $usercancreate; // Used by the include of actions_addupdatedelete.inc.php
108
109
110/*
111 * Actions
112 */
113
114$parameters = array();
115$reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
116if ($reshook < 0) {
117 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
118}
119
120// Update a dispatched line
121if ($action == 'updatelines' && $usercancreate) {
122 $db->begin();
123 $error = 0;
124
125 $expeditiondispatch = new ExpeditionLigne($db);
126 $expeditionlinebatch = new ExpeditionLineBatch($db);
127
128 $pos = 0;
129
130 foreach ($_POST as $key => $value) {
131 // without batch module enabled
132 $reg = array();
133 if (preg_match('/^product_.*([0-9]+)_([0-9]+)$/i', $key, $reg)) {
134 $pos++;
135 if (preg_match('/^product_([0-9]+)_([0-9]+)$/i', $key, $reg)) {
136 $modebatch = "barcode";
137 } elseif (preg_match('/^product_batch_([0-9]+)_([0-9]+)$/i', $key, $reg)) { // With batchmode enabled
138 $modebatch = "batch";
139 }
140
141 $numline = $pos;
142 if ($modebatch == "barcode") {
143 $prod = "product_".$reg[1].'_'.$reg[2];
144 } else {
145 $prod = 'product_batch_'.$reg[1].'_'.$reg[2];
146 }
147 $qty = "qty_".$reg[1].'_'.$reg[2];
148 $ent = "entrepot_".$reg[1].'_'.$reg[2];
149 $fk_commandedet = "fk_commandedet_".$reg[1].'_'.$reg[2];
150 $idline = GETPOST("idline_".$reg[1].'_'.$reg[2]);
151 $pu = "pu_".$reg[1].'_'.$reg[2]; // This is unit price including discount
152 $lot = '';
153 $dDLUO = '';
154 $dDLC = '';
155 if ($modebatch == "batch") { //TODO: Make impossible to input non existing batch code
156 $lot = GETPOST('lot_number_'.$reg[1].'_'.$reg[2]);
157 $dDLUO = dol_mktime(12, 0, 0, GETPOST('dluo_'.$reg[1].'_'.$reg[2].'month', 'int'), GETPOST('dluo_'.$reg[1].'_'.$reg[2].'day', 'int'), GETPOST('dluo_'.$reg[1].'_'.$reg[2].'year', 'int'));
158 $dDLC = dol_mktime(12, 0, 0, GETPOST('dlc_'.$reg[1].'_'.$reg[2].'month', 'int'), GETPOST('dlc_'.$reg[1].'_'.$reg[2].'day', 'int'), GETPOST('dlc_'.$reg[1].'_'.$reg[2].'year', 'int'));
159 }
160
161 $newqty = price2num(GETPOST($qty, 'alpha'), 'MS');
162 //var_dump("modebatch=".$modebatch." newqty=".$newqty." ent=".$ent." idline=".$idline);
163
164 // We ask to move a qty
165 if (($modebatch == "batch" && $newqty >= 0) || ($modebatch == "barcode" && $newqty != 0)) {
166 if ($newqty > 0) { // If we want a qty, we make test on input data
167 if (!(GETPOST($ent, 'int') > 0)) {
168 dol_syslog('No dispatch for line '.$key.' as no warehouse was chosen.');
169 $text = $langs->transnoentities('Warehouse').', '.$langs->transnoentities('Line').' '.($numline);
170 setEventMessages($langs->trans('ErrorFieldRequired', $text), null, 'errors');
171 $error++;
172 }
173 if (!$error && $modebatch == "batch") {
174 $sql = "SELECT pb.rowid ";
175 $sql .= " FROM ".MAIN_DB_PREFIX."product_batch as pb";
176 $sql .= " JOIN ".MAIN_DB_PREFIX."product_stock as ps";
177 $sql .= " ON ps.rowid = pb.fk_product_stock";
178 $sql .= " WHERE pb.batch = '".$db->escape($lot)."'";
179 $sql .= " AND ps.fk_product = ".((int) GETPOST($prod, 'int')) ;
180 $sql .= " AND ps.fk_entrepot = ".((int) GETPOST($ent, 'int')) ;
181
182 $resql = $db->query($sql);
183 if ($resql) {
184 $num = $db->num_rows($resql);
185 if ($num > 1) {
186 dol_syslog('No dispatch for line '.$key.' as too many combination warehouse, product, batch code was found ('.$num.').');
187 setEventMessages($langs->trans('ErrorTooManyCombinationBatchcode', $numline, $num), null, 'errors');
188 $error++;
189 } elseif ($num < 1) {
190 dol_syslog('No dispatch for line '.$key.' as no combination warehouse, product, batch code was found.');
191 setEventMessages($langs->trans('ErrorNoCombinationBatchcode', $numline), null, 'errors');
192 $error++;
193 }
194 $db->free($resql);
195 }
196 }
197 }
198 //var_dump($key.' '.$newqty.' '.$idline.' '.$error);
199
200 if (!$error) {
201 $qtystart = 0;
202
203 if ($idline > 0) {
204 $result = $expeditiondispatch->fetch($idline); // get line from llx_expeditiondet
205 if ($result < 0) {
206 setEventMessages($expeditiondispatch->error, $expeditiondispatch->errors, 'errors');
207 $error++;
208 } else {
209 $qtystart = $expeditiondispatch->qty;
210 $expeditiondispatch->qty = $newqty;
211 $expeditiondispatch->entrepot_id = GETPOST($ent, 'int');
212
213 if ($newqty > 0) {
214 $result = $expeditiondispatch->update($user);
215 } else {
216 $result = $expeditiondispatch->delete($user);
217 }
218 if ($result < 0) {
219 setEventMessages($expeditiondispatch->error, $expeditiondispatch->errors, 'errors');
220 $error++;
221 }
222
223 if (!$error && $modebatch == "batch") {
224 if ($newqty > 0) {
225 $suffixkeyfordate = preg_replace('/^product_batch/', '', $key);
226 $sellby = dol_mktime(0, 0, 0, GETPOST('dlc'.$suffixkeyfordate.'month'), GETPOST('dlc'.$suffixkeyfordate.'day'), GETPOST('dlc'.$suffixkeyfordate.'year'), '');
227 $eatby = dol_mktime(0, 0, 0, GETPOST('dluo'.$suffixkeyfordate.'month'), GETPOST('dluo'.$suffixkeyfordate.'day'), GETPOST('dluo'.$suffixkeyfordate.'year'));
228
229 $sqlsearchdet = "SELECT rowid FROM ".MAIN_DB_PREFIX.$expeditionlinebatch->table_element;
230 $sqlsearchdet .= " WHERE fk_expeditiondet = ".((int) $idline);
231 $sqlsearchdet .= " AND batch = '".$db->escape($lot)."'";
232 $resqlsearchdet = $db->query($sqlsearchdet);
233
234 if ($resqlsearchdet) {
235 $objsearchdet = $db->fetch_object($resqlsearchdet);
236 } else {
237 dol_print_error($db);
238 }
239
240 if ($objsearchdet) {
241 $sql = "UPDATE ".MAIN_DB_PREFIX.$expeditionlinebatch->table_element." SET";
242 $sql .= " eatby = ".($eatby ? "'".$db->idate($eatby)."'" : "null");
243 $sql .= " , sellby = ".($sellby ? "'".$db->idate($sellby)."'" : "null");
244 $sql .= " , qty = ".((float) $newqty);
245 // TODO Add a column fk_warehouse
246 $sql .= " WHERE rowid = ".((int) $objsearchdet->rowid);
247 } else {
248 $sql = "INSERT INTO ".MAIN_DB_PREFIX.$expeditionlinebatch->table_element." (";
249 $sql .= "fk_expeditiondet, eatby, sellby, batch, qty, fk_origin_stock)";
250 // TODO Add a column fk_warehouse
251 $sql .= " VALUES (".((int) $idline).", ".($eatby ? "'".$db->idate($eatby)."'" : "null").", ".($sellby ? "'".$db->idate($sellby)."'" : "null").", ";
252 $sql .= " '".$db->escape($lot)."', ".((float) $newqty).", 0)";
253 }
254 } else {
255 $sql = " DELETE FROM ".MAIN_DB_PREFIX.$expeditionlinebatch->table_element;
256 $sql .= " WHERE fk_expeditiondet = ".((int) $idline);
257 $sql .= " AND batch = '".$db->escape($lot)."'";
258 }
259
260 $resql = $db->query($sql);
261 if (!$resql) {
262 dol_print_error($db);
263 $error++;
264 }
265 }
266 }
267 } else {
268 $expeditiondispatch->fk_expedition = $object->id;
269 $expeditiondispatch->entrepot_id = GETPOST($ent, 'int');
270 $expeditiondispatch->fk_origin_line = GETPOST($fk_commandedet, 'int');
271 $expeditiondispatch->qty = $newqty;
272
273 if ($newqty > 0) {
274 $idline = $expeditiondispatch->insert($user);
275 if ($idline < 0) {
276 setEventMessages($expeditiondispatch->error, $expeditiondispatch->errors, 'errors');
277 $error++;
278 }
279
280 if ($modebatch == "batch" && !$error) {
281 $expeditionlinebatch->sellby = $dDLUO;
282 $expeditionlinebatch->eatby = $dDLC;
283 $expeditionlinebatch->batch = $lot;
284 $expeditionlinebatch->qty = $newqty;
285 $expeditionlinebatch->fk_origin_stock = 0;
286 $expeditionlinebatch->fk_warehouse = GETPOST($ent, 'int');
287
288 $result = $expeditionlinebatch->create($idline);
289 if ($result < 0) {
290 setEventMessages($expeditionlinebatch->error, $expeditionlinebatch->errors, 'errors');
291 $error++;
292 }
293 }
294 }
295 }
296
297 // If module stock is enabled and the stock decrease is done on edtion of this page
298 /*
299 if (!$error && GETPOST($ent, 'int') > 0 && isModEnabled('stock') && !empty($conf->global->STOCK_CALCULATE_ON_SHIPMENT_DISPATCH_ORDER)) {
300 $mouv = new MouvementStock($db);
301 $product = GETPOST($prod, 'int');
302 $entrepot = GETPOST($ent, 'int');
303 $qtymouv = price2num(GETPOST($qty, 'alpha'), 'MS') - $qtystart;
304 $price = price2num(GETPOST($pu), 'MU');
305 $comment = GETPOST('comment');
306 $inventorycode = dol_print_date(dol_now(), 'dayhourlog');
307 $now = dol_now();
308 $eatby = '';
309 $sellby = '';
310 $batch = '';
311 if ($modebatch == "batch") {
312 $eatby = $dDLUO;
313 $sellby = $dDLC;
314 $batch = $lot ;
315 }
316 if ($product > 0 && $qtymouv != 0) {
317 // $price should take into account discount (except if option STOCK_EXCLUDE_DISCOUNT_FOR_PMP is on)
318 $mouv->origin = $objectorder;
319 $mouv->setOrigin($objectorder->element, $objectorder->id);
320
321 // Method change if qty < 0
322 if (!empty($conf->global->SUPPLIER_ORDER_ALLOW_NEGATIVE_QTY_FOR_SUPPLIER_ORDER_RETURN) && $qtymouv < 0) {
323 $result = $mouv->reception($user, $product, $entrepot, $qtymouv*(-1), $price, $comment, $eatby, $sellby, $batch, '', 0, $inventorycode);
324 } else {
325 $result = $mouv->livraison($user, $product, $entrepot, $qtymouv, $price, $comment, $now, $eatby, $sellby, $batch, 0, $inventorycode);
326 }
327
328 if ($result < 0) {
329 setEventMessages($mouv->error, $mouv->errors, 'errors');
330 $error++;
331 }
332 }
333 }
334 */
335 }
336 }
337 }
338 }
339
340 if ($error > 0) {
341 $db->rollback();
342 setEventMessages($error, $errors, 'errors');
343 } else {
344 $db->commit();
345 setEventMessages($langs->trans("ReceptionUpdated"), null);
346
347 header("Location: ".DOL_URL_ROOT.'/expedition/dispatch.php?id='.$object->id);
348 exit;
349 }
350} elseif ($action == 'setdate_livraison' && $usercancreate) {
351 $datedelivery = dol_mktime(GETPOST('liv_hour', 'int'), GETPOST('liv_min', 'int'), 0, GETPOST('liv_month', 'int'), GETPOST('liv_day', 'int'), GETPOST('liv_year', 'int'));
352
353 $object->fetch($id);
354 $result = $object->setDeliveryDate($user, $datedelivery);
355 if ($result < 0) {
356 setEventMessages($object->error, $object->errors, 'errors');
357 }
358}
359
360
361/*
362 * View
363 */
364
365$now = dol_now();
366
367$form = new Form($db);
368$formproduct = new FormProduct($db);
369$warehouse_static = new Entrepot($db);
370
371$title = $object->ref." - ".$langs->trans('ShipmentDistribution');
372$help_url = 'EN:Module_Shipments|FR:Module_Expéditions|ES:M&oacute;dulo_Expediciones|DE:Modul_Lieferungen';
373$morejs = array('/expedition/js/lib_dispatch.js.php');
374
375llxHeader('', $title, $help_url, '', 0, 0, $morejs);
376
377if ($object->id > 0 || !empty($object->ref)) {
378 $lines = $object->lines; // This is an array of detail of line, on line per source order line found intolines[]->fk_origin_line, then each line may have sub data
379 //var_dump($lines[0]->fk_origin_line); exit;
380
381 $num_prod = count($lines);
382
383 if (!empty($object->origin) && $object->origin_id > 0) {
384 $object->origin = 'commande';
385 $typeobject = $object->origin;
386 $origin = $object->origin;
387 $origin_id = $object->origin_id;
388 $object->fetch_origin(); // Load property $object->commande, $object->propal, ...
389 }
390 $soc = new Societe($db);
391 $soc->fetch($object->socid);
392
393 $author = new User($db);
394 $author->fetch($object->user_author_id);
395
396 $head = shipping_prepare_head($object);
397
398 print dol_get_fiche_head($head, 'dispatch', $langs->trans("Shipment"), -1, $object->picto);
399
400
401 $formconfirm = '';
402
403 // Confirmation to delete line
404 if ($action == 'ask_deleteline') {
405 $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id.'&lineid='.$lineid, $langs->trans('DeleteLine'), $langs->trans('ConfirmDeleteLine'), 'confirm_deleteline', '', 0, 1);
406 }
407
408 // Call Hook formConfirm
409 $parameters = array('lineid' => $lineid);
410 // Note that $action and $object may be modified by hook
411 $reshook = $hookmanager->executeHooks('formConfirm', $parameters, $object, $action);
412 if (empty($reshook)) {
413 $formconfirm .= $hookmanager->resPrint;
414 } elseif ($reshook > 0) {
415 $formconfirm = $hookmanager->resPrint;
416 }
417
418 // Print form confirm
419 print $formconfirm;
420
421 if ($typeobject == 'commande' && $object->$typeobject->id && isModEnabled('commande')) {
422 $objectsrc = new Commande($db);
423 $objectsrc->fetch($object->$typeobject->id);
424 }
425 if ($typeobject == 'propal' && $object->$typeobject->id && isModEnabled("propal")) {
426 $objectsrc = new Propal($db);
427 $objectsrc->fetch($object->$typeobject->id);
428 }
429
430 // Shipment card
431 $linkback = '<a href="'.DOL_URL_ROOT.'/expedition/list.php?restore_lastsearch_values=1'.(!empty($socid) ? '&socid='.$socid : '').'">'.$langs->trans("BackToList").'</a>';
432 $morehtmlref = '<div class="refidno">';
433
434 // Ref customer shipment
435 $morehtmlref .= $form->editfieldkey("RefCustomer", 'ref_customer', $object->ref_customer, $object, $user->rights->expedition->creer, 'string', '', 0, 1);
436 $morehtmlref .= $form->editfieldval("RefCustomer", 'ref_customer', $object->ref_customer, $object, $user->rights->expedition->creer, 'string'.(isset($conf->global->THIRDPARTY_REF_INPUT_SIZE) ? ':'.$conf->global->THIRDPARTY_REF_INPUT_SIZE : ''), '', null, null, '', 1);
437
438 // Thirdparty
439 $morehtmlref .= '<br>'.$object->thirdparty->getNomUrl(1);
440 // Project
441 if (isModEnabled('project')) {
442 $langs->load("projects");
443 $morehtmlref .= '<br>';
444 if (0) { // Do not change on reception
445 $morehtmlref .= img_picto($langs->trans("Project"), 'project', 'class="pictofixedwidth"');
446 if ($action != 'classify' && $permissiontoadd) {
447 $morehtmlref .= '<a class="editfielda" href="'.$_SERVER['PHP_SELF'].'?action=classify&token='.newToken().'&id='.$object->id.'">'.img_edit($langs->transnoentitiesnoconv('SetProject')).'</a> ';
448 }
449 $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'].'?id='.$object->id, (empty($conf->global->PROJECT_CAN_ALWAYS_LINK_TO_ALL_SUPPLIERS) ? $object->socid : -1), $object->fk_project, ($action == 'classify' ? 'projectid' : 'none'), 0, 0, 0, 1, '', 'maxwidth300');
450 } else {
451 if (!empty($objectsrc) && !empty($objectsrc->fk_project)) {
452 $proj = new Project($db);
453 $proj->fetch($objectsrc->fk_project);
454 $morehtmlref .= $proj->getNomUrl(1);
455 if ($proj->title) {
456 $morehtmlref .= '<span class="opacitymedium"> - '.dol_escape_htmltag($proj->title).'</span>';
457 }
458 }
459 }
460 }
461 $morehtmlref .= '</div>';
462
463 dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref);
464
465
466 print '<div class="fichecenter">';
467 print '<div class="underbanner clearboth"></div>';
468
469 print '<table class="border tableforfield centpercent">';
470
471 // Linked documents
472 if ($typeobject == 'commande' && $object->$typeobject->id && isModEnabled('commande')) {
473 print '<tr><td>';
474 print $langs->trans("RefOrder").'</td>';
475 print '<td colspan="3">';
476 print $objectsrc->getNomUrl(1, 'commande');
477 print "</td>\n";
478 print '</tr>';
479 }
480 if ($typeobject == 'propal' && $object->$typeobject->id && isModEnabled("propal")) {
481 print '<tr><td>';
482 print $langs->trans("RefProposal").'</td>';
483 print '<td colspan="3">';
484 print $objectsrc->getNomUrl(1, 'expedition');
485 print "</td>\n";
486 print '</tr>';
487 }
488
489 // Date creation
490 print '<tr><td class="titlefield">'.$langs->trans("DateCreation").'</td>';
491 print '<td colspan="3">'.dol_print_date($object->date_creation, "dayhour", "tzuserrel")."</td>\n";
492 print '</tr>';
493
494 // Delivery date planned
495 print '<tr><td height="10">';
496 print '<table class="nobordernopadding" width="100%"><tr><td>';
497 print $langs->trans('DateDeliveryPlanned');
498 print '</td>';
499 if ($action != 'editdate_livraison') {
500 print '<td class="right"><a class="editfielda" href="'.$_SERVER["PHP_SELF"].'?action=editdate_livraison&token='.newToken().'&id='.$object->id.'">'.img_edit($langs->trans('SetDeliveryDate'), 1).'</a></td>';
501 }
502 print '</tr></table>';
503 print '</td><td colspan="2">';
504 if ($action == 'editdate_livraison') {
505 print '<form name="setdate_livraison" action="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'" method="post">';
506 print '<input type="hidden" name="token" value="'.newToken().'">';
507 print '<input type="hidden" name="action" value="setdate_livraison">';
508 print $form->selectDate($object->date_delivery ? $object->date_delivery : -1, 'liv_', 1, 1, '', "setdate_livraison", 1, 0);
509 print '<input type="submit" class="button button-edit smallpaddingimp" value="'.$langs->trans('Modify').'">';
510 print '</form>';
511 } else {
512 print $object->date_delivery ? dol_print_date($object->date_delivery, 'dayhour') : '&nbsp;';
513 }
514 print '</td>';
515 print '</tr></table>';
516
517 print '<br><center>';
518 print '<a href="#" id="resetalltoexpected" class="marginrightonly paddingright marginleftonly paddingleft">'.img_picto("", 'autofill', 'class="pictofixedwidth"').$langs->trans("RestoreWithCurrentQtySaved").'</a></td>';
519 // Link to clear qty
520 print '<a href="#" id="autoreset" class="marginrightonly paddingright marginleftonly paddingleft">'.img_picto("", 'eraser', 'class="pictofixedwidth"').$langs->trans("ClearQtys").'</a></td>';
521 print '<center>';
522
523 print '<br>';
524 $disabled = 0; // This is used to disable or not the bulk selection of target warehouse. No reason to have it disabled so forced to 0.
525
526 if ($object->statut == Expedition::STATUS_DRAFT) {
527 require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php';
528 $formproduct = new FormProduct($db);
529 $formproduct->loadWarehouses();
530 $entrepot = new Entrepot($db);
531 $listwarehouses = $entrepot->list_array(1);
532
533
534 print '<form method="post" action="'.$_SERVER["PHP_SELF"].'">';
535
536 print '<input type="hidden" name="token" value="'.newToken().'">';
537 print '<input type="hidden" name="action" value="updatelines">';
538 print '<input type="hidden" name="id" value="'.$object->id.'">';
539
540 print '<div class="div-table-responsive-no-min">';
541 print '<table class="noborder centpercent">';
542
543 // Get list of lines of the shipment $products_dispatched, with qty dispatched for each product id
544 $products_dispatched = array();
545 $sql = "SELECT ed.fk_origin_line as rowid, sum(ed.qty) as qty";
546 $sql .= " FROM ".MAIN_DB_PREFIX."expeditiondet as ed";
547 $sql .= " WHERE ed.fk_expedition = ".((int) $object->id);
548 $sql .= " GROUP BY ed.fk_origin_line";
549
550 $resql = $db->query($sql);
551 if ($resql) {
552 $num = $db->num_rows($resql);
553 $i = 0;
554
555 if ($num) {
556 while ($i < $num) {
557 $objd = $db->fetch_object($resql);
558 $products_dispatched[$objd->rowid] = price2num($objd->qty, 'MS');
559 $i++;
560 }
561 }
562 $db->free($resql);
563 }
564
565 //$sql = "SELECT l.rowid, l.fk_product, l.subprice, l.remise_percent, l.ref AS sref, SUM(l.qty) as qty,";
566 $sql = "SELECT l.rowid, l.fk_product, l.subprice, l.remise_percent, '' AS sref, l.qty as qty,";
567 $sql .= " p.ref, p.label, p.tobatch, p.fk_default_warehouse";
568 // Enable hooks to alter the SQL query (SELECT)
569 $parameters = array();
570 $reshook = $hookmanager->executeHooks(
571 'printFieldListSelect',
572 $parameters,
573 $object,
574 $action
575 );
576 if ($reshook < 0) {
577 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
578 }
579 $sql .= $hookmanager->resPrint;
580
581 $sql .= " FROM ".MAIN_DB_PREFIX."commandedet as l";
582 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product as p ON l.fk_product=p.rowid";
583 $sql .= " WHERE l.fk_commande = ".((int) $objectsrc->id);
584 if (empty($conf->global->STOCK_SUPPORTS_SERVICES)) {
585 $sql .= " AND l.product_type = 0";
586 }
587 // Enable hooks to alter the SQL query (WHERE)
588 $parameters = array();
589 $reshook = $hookmanager->executeHooks(
590 'printFieldListWhere',
591 $parameters,
592 $object,
593 $action
594 );
595 if ($reshook < 0) {
596 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
597 }
598 $sql .= $hookmanager->resPrint;
599
600 //$sql .= " GROUP BY p.ref, p.label, p.tobatch, p.fk_default_warehouse, l.rowid, l.fk_product, l.subprice, l.remise_percent, l.ref"; // Calculation of amount dispatched is done per fk_product so we must group by fk_product
601 $sql .= " ORDER BY l.rang, p.ref, p.label";
602
603 $resql = $db->query($sql);
604 if ($resql) {
605 $num = $db->num_rows($resql);
606 $i = 0;
607 $numline = 1;
608
609 if ($num) {
610 print '<tr class="liste_titre">';
611
612 print '<td>'.$langs->trans("Description").'</td>';
613 if (isModEnabled('productbatch')) {
614 print '<td class="dispatch_batch_number_title">'.$langs->trans("batch_number").'</td>';
615 if (empty($conf->global->PRODUCT_DISABLE_SELLBY)) {
616 print '<td class="dispatch_dlc_title">'.$langs->trans("SellByDate").'</td>';
617 }
618 if (empty($conf->global->PRODUCT_DISABLE_EATBY)) {
619 print '<td class="dispatch_dluo_title">'.$langs->trans("EatByDate").'</td>';
620 }
621 } else {
622 print '<td></td>';
623 print '<td></td>';
624 print '<td></td>';
625 }
626 print '<td class="right">'.$langs->trans("QtyOrdered").'</td>';
627 if ($object->status == Expedition::STATUS_DRAFT) {
628 print '<td class="right">'.$langs->trans("QtyToShip"); // Qty to dispatch (sum for all lines of batch detail if there is)
629 } else {
630 print '<td class="right">'.$langs->trans("QtyDispatchedShort").'</td>';
631 }
632 print '<td class="right">'.$langs->trans("Details");
633 print '<td width="32"></td>';
634
635 if (!empty($conf->global->SUPPLIER_ORDER_CAN_UPDATE_BUYINGPRICE_DURING_RECEIPT)) {
636 if (!isModEnabled("multicurrency") && empty($conf->dynamicprices->enabled)) {
637 print '<td class="right">'.$langs->trans("Price").'</td>';
638 print '<td class="right">'.$langs->trans("ReductionShort").' (%)</td>';
639 print '<td class="right">'.$langs->trans("UpdatePrice").'</td>';
640 }
641 }
642
643 print '<td align="right">'.$langs->trans("Warehouse");
644
645 // Select warehouse to force it everywhere
646 if (count($listwarehouses) > 1) {
647 print '<br><span class="opacitymedium">'.$langs->trans("ForceTo").'</span> '.$form->selectarray('fk_default_warehouse', $listwarehouses, $fk_default_warehouse, 1, 0, 0, '', 0, 0, $disabled, '', 'minwidth100 maxwidth300', 1);
648 } elseif (count($listwarehouses) == 1) {
649 print '<br><span class="opacitymedium">'.$langs->trans("ForceTo").'</span> '.$form->selectarray('fk_default_warehouse', $listwarehouses, $fk_default_warehouse, 0, 0, 0, '', 0, 0, $disabled, '', 'minwidth100 maxwidth300', 1);
650 }
651
652 print '</td>';
653
654 // Enable hooks to append additional columns
655 $parameters = array();
656 $reshook = $hookmanager->executeHooks(
657 'printFieldListTitle',
658 $parameters,
659 $object,
660 $action
661 );
662 if ($reshook < 0) {
663 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
664 }
665 print $hookmanager->resPrint;
666
667 print "</tr>\n";
668 }
669
670 $nbfreeproduct = 0; // Nb of lins of free products/services
671 $nbproduct = 0; // Nb of predefined product lines to dispatch (already done or not) if SUPPLIER_ORDER_DISABLE_STOCK_DISPATCH_WHEN_TOTAL_REACHED is off (default)
672 // or nb of line that remain to dispatch if SUPPLIER_ORDER_DISABLE_STOCK_DISPATCH_WHEN_TOTAL_REACHED is on.
673
674 $conf->cache['product'] = array();
675
676 // Loop on each line of origin order
677 while ($i < $num) {
678 $objp = $db->fetch_object($resql);
679
680 // On n'affiche pas les produits libres
681 if (!$objp->fk_product > 0) {
682 $nbfreeproduct++;
683 } else {
684 $alreadydispatched = isset($products_dispatched[$objp->rowid])?$products_dispatched[$objp->rowid]:0;
685 $remaintodispatch = price2num($objp->qty, 5); // Calculation of dispatched
686 if ($remaintodispatch < 0 && empty($conf->global->SUPPLIER_ORDER_ALLOW_NEGATIVE_QTY_FOR_SUPPLIER_ORDER_RETURN)) {
687 $remaintodispatch = 0;
688 }
689
690 if ($remaintodispatch || empty($conf->global->SUPPLIER_ORDER_DISABLE_STOCK_DISPATCH_WHEN_TOTAL_REACHED)) {
691 $nbproduct++;
692
693 // To show detail cref and description value, we must make calculation by cref
694 // print ($objp->cref?' ('.$objp->cref.')':'');
695 // if ($objp->description) print '<br>'.nl2br($objp->description);
696 $suffix = '_0_'.$i;
697
698 print "\n";
699 print '<!-- Line to dispatch '.$suffix.' -->'."\n";
700 // hidden fields for js function
701 print '<input id="qty_ordered'.$suffix.'" type="hidden" value="'.$objp->qty.'">';
702 print '<input id="qty_dispatched'.$suffix.'" type="hidden" data-dispatched="'.((float) $alreadydispatched).'" value="'.(float) $alreadydispatched.'">';
703 print '<tr class="oddeven">';
704
705 if (empty($conf->cache['product'][$objp->fk_product])) {
706 $tmpproduct = new Product($db);
707 $tmpproduct->fetch($objp->fk_product);
708 $conf->cache['product'][$objp->fk_product] = $tmpproduct;
709 } else {
710 $tmpproduct = $conf->cache['product'][$objp->fk_product];
711 }
712
713 $linktoprod = $tmpproduct->getNomUrl(1);
714 $linktoprod .= ' - '.$objp->label."\n";
715
716 if (isModEnabled('productbatch')) {
717 if ($objp->tobatch) {
718 // Product
719 print '<td>';
720 print $linktoprod;
721 print "</td>";
722 print '<td class="dispatch_batch_number"></td>';
723 if (empty($conf->global->PRODUCT_DISABLE_SELLBY)) {
724 print '<td class="dispatch_dlc"></td>';
725 }
726 if (empty($conf->global->PRODUCT_DISABLE_EATBY)) {
727 print '<td class="dispatch_dluo"></td>';
728 }
729 } else {
730 // Product
731 print '<td>';
732 print $linktoprod;
733 print "</td>";
734 print '<td class="dispatch_batch_number">';
735 print '<span class="opacitymedium small">'.$langs->trans("ProductDoesNotUseBatchSerial").'</span>';
736 print '</td>';
737 if (empty($conf->global->PRODUCT_DISABLE_SELLBY)) {
738 print '<td class="dispatch_dlc"></td>';
739 }
740 if (empty($conf->global->PRODUCT_DISABLE_EATBY)) {
741 print '<td class="dispatch_dluo"></td>';
742 }
743 }
744 } else {
745 print '<td colspan="4">';
746 print $linktoprod;
747 print "</td>";
748 }
749
750 // Define unit price for PMP calculation
751 $up_ht_disc = $objp->subprice;
752 if (!empty($objp->remise_percent) && empty($conf->global->STOCK_EXCLUDE_DISCOUNT_FOR_PMP)) {
753 $up_ht_disc = price2num($up_ht_disc * (100 - $objp->remise_percent) / 100, 'MU');
754 }
755
756 // Qty ordered
757 print '<td class="right">'.$objp->qty.'</td>';
758
759 // Already dispatched
760 print '<td class="right">'.$alreadydispatched.'</td>';
761
762 print '<td class="right">';
763 print '</td>'; // Qty to dispatch
764 print '<td>';
765 print '</td>'; // Dispatch column
766 print '<td></td>'; // Warehouse column
767
768 /*$sql = "SELECT cfd.rowid, cfd.qty, cfd.fk_entrepot, cfd.batch, cfd.eatby, cfd.sellby, cfd.fk_product";
769 $sql .= " FROM ".MAIN_DB_PREFIX."commande_fournisseur_dispatch as cfd";
770 $sql .= " WHERE cfd.fk_commandefourndet = ".(int) $objp->rowid;*/
771
772 $sql = "SELECT ed.rowid, ed.qty, ed.fk_entrepot, eb.batch, eb.eatby, eb.sellby, cd.fk_product";
773 $sql .= " FROM ".MAIN_DB_PREFIX."expeditiondet as ed";
774 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."expeditiondet_batch as eb on ed.rowid = eb.fk_expeditiondet";
775 $sql .= " JOIN ".MAIN_DB_PREFIX."commandedet as cd on ed.fk_origin_line = cd.rowid";
776 $sql .= " WHERE ed.fk_origin_line =".(int) $objp->rowid;
777 $sql .= " AND ed.fk_expedition =".(int) $object->id;
778 $sql .= " ORDER BY ed.rowid, ed.fk_origin_line";
779
780 $resultsql = $db->query($sql);
781 $j = 0;
782 if ($resultsql) {
783 $numd = $db->num_rows($resultsql);
784
785 while ($j < $numd) {
786 $suffix = "_".$j."_".$i;
787 $objd = $db->fetch_object($resultsql);
788
789 if (isModEnabled('productbatch') && (!empty($objd->batch) || (is_null($objd->batch) && $tmpproduct->status_batch > 0))) {
790 $type = 'batch';
791
792 // Enable hooks to append additional columns
793 $parameters = array(
794 // allows hook to distinguish between the rows with information and the rows with dispatch form input
795 'is_information_row' => true,
796 'j' => $j,
797 'suffix' => $suffix,
798 'objd' => $objd,
799 );
800 $reshook = $hookmanager->executeHooks(
801 'printFieldListValue',
802 $parameters,
803 $object,
804 $action
805 );
806 if ($reshook < 0) {
807 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
808 }
809 print $hookmanager->resPrint;
810
811 print '</tr>';
812
813 print '<!-- line for batch '.$numline.' -->';
814 print '<tr class="oddeven autoresettr" name="'.$type.$suffix.'" data-remove="clear">';
815 print '<td>';
816 print '<input id="fk_commandedet'.$suffix.'" name="fk_commandedet'.$suffix.'" type="hidden" value="'.$objp->rowid.'">';
817 print '<input id="idline'.$suffix.'" name="idline'.$suffix.'" type="hidden" value="'.$objd->rowid.'">';
818 print '<input name="product_batch'.$suffix.'" type="hidden" value="'.$objd->fk_product.'">';
819
820 print '<!-- This is a U.P. (may include discount or not depending on STOCK_EXCLUDE_DISCOUNT_FOR_PMP. will be used for PMP calculation) -->';
821 print '<input class="maxwidth75" name="pu'.$suffix.'" type="hidden" value="'.price2num($up_ht_disc, 'MU').'">';
822
823 print '</td>';
824
825 print '<td>';
826 print '<input type="text" class="inputlotnumber quatrevingtquinzepercent" id="lot_number'.$suffix.'" name="lot_number'.$suffix.'" value="'.(GETPOSTISSET('lot_number'.$suffix) ? GETPOST('lot_number'.$suffix) : $objd->batch).'">';
827 //print '<input type="hidden" id="lot_number'.$suffix.'" name="lot_number'.$suffix.'" value="'.$objd->batch.'">';
828 print '</td>';
829 if (empty($conf->global->PRODUCT_DISABLE_SELLBY)) {
830 print '<td class="nowraponall">';
831 $dlcdatesuffix = !empty($objd->sellby) ? dol_stringtotime($objd->sellby) : dol_mktime(0, 0, 0, GETPOST('dlc'.$suffix.'month'), GETPOST('dlc'.$suffix.'day'), GETPOST('dlc'.$suffix.'year'));
832 print $form->selectDate($dlcdatesuffix, 'dlc'.$suffix, '', '', 1, '');
833 print '</td>';
834 }
835 if (empty($conf->global->PRODUCT_DISABLE_EATBY)) {
836 print '<td class="nowraponall">';
837 $dluodatesuffix = !empty($objd->eatby) ? dol_stringtotime($objd->eatby) : dol_mktime(0, 0, 0, GETPOST('dluo'.$suffix.'month'), GETPOST('dluo'.$suffix.'day'), GETPOST('dluo'.$suffix.'year'));
838 print $form->selectDate($dluodatesuffix, 'dluo'.$suffix, '', '', 1, '');
839 print '</td>';
840 }
841 print '<td colspan="2">&nbsp;</td>'; // Supplier ref + Qty ordered + qty already dispatched
842 } else {
843 $type = 'dispatch';
844 $colspan = 6;
845 $colspan = (!empty($conf->global->PRODUCT_DISABLE_SELLBY)) ? --$colspan : $colspan;
846 $colspan = (!empty($conf->global->PRODUCT_DISABLE_EATBY)) ? --$colspan : $colspan;
847
848 // Enable hooks to append additional columns
849 $parameters = array(
850 // allows hook to distinguish between the rows with information and the rows with dispatch form input
851 'is_information_row' => true,
852 'j' => $j,
853 'suffix' => $suffix,
854 'objd' => $objd,
855 );
856 $reshook = $hookmanager->executeHooks(
857 'printFieldListValue',
858 $parameters,
859 $object,
860 $action
861 );
862 if ($reshook < 0) {
863 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
864 }
865 print $hookmanager->resPrint;
866
867 print '</tr>';
868
869 print '<!-- line no batch '.$numline.' -->';
870 print '<tr class="oddeven autoresettr" name="'.$type.$suffix.'" data-remove="clear">';
871 print '<td colspan="'.$colspan.'">';
872 print '<input id="fk_commandedet'.$suffix.'" name="fk_commandedet'.$suffix.'" type="hidden" value="'.$objp->rowid.'">';
873 print '<input id="idline'.$suffix.'" name="idline'.$suffix.'" type="hidden" value="'.$objd->rowid.'">';
874 print '<input name="product'.$suffix.'" type="hidden" value="'.$objd->fk_product.'">';
875 print '<!-- This is a up (may include discount or not depending on STOCK_EXCLUDE_DISCOUNT_FOR_PMP. will be used for PMP calculation) -->';
876 print '<input class="maxwidth75" name="pu'.$suffix.'" type="hidden" value="'.price2num($up_ht_disc, 'MU').'">';
877 print '</td>';
878 }
879 // Qty to dispatch
880 print '<td class="right">';
881 print '<a href="" id="reset'.$suffix.'" class="resetline">'.img_picto($langs->trans("Reset"), 'eraser', 'class="pictofixedwidth opacitymedium"').'</a>';
882 $suggestedvalue = (GETPOSTISSET('qty'.$suffix) ? GETPOST('qty'.$suffix, 'int') : $objd->qty);
883 //var_dump($suggestedvalue);exit;
884 print '<input id="qty'.$suffix.'" onchange="onChangeDispatchLineQty($(this))" name="qty'.$suffix.'" data-type="'.$type.'" data-index="'.$i.'" class="width50 right qtydispatchinput" value="'.$suggestedvalue.'" data-expected="'.$objd->qty.'">';
885 print '</td>';
886 print '<td>';
887 if (isModEnabled('productbatch') && $objp->tobatch > 0) {
888 $type = 'batch';
889 print img_picto($langs->trans('AddStockLocationLine'), 'split.png', 'class="splitbutton" '.($numd != $j+1 ? 'style="display:none"' : '').' onClick="addDispatchLine('.$i.', \''.$type.'\')"');
890 } else {
891 $type = 'dispatch';
892 print img_picto($langs->trans('AddStockLocationLine'), 'split.png', 'class="splitbutton" '.($numd != $j+1 ? 'style="display:none"' : '').' onClick="addDispatchLine('.$i.', \''.$type.'\')"');
893 }
894
895 print '</td>';
896
897 // Warehouse
898 print '<td class="right">';
899 if (count($listwarehouses) > 1) {
900 print $formproduct->selectWarehouses(GETPOST("entrepot".$suffix) ?GETPOST("entrepot".$suffix) : $objd->fk_entrepot, "entrepot".$suffix, '', 1, 0, $objp->fk_product, '', 1, 0, null, 'csswarehouse'.$suffix);
901 } elseif (count($listwarehouses) == 1) {
902 print $formproduct->selectWarehouses(GETPOST("entrepot".$suffix) ?GETPOST("entrepot".$suffix) : $objd->fk_entrepot, "entrepot".$suffix, '', 0, 0, $objp->fk_product, '', 1, 0, null, 'csswarehouse'.$suffix);
903 } else {
904 $langs->load("errors");
905 print $langs->trans("ErrorNoWarehouseDefined");
906 }
907 print "</td>\n";
908
909 // Enable hooks to append additional columns
910 $parameters = array(
911 'is_information_row' => false, // this is a dispatch form row
912 'i' => $i,
913 'suffix' => $suffix,
914 'objp' => $objp,
915 );
916 $reshook = $hookmanager->executeHooks(
917 'printFieldListValue',
918 $parameters,
919 $object,
920 $action
921 );
922 if ($reshook < 0) {
923 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
924 }
925 print $hookmanager->resPrint;
926
927 print "</tr>\n";
928 $j++;
929
930 $numline++;
931 }
932 $suffix = "_".$j."_".$i;
933 }
934
935 if ($j == 0) {
936 if (isModEnabled('productbatch') && !empty($objp->tobatch)) {
937 $type = 'batch';
938
939 // Enable hooks to append additional columns
940 $parameters = array(
941 // allows hook to distinguish between the rows with information and the rows with dispatch form input
942 'is_information_row' => true,
943 'j' => $j,
944 'suffix' => $suffix,
945 'objp' => $objp,
946 );
947 $reshook = $hookmanager->executeHooks(
948 'printFieldListValue',
949 $parameters,
950 $object,
951 $action
952 );
953 if ($reshook < 0) {
954 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
955 }
956 print $hookmanager->resPrint;
957
958 print '</tr>';
959
960 print '<!-- line for batch '.$numline.' (not dispatched line yet for this order line) -->';
961 print '<tr class="oddeven autoresettr" name="'.$type.$suffix.'">';
962 print '<td>';
963 print '<input id="fk_commandedet'.$suffix.'" name="fk_commandedet'.$suffix.'" type="hidden" value="'.$objp->rowid.'">';
964 print '<input id="idline'.$suffix.'" name="idline'.$suffix.'" type="hidden" value="-1">';
965 print '<input name="product_batch'.$suffix.'" type="hidden" value="'.$objp->fk_product.'">';
966
967 print '<!-- This is a up (may include discount or not depending on STOCK_EXCLUDE_DISCOUNT_FOR_PMP. will be used for PMP calculation) -->';
968 print '<input class="maxwidth75" name="pu'.$suffix.'" type="hidden" value="'.price2num($up_ht_disc, 'MU').'">';
969 print '</td>';
970
971 print '<td>';
972 print '<input type="text" class="inputlotnumber quatrevingtquinzepercent" id="lot_number'.$suffix.'" name="lot_number'.$suffix.'" value="'.GETPOST('lot_number'.$suffix).'">';
973 print '</td>';
974 if (empty($conf->global->PRODUCT_DISABLE_SELLBY)) {
975 print '<td class="nowraponall">';
976 $dlcdatesuffix = dol_mktime(0, 0, 0, GETPOST('dlc'.$suffix.'month'), GETPOST('dlc'.$suffix.'day'), GETPOST('dlc'.$suffix.'year'));
977 print $form->selectDate($dlcdatesuffix, 'dlc'.$suffix, '', '', 1, '');
978 print '</td>';
979 }
980 if (empty($conf->global->PRODUCT_DISABLE_EATBY)) {
981 print '<td class="nowraponall">';
982 $dluodatesuffix = dol_mktime(0, 0, 0, GETPOST('dluo'.$suffix.'month'), GETPOST('dluo'.$suffix.'day'), GETPOST('dluo'.$suffix.'year'));
983 print $form->selectDate($dluodatesuffix, 'dluo'.$suffix, '', '', 1, '');
984 print '</td>';
985 }
986 print '<td colspan="2">&nbsp;</td>'; // Supplier ref + Qty ordered + qty already dispatched
987 } else {
988 $type = 'dispatch';
989 $colspan = 6;
990 $colspan = (!empty($conf->global->PRODUCT_DISABLE_SELLBY)) ? --$colspan : $colspan;
991 $colspan = (!empty($conf->global->PRODUCT_DISABLE_EATBY)) ? --$colspan : $colspan;
992
993 // Enable hooks to append additional columns
994 $parameters = array(
995 // allows hook to distinguish between the rows with information and the rows with dispatch form input
996 'is_information_row' => true,
997 'j' => $j,
998 'suffix' => $suffix,
999 'objp' => $objp,
1000 );
1001 $reshook = $hookmanager->executeHooks(
1002 'printFieldListValue',
1003 $parameters,
1004 $object,
1005 $action
1006 );
1007 if ($reshook < 0) {
1008 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
1009 }
1010 print $hookmanager->resPrint;
1011
1012 print '</tr>';
1013
1014 print '<!-- line no batch '.$numline.' (not dispatched line yet for this order line) -->';
1015 print '<tr class="oddeven autoresettr" name="'.$type.$suffix.'" data-remove="clear">';
1016 print '<td colspan="'.$colspan.'">';
1017 print '<input id="fk_commandedet'.$suffix.'" name="fk_commandedet'.$suffix.'" type="hidden" value="'.$objp->rowid.'">';
1018 print '<input id="idline'.$suffix.'" name="idline'.$suffix.'" type="hidden" value="-1">';
1019 print '<input name="product'.$suffix.'" type="hidden" value="'.$objp->fk_product.'">';
1020
1021 print '<!-- This is a up (may include discount or not depending on STOCK_EXCLUDE_DISCOUNT_FOR_PMP. will be used for PMP calculation) -->';
1022 print '<input class="maxwidth75" name="pu'.$suffix.'" type="hidden" value="'.price2num($up_ht_disc, 'MU').'">';
1023 print '</td>';
1024 }
1025 // Qty to dispatch
1026 print '<td class="right">';
1027 print '<a href="" id="reset'.$suffix.'" class="resetline">'.img_picto($langs->trans("Reset"), 'eraser', 'class="pictofixedwidth opacitymedium"').'</a>';
1028 $amounttosuggest = (GETPOSTISSET('qty'.$suffix) ? GETPOST('qty'.$suffix, 'int') : (empty($conf->global->SUPPLIER_ORDER_DISPATCH_FORCE_QTY_INPUT_TO_ZERO) ? $remaintodispatch : 0));
1029 if (count($products_dispatched)) {
1030 // There is already existing lines into llx_expeditiondet, this means a plan for the shipment has already been started.
1031 // In such a case, we do not suggest new values, we suggest the value known.
1032 $amounttosuggest = (GETPOSTISSET('qty'.$suffix) ? GETPOST('qty'.$suffix, 'int') : (isset($products_dispatched[$objp->rowid]) ? $products_dispatched[$objp->rowid] : ''));
1033 }
1034 print '<input id="qty'.$suffix.'" onchange="onChangeDispatchLineQty($(this))" name="qty'.$suffix.'" data-index="'.$i.'" data-type="text" class="width50 right qtydispatchinput" value="'.$amounttosuggest.'" data-expected="'.$amounttosuggest.'">';
1035 print '</td>';
1036 print '<td>';
1037 if (isModEnabled('productbatch') && $objp->tobatch > 0) {
1038 $type = 'batch';
1039 print img_picto($langs->trans('AddStockLocationLine'), 'split.png', 'class="splitbutton" onClick="addDispatchLine('.$i.', \''.$type.'\')"');
1040 } else {
1041 $type = 'dispatch';
1042 print img_picto($langs->trans('AddStockLocationLine'), 'split.png', 'class="splitbutton" onClick="addDispatchLine('.$i.', \''.$type.'\')"');
1043 }
1044
1045 print '</td>';
1046
1047 // Warehouse
1048 print '<td class="right">';
1049 if (count($listwarehouses) > 1) {
1050 print $formproduct->selectWarehouses(GETPOST("entrepot".$suffix) ?GETPOST("entrepot".$suffix) : ($objp->fk_default_warehouse ? $objp->fk_default_warehouse : ''), "entrepot".$suffix, '', 1, 0, $objp->fk_product, '', 1, 0, null, 'csswarehouse'.$suffix);
1051 } elseif (count($listwarehouses) == 1) {
1052 print $formproduct->selectWarehouses(GETPOST("entrepot".$suffix) ?GETPOST("entrepot".$suffix) : ($objp->fk_default_warehouse ? $objp->fk_default_warehouse : ''), "entrepot".$suffix, '', 0, 0, $objp->fk_product, '', 1, 0, null, 'csswarehouse'.$suffix);
1053 } else {
1054 $langs->load("errors");
1055 print $langs->trans("ErrorNoWarehouseDefined");
1056 }
1057 print "</td>\n";
1058
1059 // Enable hooks to append additional columns
1060 $parameters = array(
1061 'is_information_row' => false, // this is a dispatch form row
1062 'i' => $i,
1063 'suffix' => $suffix,
1064 'objp' => $objp,
1065 );
1066 $reshook = $hookmanager->executeHooks(
1067 'printFieldListValue',
1068 $parameters,
1069 $object,
1070 $action
1071 );
1072 if ($reshook < 0) {
1073 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
1074 }
1075 print $hookmanager->resPrint;
1076 print "</tr>\n";
1077 }
1078 }
1079 }
1080 $i++;
1081 }
1082 $db->free($resql);
1083 } else {
1084 dol_print_error($db);
1085 }
1086
1087 print "</table>\n";
1088 print '</div>';
1089
1090 if ($nbproduct) {
1091 //$checkboxlabel = $langs->trans("CloseReceivedSupplierOrdersAutomatically", $langs->transnoentitiesnoconv('StatusOrderReceivedAll'));
1092
1093 print '<div class="center">';
1094 $parameters = array();
1095 $reshook = $hookmanager->executeHooks('addMoreActionsButtons', $parameters, $object, $action); // Note that $action and $object may have been
1096 // modified by hook
1097 if (empty($reshook)) {
1098 /*if (empty($conf->reception->enabled)) {
1099 print $langs->trans("Comment").' : ';
1100 print '<input type="text" class="minwidth400" maxlength="128" name="comment" value="';
1101 print GETPOSTISSET("comment") ? GETPOST("comment") : $langs->trans("DispatchSupplierOrder", $object->ref);
1102 // print ' / '.$object->ref_supplier; // Not yet available
1103 print '" class="flat"><br>';
1104
1105 print '<input type="checkbox" checked="checked" name="closeopenorder"> '.$checkboxlabel;
1106 }
1107
1108 $dispatchBt = empty($conf->reception->enabled) ? $langs->trans("Receive") : $langs->trans("CreateReception");
1109
1110 print '<br>';
1111 */
1112
1113 print '<input type="submit" id="submitform" class="button" name="dispatch" value="'.$langs->trans("Save").'"';
1114 $disabled = 0;
1115 if (!$usercancreate) {
1116 $disabled = 1;
1117 }
1118 if (count($listwarehouses) <= 0) {
1119 $disabled = 1;
1120 }
1121 if ($disabled) {
1122 print ' disabled';
1123 }
1124
1125 print '>';
1126 }
1127 print '</div>';
1128 }
1129
1130 // Message if nothing to dispatch
1131 if (!$nbproduct) {
1132 print "<br>\n";
1133 if (empty($conf->global->SUPPLIER_ORDER_DISABLE_STOCK_DISPATCH_WHEN_TOTAL_REACHED)) {
1134 print '<div class="opacitymedium">'.$langs->trans("NoPredefinedProductToDispatch").'</div>'; // No predefined line at all
1135 } else {
1136 print '<div class="opacitymedium">'.$langs->trans("NoMorePredefinedProductToDispatch").'</div>'; // No predefined line that remain to be dispatched.
1137 }
1138 }
1139
1140 print '</form>';
1141 }
1142
1143 print dol_get_fiche_end();
1144
1145 // traitement entrepot par défaut
1146 print '<script type="text/javascript">
1147 $(document).ready(function () {
1148 $("select[name=fk_default_warehouse]").change(function() {
1149 console.log("warehouse is modified");
1150 var fk_default_warehouse = $("option:selected", this).val();
1151 $("select[name^=entrepot_]").val(fk_default_warehouse).change();
1152 });
1153
1154 $("#autoreset").click(function() {
1155 console.log("we click on autoreset");
1156 $(".autoresettr").each(function(){
1157 id = $(this).attr("name");
1158 idtab = id.split("_");
1159 if ($(this).data("remove") == "clear"){
1160 console.log("We clear the object to expected value")
1161 $("#qty_"+idtab[1]+"_"+idtab[2]).val("");
1162 /*
1163 qtyexpected = $("#qty_"+idtab[1]+"_"+idtab[2]).data("expected")
1164 console.log(qtyexpected);
1165 $("#qty_"+idtab[1]+"_"+idtab[2]).val(qtyexpected);
1166 qtydispatched = $("#qty_dispatched_0_"+idtab[2]).data("dispatched")
1167 $("#qty_dispatched_0_"+idtab[2]).val(qtydispatched);
1168 */
1169 } else {
1170 console.log("We remove the object")
1171 $(this).remove();
1172 $("tr[name^=\'"+idtab[0]+"_\'][name$=\'_"+idtab[2]+"\']:last .splitbutton").show();
1173 }
1174 });
1175 return false;
1176 });
1177
1178 $("#resetalltoexpected").click(function(){
1179 $(".qtydispatchinput").each(function(){
1180 console.log("We reset to expected "+$(this).attr("id")+" qty to dispatch");
1181 $(this).val($(this).data("expected"));
1182 });
1183 return false;
1184 });
1185
1186 $(".resetline").on("click", function(event) {
1187 event.preventDefault();
1188 id = $(this).attr("id");
1189 id = id.split("reset_");
1190 console.log("Reset trigger for id = qty_"+id[1]);
1191 $("#qty_"+id[1]).val("");
1192 });
1193 });
1194 </script>';
1195}
1196
1197// End of page
1198llxFooter();
1199$db->close();
if(!defined('NOREQUIRESOC')) if(!defined( 'NOREQUIRETRAN')) if(!defined('NOTOKENRENEWAL')) if(!defined( 'NOREQUIREMENU')) if(!defined('NOREQUIREHTML')) if(!defined( 'NOREQUIREAJAX')) llxHeader()
Empty header.
Definition wrapper.php:56
llxFooter()
Empty footer.
Definition wrapper.php:70
Class to manage customers orders.
Class to manage comment.
Class to manage warehouses.
Class to manage shipments.
const STATUS_DRAFT
Draft status.
Classe to manage lines of shipment.
CRUD class for batch number management within shipment.
Class to manage generation of HTML components Only common components must be here.
Class with static methods for building HTML components related to products Only components common to ...
Class to manage products or services.
Class to manage projects.
Class to manage proposals.
Class to manage third parties objects (customers, suppliers, prospects...)
Class to manage Dolibarr users.
dol_stringtotime($string, $gm=1)
Convert a string date into a GM Timestamps date Warning: YYYY-MM-DDTHH:MM:SS+02:00 (RFC3339) is not s...
Definition date.lib.php:409
dol_banner_tab($object, $paramid, $morehtml='', $shownav=1, $fieldid='rowid', $fieldref='ref', $morehtmlref='', $moreparam='', $nodbprefix=0, $morehtmlleft='', $morehtmlstatus='', $onlybanner=0, $morehtmlright='')
Show tab footer of a card.
dol_mktime($hour, $minute, $second, $month, $day, $year, $gm='auto', $check=1)
Return a timestamp date built from detailed informations (by default a local PHP server timestamp) Re...
dol_get_fiche_head($links=array(), $active='', $title='', $notab=0, $picto='', $pictoisfullpath=0, $morehtmlright='', $morecss='', $limittoshow=0, $moretabssuffix='', $dragdropfile=0)
Show tabs of a record.
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
dol_print_error($db='', $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs='', $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
dol_now($mode='auto')
Return date for now.
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2)
Show picto whatever it's its name (generic function)
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='', $noduplicate=0)
Set event messages in dol_events session object.
img_edit($titlealt='default', $float=0, $other='')
Show logo editer/modifier fiche.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
publicphonebutton2 phonegreen basiclayout basiclayout TotalHT VATCode TotalVAT TotalLT1 TotalLT2 TotalTTC TotalHT clearboth nowraponall right right takeposterminal SELECT e rowid
Definition invoice.php:1632
ui dialog ui datepicker calendar ui widget content ui state ui datepicker calendar ui widget header ui state ui datepicker calendar ui button
0 = Do not include form tag and submit button -1 = Do not include form tag but include submit button
$conf db name
Only used if Module[ID]Name translation string is not found.
Definition repair.php:123
restrictedArea(User $user, $features, $object=0, $tableandshare='', $feature2='', $dbt_keyfield='fk_soc', $dbt_select='rowid', $isdraft=0, $mode=0)
Check permissions of a user to show a page and an object.
accessforbidden($message='', $printheader=1, $printfooter=1, $showonlymessage=0, $params=null)
Show a message to say access is forbidden and stop program.
shipping_prepare_head($object)
Prepare array with list of tabs.