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