dolibarr 19.0.3
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/reception.lib.php';
43require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
44
45// Load translation files required by the page
46$langs->loadLangs(array("bills", "orders", "sendings", "companies", "deliveries", "products", "stocks", "receptions"));
47
48if (isModEnabled('productbatch')) {
49 $langs->load('productbatch');
50}
51
52 // Security check
53$id = GETPOST("id", 'int');
54$ref = GETPOST('ref');
55$lineid = GETPOST('lineid', 'int');
56$action = GETPOST('action', 'aZ09');
57$fk_default_warehouse = GETPOST('fk_default_warehouse', 'int');
58$cancel = GETPOST('cancel', 'alpha');
59$confirm = GETPOST('confirm', 'alpha');
60
61$error = 0;
62$errors = array();
63
64if ($user->socid) {
65 $socid = $user->socid;
66}
67
68$hookmanager->initHooks(array('ordersupplierdispatch'));
69
70// Recuperation de l'id de projet
71$projectid = 0;
72if (GETPOSTISSET("projectid")) {
73 $projectid = GETPOST("projectid", 'int');
74}
75
76$object = new Reception($db);
77
78if ($id > 0 || !empty($ref)) {
79 $result = $object->fetch($id, $ref);
80 if ($result < 0) {
81 setEventMessages($object->error, $object->errors, 'errors');
82 }
83 $result = $object->fetch_thirdparty();
84 if ($result < 0) {
85 setEventMessages($object->error, $object->errors, 'errors');
86 }
87 if (!empty($object->origin)) {
88 $origin = $object->origin;
89
90 $object->fetch_origin();
91 $typeobject = $object->origin;
92 }
93 if ($origin == 'order_supplier' && $object->$typeobject->id && (isModEnabled("fournisseur") && !getDolGlobalString('MAIN_USE_NEW_SUPPLIERMOD') || isModEnabled("supplier_order"))) {
94 $origin_id = $object->$typeobject->id;
95 $objectsrc = new CommandeFournisseur($db);
96 $objectsrc->fetch($object->$typeobject->id);
97 }
98}
99
100if (empty($conf->reception->enabled)) {
101 $permissiontoreceive = $user->rights->fournisseur->commande->receptionner;
102 $permissiontocontrol = ((!getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && !empty($user->rights->fournisseur->commande->receptionner)) || (getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && !empty($user->rights->fournisseur->commande_advance->check)));
103} else {
104 $permissiontoreceive = $user->rights->reception->creer;
105 $permissiontocontrol = ((!getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && !empty($user->rights->reception->creer)) || (getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && !empty($user->rights->reception->reception_advance->validate)));
106}
107
108// $id is id of a reception
109$result = restrictedArea($user, 'reception', $object->id);
110
111if (!isModEnabled('stock')) {
112 accessforbidden('Module stock disabled');
113}
114
115$usercancreate = $user->hasRight('reception', 'creer');
116$permissiontoadd = $usercancreate; // Used by the include of actions_addupdatedelete.inc.php
117
118
119/*
120 * Actions
121 */
122
123$parameters = array();
124$reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
125if ($reshook < 0) {
126 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
127}
128
129// Update a dispatched line
130if ($action == 'updatelines' && $permissiontoreceive) {
131 $db->begin();
132 $error = 0;
133
134 $supplierorderdispatch = new CommandeFournisseurDispatch($db);
135 $pos = 0;
136
137 foreach ($_POST as $key => $value) {
138 // without batch module enabled
139 $reg = array();
140 if (preg_match('/^product_.*([0-9]+)_([0-9]+)$/i', $key, $reg)) {
141 $pos++;
142 if (preg_match('/^product_([0-9]+)_([0-9]+)$/i', $key, $reg)) {
143 $modebatch = "barcode";
144 } elseif (preg_match('/^product_batch_([0-9]+)_([0-9]+)$/i', $key, $reg)) { // With batchmode enabled
145 $modebatch = "batch";
146 }
147
148 $numline = $pos;
149 if ($modebatch == "barcode") {
150 $prod = "product_".$reg[1].'_'.$reg[2];
151 } else {
152 $prod = 'product_batch_'.$reg[1].'_'.$reg[2];
153 }
154 $qty = "qty_".$reg[1].'_'.$reg[2];
155 $ent = "entrepot_".$reg[1].'_'.$reg[2];
156 $pu = "pu_".$reg[1].'_'.$reg[2]; // This is unit price including discount
157 $fk_commandefourndet = "fk_commandefourndet_".$reg[1].'_'.$reg[2];
158 $idline = GETPOST("idline_".$reg[1].'_'.$reg[2]);
159 $lot = '';
160 $dDLUO = '';
161 $dDLC = '';
162 if ($modebatch == "batch") {
163 $lot = GETPOST('lot_number_'.$reg[1].'_'.$reg[2]);
164 $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'));
165 $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'));
166 }
167
168 if (getDolGlobalString('SUPPLIER_ORDER_CAN_UPDATE_BUYINGPRICE_DURING_RECEIPT')) {
169 if (!isModEnabled("multicurrency") && empty($conf->dynamicprices->enabled)) {
170 $dto = GETPOST("dto_".$reg[1].'_'.$reg[2], 'int');
171 if (!empty($dto)) {
172 $unit_price = price2num(GETPOST("pu_".$reg[1]) * (100 - $dto) / 100, 'MU');
173 }
174 $saveprice = "saveprice_".$reg[1].'_'.$reg[2];
175 }
176 }
177
178 // We ask to move a qty
179 if (($modebatch == "batch" && GETPOST($qty) > 0) || ($modebatch == "barcode" && GETPOST($qty) != 0)) {
180 if (!(GETPOST($ent, 'int') > 0)) {
181 dol_syslog('No dispatch for line '.$key.' as no warehouse was chosen.');
182 $text = $langs->transnoentities('Warehouse').', '.$langs->transnoentities('Line').' '.($numline);
183 setEventMessages($langs->trans('ErrorFieldRequired', $text), null, 'errors');
184 $error++;
185 }
186
187 if (!$error) {
188 if ($idline > 0) {
189 $result = $supplierorderdispatch->fetch($idline);
190 if ($result < 0) {
191 setEventMessages($supplierorderdispatch->error, $supplierorderdispatch->errors, 'errors');
192 $error++;
193 } else {
194 $qtystart = $supplierorderdispatch->qty;
195 $supplierorderdispatch->qty = GETPOST($qty);
196 $supplierorderdispatch->fk_entrepot = GETPOST($ent, 'int');
197 if ($modebatch == "batch") {
198 $supplierorderdispatch->eatby = $dDLUO;
199 $supplierorderdispatch->sellby = $dDLC;
200 }
201
202 $result = $supplierorderdispatch->update($user);
203 if ($result < 0) {
204 setEventMessages($supplierorderdispatch->error, $supplierorderdispatch->errors, 'errors');
205 $error++;
206 }
207
208 // If module stock is enabled and the stock decrease is done on edtion of this page
209 /*
210 if (!$error && GETPOST($ent, 'int') > 0 && isModEnabled('stock') && !empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER)) {
211 $mouv = new MouvementStock($db);
212 $product = GETPOST($prod, 'int');
213 $entrepot = GETPOST($ent, 'int');
214 $qtymouv = GETPOST($qty) - $qtystart;
215 $price = GETPOST($pu);
216 $comment = GETPOST('comment');
217 $inventorycode = dol_print_date(dol_now(), 'dayhourlog');
218 $now = dol_now();
219 $eatby = '';
220 $sellby = '';
221 $batch = '';
222 if ($modebatch == "batch") {
223 $eatby = $dDLUO;
224 $sellby = $dDLC;
225 $batch = $supplierorderdispatch->batch;
226 }
227 if ($product > 0) {
228 // $price should take into account discount (except if option STOCK_EXCLUDE_DISCOUNT_FOR_PMP is on)
229 $mouv->origin = $objectsrc;
230 $mouv->setOrigin($objectsrc->element, $objectsrc->id);
231
232 // Method change if qty < 0
233 if (!empty($conf->global->SUPPLIER_ORDER_ALLOW_NEGATIVE_QTY_FOR_SUPPLIER_ORDER_RETURN) && $qtymouv < 0) {
234 $result = $mouv->livraison($user, $product, $entrepot, $qtymouv*(-1), $price, $comment, $now, $eatby, $sellby, $batch, 0, $inventorycode);
235 } else {
236 $result = $mouv->reception($user, $product, $entrepot, $qtymouv, $price, $comment, $eatby, $sellby, $batch, '', 0, $inventorycode);
237 }
238
239 if ($result < 0) {
240 setEventMessages($mouv->error, $mouv->errors, 'errors');
241 $error++;
242 }
243 }
244 }
245 */
246 }
247 } else {
248 $result = $objectsrc->dispatchProduct($user, GETPOST($prod, 'int'), GETPOST($qty), GETPOST($ent, 'int'), GETPOST($pu), GETPOST('comment'), $dDLUO, $dDLC, $lot, GETPOST($fk_commandefourndet, 'int'), 0, $object->id);
249 if ($result < 0) {
250 setEventMessages($objectsrc->error, $objectsrc->errors, 'errors');
251 $error++;
252 }
253 }
254
255 if (!$error && getDolGlobalString('SUPPLIER_ORDER_CAN_UPDATE_BUYINGPRICE_DURING_RECEIPT')) {
256 if (!isModEnabled("multicurrency") && empty($conf->dynamicprices->enabled)) {
257 $dto = price2num(GETPOST("dto_".$reg[1].'_'.$reg[2], 'int'), '');
258 if (empty($dto)) {
259 $dto = 0;
260 }
261
262 //update supplier price
263 if (GETPOSTISSET($saveprice)) {
264 // TODO Use class
265 $sql = "UPDATE ".MAIN_DB_PREFIX."product_fournisseur_price";
266 $sql .= " SET unitprice='".price2num(GETPOST($pu), 'MU')."'";
267 $sql .= ", price=".price2num(GETPOST($pu), 'MU')."*quantity";
268 $sql .= ", remise_percent = ".((float) $dto);
269 $sql .= " WHERE fk_soc=".((int) $object->socid);
270 $sql .= " AND fk_product=".((int) GETPOST($prod, 'int'));
271
272 $resql = $db->query($sql);
273 }
274 }
275 }
276 }
277 }
278 }
279 }
280 if ($error > 0) {
281 $db->rollback();
282 setEventMessages($error, $errors, 'errors');
283 } else {
284 $db->commit();
285 setEventMessages($langs->trans("ReceptionUpdated"), null);
286
287 header("Location: ".DOL_URL_ROOT.'/reception/dispatch.php?id='.$object->id);
288 exit;
289 }
290}
291
292
293/*
294 * View
295 */
296
297$now = dol_now();
298
299$form = new Form($db);
300$formproduct = new FormProduct($db);
301$warehouse_static = new Entrepot($db);
302$supplierorderdispatch = new CommandeFournisseurDispatch($db);
303
304$title = $object->ref." - ".$langs->trans('ReceptionDistribution');
305$help_url = 'EN:Module_Suppliers_Orders|FR:CommandeFournisseur|ES:Módulo_Pedidos_a_proveedores';
306$morejs = array('/fourn/js/lib_dispatch.js.php');
307
308llxHeader('', $title, $help_url, '', 0, 0, $morejs);
309
310if ($id > 0 || !empty($ref)) {
311 if (!empty($object->origin) && $object->origin_id > 0) {
312 $object->origin = 'CommandeFournisseur';
313 $typeobject = $object->origin;
314 $origin = $object->origin;
315 $origin_id = $object->origin_id;
316 $object->fetch_origin(); // Load property $object->commande, $object->propal, ...
317 }
318 $soc = new Societe($db);
319 $soc->fetch($object->socid);
320
321 $author = new User($db);
322 $author->fetch($object->user_author_id);
323
324 $head = reception_prepare_head($object);
325
326 $title = $langs->trans("SupplierOrder");
327 print dol_get_fiche_head($head, 'dispatch', $langs->trans("Reception"), -1, 'dollyrevert');
328
329
330 $formconfirm = '';
331
332 // Confirmation to delete line
333 if ($action == 'ask_deleteline') {
334 $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id.'&lineid='.$lineid, $langs->trans('DeleteLine'), $langs->trans('ConfirmDeleteLine'), 'confirm_deleteline', '', 0, 1);
335 }
336
337 // Call Hook formConfirm
338 $parameters = array('lineid' => $lineid);
339 // Note that $action and $object may be modified by hook
340 $reshook = $hookmanager->executeHooks('formConfirm', $parameters, $object, $action);
341 if (empty($reshook)) {
342 $formconfirm .= $hookmanager->resPrint;
343 } elseif ($reshook > 0) {
344 $formconfirm = $hookmanager->resPrint;
345 }
346
347 // Print form confirm
348 print $formconfirm;
349
350 // Reception card
351 $linkback = '<a href="'.DOL_URL_ROOT.'/reception/list.php?restore_lastsearch_values=1'.(!empty($socid) ? '&socid='.$socid : '').'">'.$langs->trans("BackToList").'</a>';
352 $morehtmlref = '<div class="refidno">';
353 // Ref customer reception
354
355 $morehtmlref .= $form->editfieldkey("RefSupplier", 'ref_supplier', $object->ref_supplier, $object, $user->hasRight('reception', 'creer'), 'string', '', 0, 1);
356 $morehtmlref .= $form->editfieldval("RefSupplier", 'ref_supplier', $object->ref_supplier, $object, $user->hasRight('reception', 'creer'), 'string', '', null, null, '', 1);
357
358 // Thirdparty
359 $morehtmlref .= '<br>'.$object->thirdparty->getNomUrl(1);
360 // Project
361 if (isModEnabled('project')) {
362 $langs->load("projects");
363 $morehtmlref .= '<br>';
364 if (0) { // Do not change on reception
365 $morehtmlref .= img_picto($langs->trans("Project"), 'project', 'class="pictofixedwidth"');
366 if ($action != 'classify' && $permissiontoadd) {
367 $morehtmlref .= '<a class="editfielda" href="'.$_SERVER['PHP_SELF'].'?action=classify&token='.newToken().'&id='.$object->id.'">'.img_edit($langs->transnoentitiesnoconv('SetProject')).'</a> ';
368 }
369 $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'].'?id='.$object->id, (!getDolGlobalString('PROJECT_CAN_ALWAYS_LINK_TO_ALL_SUPPLIERS') ? $object->socid : -1), $object->fk_project, ($action == 'classify' ? 'projectid' : 'none'), 0, 0, 0, 1, '', 'maxwidth300');
370 } else {
371 if (!empty($objectsrc) && !empty($objectsrc->fk_project)) {
372 $proj = new Project($db);
373 $proj->fetch($objectsrc->fk_project);
374 $morehtmlref .= $proj->getNomUrl(1);
375 if ($proj->title) {
376 $morehtmlref .= '<span class="opacitymedium"> - '.dol_escape_htmltag($proj->title).'</span>';
377 }
378 }
379 }
380 }
381 $morehtmlref .= '</div>';
382
383 dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref);
384
385
386 print '<div class="fichecenter">';
387 print '<div class="underbanner clearboth"></div>';
388
389 print '<table class="border tableforfield" width="100%">';
390
391 // Linked documents
392 if ($typeobject == 'commande' && $object->$typeobject->id && isModEnabled('commande')) {
393 print '<tr><td>';
394 print $langs->trans("RefOrder").'</td>';
395 print '<td colspan="3">';
396 print $objectsrc->getNomUrl(1, 'commande');
397 print "</td>\n";
398 print '</tr>';
399 }
400 if ($typeobject == 'propal' && $object->$typeobject->id && isModEnabled("propal")) {
401 print '<tr><td>';
402 print $langs->trans("RefProposal").'</td>';
403 print '<td colspan="3">';
404 print $objectsrc->getNomUrl(1, 'reception');
405 print "</td>\n";
406 print '</tr>';
407 }
408 if ($typeobject == 'CommandeFournisseur' && $object->$typeobject->id && isModEnabled("propal")) {
409 print '<tr><td>';
410 print $langs->trans("SupplierOrder").'</td>';
411 print '<td colspan="3">';
412 print $objectsrc->getNomUrl(1, 'reception');
413 print "</td>\n";
414 print '</tr>';
415 }
416
417 // Date creation
418 print '<tr><td class="titlefield">'.$langs->trans("DateCreation").'</td>';
419 print '<td colspan="3">'.dol_print_date($object->date_creation, "dayhour", "tzuserrel")."</td>\n";
420 print '</tr>';
421
422 // Delivery date planned
423 print '<tr><td height="10">';
424 print '<table class="nobordernopadding" width="100%"><tr><td>';
425 print $langs->trans('DateDeliveryPlanned');
426 print '</td>';
427 print '</tr></table>';
428 print '</td><td colspan="2">';
429 print $object->date_delivery ? dol_print_date($object->date_delivery, 'dayhour') : '&nbsp;';
430 print '</td>';
431 print '</tr>';
432 print '</table>';
433
434 print '<br><br><center>';
435 print '<a href="#" id="resetalltoexpected" class="marginrightonly paddingright marginleftonly paddingleft">'.img_picto("", 'autofill', 'class="pictofixedwidth"').$langs->trans("RestoreWithCurrentQtySaved").'</a></td>';
436 // Link to clear qty
437 print '<a href="#" id="autoreset" class="marginrightonly paddingright marginleftonly paddingleft">'.img_picto("", 'eraser', 'class="pictofixedwidth"').$langs->trans("ClearQtys").'</a></td>';
438 print '<center>';
439
440 print '<br>';
441 $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.
442
443 if ($object->statut == Reception::STATUS_DRAFT || ($object->statut == Reception::STATUS_VALIDATED && !getDolGlobalString('STOCK_CALCULATE_ON_RECEPTION'))) {
444 require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php';
445 $formproduct = new FormProduct($db);
446 $formproduct->loadWarehouses();
447 $entrepot = new Entrepot($db);
448 $listwarehouses = $entrepot->list_array(1);
449
450 print '<form method="post" action="'.$_SERVER["PHP_SELF"].'">';
451
452 print '<input type="hidden" name="token" value="'.newToken().'">';
453 print '<input type="hidden" name="action" value="updatelines">';
454 print '<input type="hidden" name="id" value="'.$object->id.'">';
455
456 print '<div class="div-table-responsive-no-min">';
457 print '<table class="noborder centpercent">';
458
459 // Get list of lines from the original Order into $products_dispatched with qty dispatched for each product id
460 $products_dispatched = array();
461 $sql = "SELECT l.rowid, cfd.fk_product, sum(cfd.qty) as qty";
462 $sql .= " FROM ".MAIN_DB_PREFIX."commande_fournisseur_dispatch as cfd";
463 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."commande_fournisseurdet as l on l.rowid = cfd.fk_commandefourndet";
464 $sql .= " WHERE cfd.fk_reception = ".((int) $object->id);
465 $sql .= " GROUP BY l.rowid, cfd.fk_product";
466
467 $resql = $db->query($sql);
468 if ($resql) {
469 $num = $db->num_rows($resql);
470 $i = 0;
471
472 if ($num) {
473 while ($i < $num) {
474 $objd = $db->fetch_object($resql);
475 $products_dispatched[$objd->rowid] = price2num($objd->qty, 'MS');
476 $i++;
477 }
478 }
479 $db->free($resql);
480 }
481
482
483 //$sql = "SELECT l.rowid, l.fk_product, l.subprice, l.remise_percent, l.ref AS sref, SUM(l.qty) as qty,";
484 $sql = "SELECT l.rowid, l.fk_product, l.subprice, l.remise_percent, l.ref AS sref, l.qty as qty,";
485 $sql .= " p.ref, p.label, p.tobatch, p.fk_default_warehouse";
486 // Enable hooks to alter the SQL query (SELECT)
487 $parameters = array();
488 $reshook = $hookmanager->executeHooks(
489 'printFieldListSelect',
490 $parameters,
491 $object,
492 $action
493 );
494 if ($reshook < 0) {
495 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
496 }
497 $sql .= $hookmanager->resPrint;
498 $sql .= " FROM ".MAIN_DB_PREFIX."commande_fournisseurdet as l";
499 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product as p ON l.fk_product=p.rowid";
500 $sql .= " WHERE l.fk_commande = ".((int) $objectsrc->id);
501 if (!getDolGlobalString('STOCK_SUPPORTS_SERVICES')) {
502 $sql .= " AND l.product_type = 0";
503 }
504 // Enable hooks to alter the SQL query (WHERE)
505 $parameters = array();
506 $reshook = $hookmanager->executeHooks(
507 'printFieldListWhere',
508 $parameters,
509 $object,
510 $action
511 );
512 if ($reshook < 0) {
513 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
514 }
515 $sql .= $hookmanager->resPrint;
516
517 //$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
518 $sql .= " ORDER BY l.rang, p.ref, p.label";
519
520 $resql = $db->query($sql);
521 if ($resql) {
522 $num = $db->num_rows($resql);
523 $i = 0;
524
525 if ($num) {
526 print '<tr class="liste_titre">';
527
528 print '<td>'.$langs->trans("Description").'</td>';
529 if (isModEnabled('productbatch')) {
530 print '<td class="dispatch_batch_number_title">'.$langs->trans("batch_number").'</td>';
531 if (!getDolGlobalString('PRODUCT_DISABLE_SELLBY')) {
532 print '<td class="dispatch_dlc_title">'.$langs->trans("SellByDate").'</td>';
533 }
534 if (!getDolGlobalString('PRODUCT_DISABLE_EATBY')) {
535 print '<td class="dispatch_dluo_title">'.$langs->trans("EatByDate").'</td>';
536 }
537 } else {
538 print '<td></td>';
539 print '<td></td>';
540 print '<td></td>';
541 }
542 print '<td class="right">'.$langs->trans("SupplierRef").'</td>';
543 print '<td class="right">'.$langs->trans("QtyOrdered").'</td>';
544 if ($object->status == Reception::STATUS_DRAFT) {
545 print '<td class="right">'.$langs->trans("QtyToReceive"); // Qty to dispatch (sum for all lines of batch detail if there is)
546 } else {
547 print '<td class="right">'.$langs->trans("QtyDispatchedShort").'</td>';
548 }
549 print '<td class="right">'.$langs->trans("Details");
550 print '<td width="32"></td>';
551
552 if (getDolGlobalString('SUPPLIER_ORDER_CAN_UPDATE_BUYINGPRICE_DURING_RECEIPT')) {
553 if (!isModEnabled("multicurrency") && empty($conf->dynamicprices->enabled)) {
554 print '<td class="right">'.$langs->trans("Price").'</td>';
555 print '<td class="right">'.$langs->trans("ReductionShort").' (%)</td>';
556 print '<td class="right">'.$langs->trans("UpdatePrice").'</td>';
557 }
558 }
559
560 print '<td align="right">'.$langs->trans("Warehouse");
561
562 // Select warehouse to force it everywhere
563 if (count($listwarehouses) > 1) {
564 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);
565 } elseif (count($listwarehouses) == 1) {
566 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);
567 }
568
569 print '</td>';
570
571 // Enable hooks to append additional columns
572 $parameters = array();
573 $reshook = $hookmanager->executeHooks(
574 'printFieldListTitle',
575 $parameters,
576 $object,
577 $action
578 );
579 if ($reshook < 0) {
580 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
581 }
582 print $hookmanager->resPrint;
583
584 print "</tr>\n";
585 }
586
587 $nbfreeproduct = 0; // Nb of lins of free products/services
588 $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)
589 // or nb of line that remain to dispatch if SUPPLIER_ORDER_DISABLE_STOCK_DISPATCH_WHEN_TOTAL_REACHED is on.
590
591 $conf->cache['product'] = array();
592
593 // Loop on each source order line (may be more or less than current number of lines in llx_commande_fournisseurdet)
594 while ($i < $num) {
595 $objp = $db->fetch_object($resql);
596
597 // On n'affiche pas les produits libres
598 if (!$objp->fk_product > 0) {
599 $nbfreeproduct++;
600 } else {
601 $alreadydispatched = isset($products_dispatched[$objp->rowid]) ? $products_dispatched[$objp->rowid] : 0;
602 $remaintodispatch = price2num($objp->qty, 5); // Calculation of dispatched
603 if ($remaintodispatch < 0 && !getDolGlobalString('SUPPLIER_ORDER_ALLOW_NEGATIVE_QTY_FOR_SUPPLIER_ORDER_RETURN')) {
604 $remaintodispatch = 0;
605 }
606
607 if ($remaintodispatch || !getDolGlobalString('SUPPLIER_ORDER_DISABLE_STOCK_DISPATCH_WHEN_TOTAL_REACHED')) {
608 $nbproduct++;
609
610 // To show detail cref and description value, we must make calculation by cref
611 // print ($objp->cref?' ('.$objp->cref.')':'');
612 // if ($objp->description) print '<br>'.nl2br($objp->description);
613 $suffix = '_0_'.$i;
614
615 print "\n";
616 print '<!-- Line to dispatch '.$suffix.' -->'."\n";
617 // hidden fields for js function
618 print '<input id="qty_ordered'.$suffix.'" type="hidden" value="'.$objp->qty.'">';
619 print '<input id="qty_dispatched'.$suffix.'" type="hidden" data-dispatched="'.((float) $alreadydispatched).'" value="'.(float) $alreadydispatched.'">';
620 print '<tr class="oddeven">';
621
622 if (empty($conf->cache['product'][$objp->fk_product])) {
623 $tmpproduct = new Product($db);
624 $tmpproduct->fetch($objp->fk_product);
625 $conf->cache['product'][$objp->fk_product] = $tmpproduct;
626 } else {
627 $tmpproduct = $conf->cache['product'][$objp->fk_product];
628 }
629
630 $linktoprod = $tmpproduct->getNomUrl(1);
631 $linktoprod .= ' - '.$objp->label."\n";
632
633 if (isModEnabled('productbatch')) {
634 if ($objp->tobatch) {
635 // Product
636 print '<td>';
637 print $linktoprod;
638 print "</td>";
639 print '<td class="dispatch_batch_number"></td>';
640 if (!getDolGlobalString('PRODUCT_DISABLE_SELLBY')) {
641 print '<td class="dispatch_dlc"></td>';
642 }
643 if (!getDolGlobalString('PRODUCT_DISABLE_EATBY')) {
644 print '<td class="dispatch_dluo"></td>';
645 }
646 } else {
647 // Product
648 print '<td>';
649 print $linktoprod;
650 print "</td>";
651 print '<td class="dispatch_batch_number">';
652 print '<span class="opacitymedium small">'.$langs->trans("ProductDoesNotUseBatchSerial").'</small>';
653 print '</td>';
654 if (!getDolGlobalString('PRODUCT_DISABLE_SELLBY')) {
655 print '<td class="dispatch_dlc"></td>';
656 }
657 if (!getDolGlobalString('PRODUCT_DISABLE_EATBY')) {
658 print '<td class="dispatch_dluo"></td>';
659 }
660 }
661 } else {
662 print '<td colspan="4">';
663 print $linktoprod;
664 print "</td>";
665 }
666
667 // Define unit price for PMP calculation
668 $up_ht_disc = $objp->subprice;
669 if (!empty($objp->remise_percent) && !getDolGlobalString('STOCK_EXCLUDE_DISCOUNT_FOR_PMP')) {
670 $up_ht_disc = price2num($up_ht_disc * (100 - $objp->remise_percent) / 100, 'MU');
671 }
672
673 // Supplier ref
674 print '<td class="right">'.$objp->sref.'</td>';
675
676 // Qty ordered
677 print '<td class="right">'.$objp->qty.'</td>';
678
679 // Already dispatched
680 print '<td class="right">'.$alreadydispatched.'</td>';
681
682 print '<td class="right">';
683 print '</td>'; // Qty to dispatch
684 print '<td>';
685 print '</td>'; // Dispatch column
686 print '<td></td>'; // Warehouse column
687
688 $sql = "SELECT cfd.rowid, cfd.qty, cfd.fk_entrepot, cfd.batch, cfd.eatby, cfd.sellby, cfd.fk_product";
689 $sql .= " FROM ".MAIN_DB_PREFIX."commande_fournisseur_dispatch as cfd"; // commande_fournisseur_dispatch should be named receptiondet_batch
690 $sql .= " WHERE cfd.fk_reception = ".((int) $object->id);
691 $sql .= " AND cfd.fk_commande = ".((int) $objectsrc->id);
692 $sql .= " AND cfd.fk_commandefourndet = ".(int) $objp->rowid;
693
694 //print $sql;
695 $resultsql = $db->query($sql);
696 $j = 0;
697 if ($resultsql) {
698 $numd = $db->num_rows($resultsql);
699
700 while ($j < $numd) {
701 $suffix = "_".$j."_".$i;
702 $objd = $db->fetch_object($resultsql);
703
704 if (isModEnabled('productbatch') && (!empty($objd->batch) || (is_null($objd->batch) && $tmpproduct->status_batch > 0))) {
705 $type = 'batch';
706
707 // Enable hooks to append additional columns
708 $parameters = array(
709 // allows hook to distinguish between the rows with information and the rows with dispatch form input
710 'is_information_row' => true,
711 'j' => $j,
712 'suffix' => $suffix,
713 'objd' => $objd,
714 );
715 $reshook = $hookmanager->executeHooks(
716 'printFieldListValue',
717 $parameters,
718 $object,
719 $action
720 );
721 if ($reshook < 0) {
722 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
723 }
724 print $hookmanager->resPrint;
725
726 print '</tr>';
727
728 print '<!-- line for batch '.$numline.' -->';
729 print '<tr class="oddeven autoresettr" name="'.$type.$suffix.'" data-remove="clear">';
730 print '<td>';
731 print '<input id="fk_commandefourndet'.$suffix.'" name="fk_commandefourndet'.$suffix.'" type="hidden" value="'.$objp->rowid.'">';
732 print '<input id="idline'.$suffix.'" name="idline'.$suffix.'" type="hidden" value="'.$objd->rowid.'">';
733 print '<input name="product_batch'.$suffix.'" type="hidden" value="'.$objd->fk_product.'">';
734
735 print '<!-- This is a U.P. (may include discount or not depending on STOCK_EXCLUDE_DISCOUNT_FOR_PMP. will be used for PMP calculation) -->';
736 if (getDolGlobalString('SUPPLIER_ORDER_EDIT_BUYINGPRICE_DURING_RECEIPT')) { // Not tested !
737 print $langs->trans("BuyingPrice").': <input class="maxwidth75" name="pu'.$suffix.'" type="text" value="'.price2num($up_ht_disc, 'MU').'">';
738 } else {
739 print '<input class="maxwidth75" name="pu'.$suffix.'" type="hidden" value="'.price2num($up_ht_disc, 'MU').'">';
740 }
741
742 print '</td>';
743
744 print '<td>';
745 print '<input disabled="" type="text" class="inputlotnumber quatrevingtquinzepercent" id="lot_number'.$suffix.'" name="lot_number'.$suffix.'" value="'.(GETPOSTISSET('lot_number'.$suffix) ? GETPOST('lot_number'.$suffix) : $objd->batch).'">';
746 print '</td>';
747 if (!getDolGlobalString('PRODUCT_DISABLE_SELLBY')) {
748 print '<td class="nowraponall">';
749 $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'));
750 print $form->selectDate($dlcdatesuffix, 'dlc'.$suffix, '', '', 1, '');
751 print '</td>';
752 }
753 if (!getDolGlobalString('PRODUCT_DISABLE_EATBY')) {
754 print '<td class="nowraponall">';
755 $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'));
756 print $form->selectDate($dluodatesuffix, 'dluo'.$suffix, '', '', 1, '');
757 print '</td>';
758 }
759 print '<td colspan="3">&nbsp;</td>'; // Supplier ref + Qty ordered + qty already dispatched
760 } else {
761 $type = 'dispatch';
762 $colspan = 7;
763 $colspan = (getDolGlobalString('PRODUCT_DISABLE_SELLBY')) ? --$colspan : $colspan;
764 $colspan = (getDolGlobalString('PRODUCT_DISABLE_EATBY')) ? --$colspan : $colspan;
765
766 // Enable hooks to append additional columns
767 $parameters = array(
768 // allows hook to distinguish between the rows with information and the rows with dispatch form input
769 'is_information_row' => true,
770 'j' => $j,
771 'suffix' => $suffix,
772 'objd' => $objd,
773 );
774 $reshook = $hookmanager->executeHooks(
775 'printFieldListValue',
776 $parameters,
777 $object,
778 $action
779 );
780 if ($reshook < 0) {
781 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
782 }
783 print $hookmanager->resPrint;
784
785 print '</tr>';
786
787 print '<!-- line no batch '.$numline.' -->';
788 print '<tr class="oddeven autoresettr" name="'.$type.$suffix.'" data-remove="clear">';
789 print '<td colspan="'.$colspan.'">';
790 print '<input id="fk_commandefourndet'.$suffix.'" name="fk_commandefourndet'.$suffix.'" type="hidden" value="'.$objp->rowid.'">';
791 print '<input id="idline'.$suffix.'" name="idline'.$suffix.'" type="hidden" value="'.$objd->rowid.'">';
792 print '<input name="product'.$suffix.'" type="hidden" value="'.$objd->fk_product.'">';
793
794 print '<!-- This is a up (may include discount or not depending on STOCK_EXCLUDE_DISCOUNT_FOR_PMP. will be used for PMP calculation) -->';
795 if (getDolGlobalString('SUPPLIER_ORDER_EDIT_BUYINGPRICE_DURING_RECEIPT')) { // Not tested !
796 print $langs->trans("BuyingPrice").': <input class="maxwidth75" name="pu'.$suffix.'" type="text" value="'.price2num($up_ht_disc, 'MU').'">';
797 } else {
798 print '<input class="maxwidth75" name="pu'.$suffix.'" type="hidden" value="'.price2num($up_ht_disc, 'MU').'">';
799 }
800
801 print '</td>';
802 }
803 // Qty to dispatch
804 print '<td class="right">';
805 print '<a href="#" id="reset'.$suffix.'" class="resetline">'.img_picto($langs->trans("Reset"), 'eraser', 'class="pictofixedwidth opacitymedium"').'</a>';
806 print '<input id="qty'.$suffix.'" onchange="onChangeDispatchLineQty($(this))" name="qty'.$suffix.'" data-type="'.$type.'" data-index="'.$i.'" class="width50 right qtydispatchinput" value="'.(GETPOSTISSET('qty'.$suffix) ? GETPOST('qty'.$suffix, 'int') : $objd->qty).'" data-expected="'.$objd->qty.'">';
807 print '</td>';
808 print '<td>';
809 if (isModEnabled('productbatch') && $objp->tobatch > 0) {
810 $type = 'batch';
811 print img_picto($langs->trans('AddStockLocationLine'), 'split.png', 'class="splitbutton" '.($numd != $j+1 ? 'style="display:none"' : '').' onClick="addDispatchLine('.$i.', \''.$type.'\')"');
812 } else {
813 $type = 'dispatch';
814 print img_picto($langs->trans('AddStockLocationLine'), 'split.png', 'class="splitbutton" '.($numd != $j+1 ? 'style="display:none"' : '').' onClick="addDispatchLine('.$i.', \''.$type.'\')"');
815 }
816
817 print '</td>';
818
819 if (getDolGlobalString('SUPPLIER_ORDER_CAN_UPDATE_BUYINGPRICE_DURING_RECEIPT')) {
820 if (!isModEnabled("multicurrency") && empty($conf->dynamicprices->enabled)) {
821 // Price
822 print '<td class="right">';
823 print '<input id="pu'.$suffix.'" name="pu'.$suffix.'" type="text" size="8" value="'.price((GETPOST('pu'.$suffix) != '' ? price2num(GETPOST('pu'.$suffix)) : $up_ht_disc)).'">';
824 print '</td>';
825
826 // Discount
827 print '<td class="right">';
828 print '<input id="dto'.$suffix.'" name="dto'.$suffix.'" type="text" size="8" value="'.(GETPOST('dto'.$suffix) != '' ? GETPOST('dto'.$suffix) : '').'">';
829 print '</td>';
830
831 // Save price
832 print '<td class="center">';
833 print '<input class="flat checkformerge" type="checkbox" name="saveprice'.$suffix.'" value="'.(GETPOST('saveprice'.$suffix) != '' ? GETPOST('saveprice'.$suffix) : '').'">';
834 print '</td>';
835 }
836 }
837
838 // Warehouse
839 print '<td class="right">';
840 if (count($listwarehouses) > 1) {
841 print $formproduct->selectWarehouses(GETPOST("entrepot".$suffix) ? GETPOST("entrepot".$suffix) : $objd->fk_entrepot, "entrepot".$suffix, '', 1, 0, $objp->fk_product, '', 1, 0, null, 'csswarehouse'.$suffix);
842 } elseif (count($listwarehouses) == 1) {
843 print $formproduct->selectWarehouses(GETPOST("entrepot".$suffix) ? GETPOST("entrepot".$suffix) : $objd->fk_entrepot, "entrepot".$suffix, '', 0, 0, $objp->fk_product, '', 1, 0, null, 'csswarehouse'.$suffix);
844 } else {
845 $langs->load("errors");
846 print $langs->trans("ErrorNoWarehouseDefined");
847 }
848 print "</td>\n";
849
850 // Enable hooks to append additional columns
851 $parameters = array(
852 'is_information_row' => false, // this is a dispatch form row
853 'i' => $i,
854 'suffix' => $suffix,
855 'objp' => $objp,
856 );
857 $reshook = $hookmanager->executeHooks(
858 'printFieldListValue',
859 $parameters,
860 $object,
861 $action
862 );
863 if ($reshook < 0) {
864 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
865 }
866 print $hookmanager->resPrint;
867
868 print "</tr>\n";
869 $j++;
870
871 $numline++;
872 }
873 $suffix = "_".$j."_".$i;
874 }
875
876 if ($j == 0) {
877 if (isModEnabled('productbatch') && !empty($objp->tobatch)) {
878 $type = 'batch';
879
880 // Enable hooks to append additional columns
881 $parameters = array(
882 // allows hook to distinguish between the rows with information and the rows with dispatch form input
883 'is_information_row' => true,
884 'j' => $j,
885 'suffix' => $suffix,
886 'objp' => $objp,
887 );
888 $reshook = $hookmanager->executeHooks(
889 'printFieldListValue',
890 $parameters,
891 $object,
892 $action
893 );
894 if ($reshook < 0) {
895 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
896 }
897 print $hookmanager->resPrint;
898
899 print '</tr>';
900
901 print '<!-- line for batch '.$numline.' (not dispatched line yet for this order line) -->';
902 print '<tr class="oddeven autoresettr" name="'.$type.$suffix.'">';
903 print '<td>';
904 print '<input id="fk_commandefourndet'.$suffix.'" name="fk_commandefourndet'.$suffix.'" type="hidden" value="'.$objp->rowid.'">';
905 print '<input id="idline'.$suffix.'" name="idline'.$suffix.'" type="hidden" value="-1">';
906 print '<input name="product_batch'.$suffix.'" type="hidden" value="'.$objp->fk_product.'">';
907
908 print '<!-- This is a up (may include discount or not depending on STOCK_EXCLUDE_DISCOUNT_FOR_PMP. will be used for PMP calculation) -->';
909 if (getDolGlobalString('SUPPLIER_ORDER_EDIT_BUYINGPRICE_DURING_RECEIPT')) { // Not tested !
910 print $langs->trans("BuyingPrice").': <input class="maxwidth75" name="pu'.$suffix.'" type="text" value="'.price2num($up_ht_disc, 'MU').'">';
911 } else {
912 print '<input class="maxwidth75" name="pu'.$suffix.'" type="hidden" value="'.price2num($up_ht_disc, 'MU').'">';
913 }
914
915 print '</td>';
916
917 print '<td>';
918 print '<input type="text" class="inputlotnumber quatrevingtquinzepercent" id="lot_number'.$suffix.'" name="lot_number'.$suffix.'" value="'.GETPOST('lot_number'.$suffix).'">';
919 print '</td>';
920 if (!getDolGlobalString('PRODUCT_DISABLE_SELLBY')) {
921 print '<td class="nowraponall">';
922 $dlcdatesuffix = dol_mktime(0, 0, 0, GETPOST('dlc'.$suffix.'month'), GETPOST('dlc'.$suffix.'day'), GETPOST('dlc'.$suffix.'year'));
923 print $form->selectDate($dlcdatesuffix, 'dlc'.$suffix, '', '', 1, '');
924 print '</td>';
925 }
926 if (!getDolGlobalString('PRODUCT_DISABLE_EATBY')) {
927 print '<td class="nowraponall">';
928 $dluodatesuffix = dol_mktime(0, 0, 0, GETPOST('dluo'.$suffix.'month'), GETPOST('dluo'.$suffix.'day'), GETPOST('dluo'.$suffix.'year'));
929 print $form->selectDate($dluodatesuffix, 'dluo'.$suffix, '', '', 1, '');
930 print '</td>';
931 }
932 print '<td colspan="3">&nbsp;</td>'; // Supplier ref + Qty ordered + qty already dispatched
933 } else {
934 $type = 'dispatch';
935 $colspan = 7;
936 $colspan = (getDolGlobalString('PRODUCT_DISABLE_SELLBY')) ? --$colspan : $colspan;
937 $colspan = (getDolGlobalString('PRODUCT_DISABLE_EATBY')) ? --$colspan : $colspan;
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 no batch '.$numline.' (not dispatched line yet for this order line) -->';
961 print '<tr class="oddeven autoresettr" name="'.$type.$suffix.'" data-remove="clear">';
962 print '<td colspan="'.$colspan.'">';
963 print '<input id="fk_commandefourndet'.$suffix.'" name="fk_commandefourndet'.$suffix.'" type="hidden" value="'.$objp->rowid.'">';
964 print '<input id="idline'.$suffix.'" name="idline'.$suffix.'" type="hidden" value="-1">';
965 print '<input name="product'.$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 if (getDolGlobalString('SUPPLIER_ORDER_EDIT_BUYINGPRICE_DURING_RECEIPT')) { // Not tested !
969 print $langs->trans("BuyingPrice").': <input class="maxwidth75" name="pu'.$suffix.'" data-type="text" value="'.price2num($up_ht_disc, 'MU').'">';
970 } else {
971 print '<input class="maxwidth75" name="pu'.$suffix.'" type="hidden" value="'.price2num($up_ht_disc, 'MU').'">';
972 }
973
974 print '</td>';
975 }
976 // Qty to dispatch
977 print '<td class="right">';
978 print '<a href="#" id="reset'.$suffix.'" class="resetline">'.img_picto($langs->trans("Reset"), 'eraser', 'class="pictofixedwidth opacitymedium"').'</a>';
979 print '<input id="qty'.$suffix.'" onchange="onChangeDispatchLineQty($(this))" name="qty'.$suffix.'" data-index="'.$i.'" data-type="text" class="width50 right qtydispatchinput" value="'.(GETPOSTISSET('qty'.$suffix) ? GETPOST('qty'.$suffix, 'int') : (!getDolGlobalString('SUPPLIER_ORDER_DISPATCH_FORCE_QTY_INPUT_TO_ZERO') ? $remaintodispatch : 0)).'" data-expected="'.$remaintodispatch.'">';
980 print '</td>';
981 print '<td>';
982 if (isModEnabled('productbatch') && $objp->tobatch > 0) {
983 $type = 'batch';
984 print img_picto($langs->trans('AddStockLocationLine'), 'split.png', 'class="splitbutton" onClick="addDispatchLine('.$i.', \''.$type.'\')"');
985 } else {
986 $type = 'dispatch';
987 print img_picto($langs->trans('AddStockLocationLine'), 'split.png', 'class="splitbutton" onClick="addDispatchLine('.$i.', \''.$type.'\')"');
988 }
989
990 print '</td>';
991
992 if (getDolGlobalString('SUPPLIER_ORDER_CAN_UPDATE_BUYINGPRICE_DURING_RECEIPT')) {
993 if (!isModEnabled("multicurrency") && empty($conf->dynamicprices->enabled)) {
994 // Price
995 print '<td class="right">';
996 print '<input id="pu'.$suffix.'" name="pu'.$suffix.'" type="text" size="8" value="'.price((GETPOST('pu'.$suffix) != '' ? price2num(GETPOST('pu'.$suffix)) : $up_ht_disc)).'">';
997 print '</td>';
998
999 // Discount
1000 print '<td class="right">';
1001 print '<input id="dto'.$suffix.'" name="dto'.$suffix.'" type="text" size="8" value="'.(GETPOST('dto'.$suffix) != '' ? GETPOST('dto'.$suffix) : '').'">';
1002 print '</td>';
1003
1004 // Save price
1005 print '<td class="center">';
1006 print '<input class="flat checkformerge" type="checkbox" name="saveprice'.$suffix.'" value="'.(GETPOST('saveprice'.$suffix) != '' ? GETPOST('saveprice'.$suffix) : '').'">';
1007 print '</td>';
1008 }
1009 }
1010
1011 // Warehouse
1012 print '<td class="right">';
1013 if (count($listwarehouses) > 1) {
1014 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);
1015 } elseif (count($listwarehouses) == 1) {
1016 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);
1017 } else {
1018 $langs->load("errors");
1019 print $langs->trans("ErrorNoWarehouseDefined");
1020 }
1021 print "</td>\n";
1022
1023 // Enable hooks to append additional columns
1024 $parameters = array(
1025 'is_information_row' => false, // this is a dispatch form row
1026 'i' => $i,
1027 'suffix' => $suffix,
1028 'objp' => $objp,
1029 );
1030 $reshook = $hookmanager->executeHooks(
1031 'printFieldListValue',
1032 $parameters,
1033 $object,
1034 $action
1035 );
1036 if ($reshook < 0) {
1037 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
1038 }
1039 print $hookmanager->resPrint;
1040 print "</tr>\n";
1041 }
1042 }
1043 }
1044 $i++;
1045 }
1046 $db->free($resql);
1047 } else {
1048 dol_print_error($db);
1049 }
1050
1051 print "</table>\n";
1052 print '</div>';
1053
1054 if ($nbproduct) {
1055 print '<div class="center">';
1056 $parameters = array();
1057 $reshook = $hookmanager->executeHooks('addMoreActionsButtons', $parameters, $object, $action); // Note that $action and $object may have been
1058 // modified by hook
1059 if (empty($reshook)) {
1060 /*$checkboxlabel = $langs->trans("CloseReceivedSupplierOrdersAutomatically", $langs->transnoentitiesnoconv('StatusOrderReceivedAll'));
1061
1062 if (empty($conf->reception->enabled)) {
1063 print $langs->trans("Comment").' : ';
1064 print '<input type="text" class="minwidth400" maxlength="128" name="comment" value="';
1065 print GETPOSTISSET("comment") ? GETPOST("comment") : $langs->trans("DispatchSupplierOrder", $object->ref);
1066 // print ' / '.$object->ref_supplier; // Not yet available
1067 print '" class="flat"><br>';
1068
1069 print '<input type="checkbox" checked="checked" name="closeopenorder"> '.$checkboxlabel;
1070 }
1071
1072 $dispatchBt = empty($conf->reception->enabled) ? $langs->trans("Receive") : $langs->trans("CreateReception");
1073
1074 print '<br>';
1075 */
1076
1077 print '<input type="submit" id="submitform" class="button" name="dispatch" value="'.$langs->trans("Save").'"';
1078 $disabled = 0;
1079 if (!$permissiontoreceive) {
1080 $disabled = 1;
1081 }
1082 if (count($listwarehouses) <= 0) {
1083 $disabled = 1;
1084 }
1085 if ($disabled) {
1086 print ' disabled';
1087 }
1088
1089 print '>';
1090 }
1091 print '</div>';
1092 }
1093
1094 // Message if nothing to dispatch
1095 if (!$nbproduct) {
1096 print "<br>\n";
1097 if (!getDolGlobalString('SUPPLIER_ORDER_DISABLE_STOCK_DISPATCH_WHEN_TOTAL_REACHED')) {
1098 print '<div class="opacitymedium">'.$langs->trans("NoPredefinedProductToDispatch").'</div>'; // No predefined line at all
1099 } else {
1100 print '<div class="opacitymedium">'.$langs->trans("NoMorePredefinedProductToDispatch").'</div>'; // No predefined line that remain to be dispatched.
1101 }
1102 }
1103
1104 print '</form>';
1105 }
1106
1107 print dol_get_fiche_end();
1108
1109 // traitement entrepot par défaut
1110 print '<script type="text/javascript">
1111 $(document).ready(function () {
1112 $("select[name=fk_default_warehouse]").change(function() {
1113 var fk_default_warehouse = $("option:selected", this).val();
1114 $("select[name^=entrepot_]").val(fk_default_warehouse).change();
1115 });
1116
1117 $("#autoreset").click(function() {
1118 $(".autoresettr").each(function(){
1119 id = $(this).attr("name");
1120 idtab = id.split("_");
1121 if ($(this).data("remove") == "clear"){
1122 console.log("We clear the object to expected value")
1123 $("#qty_"+idtab[1]+"_"+idtab[2]).val("");
1124 /*
1125 qtyexpected = $("#qty_"+idtab[1]+"_"+idtab[2]).data("expected")
1126 console.log(qtyexpected);
1127 $("#qty_"+idtab[1]+"_"+idtab[2]).val(qtyexpected);
1128 qtydispatched = $("#qty_dispatched_0_"+idtab[2]).data("dispatched")
1129 $("#qty_dispatched_0_"+idtab[2]).val(qtydispatched);
1130 */
1131 } else {
1132 console.log("We remove the object")
1133 $(this).remove();
1134 $("tr[name^=\'"+idtab[0]+"_\'][name$=\'_"+idtab[2]+"\']:last .splitbutton").show();
1135 }
1136 });
1137 return false;
1138 });
1139
1140 $("#resetalltoexpected").click(function(){
1141 $(".qtydispatchinput").each(function(){
1142 console.log("We reset to expected "+$(this).attr("id")+" qty to dispatch");
1143 $(this).val($(this).data("expected"));
1144 });
1145 return false;
1146 });
1147
1148 $(".resetline").click(function(e){
1149 e.preventDefault();
1150 id = $(this).attr("id");
1151 id = id.split("reset_");
1152 console.log("Reset trigger for id = qty_"+id[1]);
1153 $("#qty_"+id[1]).val("");
1154 return false;
1155 });
1156 });
1157 </script>';
1158}
1159
1160// End of page
1161llxFooter();
1162$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:55
llxFooter()
Empty footer.
Definition wrapper.php:69
Class to manage table commandefournisseurdispatch.
Class to manage predefined suppliers products.
Class to manage comment.
Class to manage warehouses.
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 receptions.
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:426
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 '.
price($amount, $form=0, $outlangs='', $trunc=1, $rounding=-1, $forcerounding=-1, $currency_code='')
Function to format a value into an amount for visual output Function used into PDF and HTML pages.
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.
getDolGlobalString($key, $default='')
Return dolibarr global constant string value.
img_edit($titlealt='default', $float=0, $other='')
Show logo editer/modifier fiche.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
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
reception_prepare_head(Reception $object)
Prepare array with list of tabs.
$conf db name
Only used if Module[ID]Name translation string is not found.
Definition repair.php:124
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.