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 && (int) $supplierorderdispatch->fk_reception !== (int) $object->id) {
204 // The line must be a line of the reception of the page
205 $supplierorderdispatch->error = $langs->trans('ErrorRecordNotFound');
206 $result = -1;
207 }
208 if ($result < 0) {
209 setEventMessages($supplierorderdispatch->error, $supplierorderdispatch->errors, 'errors');
210 $error++;
211 } else {
212 $qtystart = $supplierorderdispatch->qty;
213 $supplierorderdispatch->qty = (float) price2num(GETPOST($qty));
214 $supplierorderdispatch->fk_entrepot = GETPOSTINT($ent);
215 if ($modebatch == "batch") {
216 $supplierorderdispatch->eatby = $dDLUO;
217 $supplierorderdispatch->sellby = $dDLC;
218 }
219
220 $result = $supplierorderdispatch->update($user);
221 if ($result < 0) {
222 setEventMessages($supplierorderdispatch->error, $supplierorderdispatch->errors, 'errors');
223 $error++;
224 }
225
226 // If module stock is enabled and the stock decrease is done on edition of this page
227 /*
228 if (!$error && GETPOST($ent, 'int') > 0 && isModEnabled('stock') && !empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER)) {
229 $mouv = new MouvementStock($db);
230 $product = GETPOST($prod, 'int');
231 $entrepot = GETPOST($ent, 'int');
232 $qtymouv = GETPOST($qty) - $qtystart;
233 $price = GETPOST($pu);
234 $comment = GETPOST('comment');
235 $inventorycode = dol_print_date(dol_now(), 'dayhourlog');
236 $now = dol_now();
237 $eatby = '';
238 $sellby = '';
239 $batch = '';
240 if ($modebatch == "batch") {
241 $eatby = $dDLUO;
242 $sellby = $dDLC;
243 $batch = $supplierorderdispatch->batch;
244 }
245 if ($product > 0) {
246 // $price should take into account discount (except if option STOCK_EXCLUDE_DISCOUNT_FOR_PMP is on)
247 $mouv->origin = $objectsrc;
248 $mouv->setOrigin($objectsrc->element, $objectsrc->id);
249
250 // Method change if qty < 0
251 if (getDolGlobalString('SUPPLIER_ORDER_ALLOW_NEGATIVE_QTY_FOR_SUPPLIER_ORDER_RETURN') && $qtymouv < 0) {
252 $result = $mouv->livraison($user, $product, $entrepot, $qtymouv*(-1), $price, $comment, $now, $eatby, $sellby, $batch, 0, $inventorycode);
253 } else {
254 $result = $mouv->reception($user, $product, $entrepot, $qtymouv, $price, $comment, $eatby, $sellby, $batch, '', 0, $inventorycode);
255 }
256
257 if ($result < 0) {
258 setEventMessages($mouv->error, $mouv->errors, 'errors');
259 $error++;
260 }
261 }
262 }
263 */
264 }
265 } else {
266 $result = $objectsrc->dispatchProduct($user, GETPOSTINT($prod), GETPOSTFLOAT($qty), GETPOSTINT($ent), GETPOSTFLOAT($pu), GETPOST('comment'), $dDLUO, $dDLC, $lot, GETPOSTINT($fk_commandefourndet), 0, $object->id);
267 if ($result < 0) {
268 setEventMessages($objectsrc->error, $objectsrc->errors, 'errors');
269 $error++;
270 }
271 }
272
273 if (!$error && getDolGlobalString('SUPPLIER_ORDER_CAN_UPDATE_BUYINGPRICE_DURING_RECEIPT')) {
274 if (!isModEnabled("multicurrency") && empty($conf->dynamicprices->enabled)) {
275 $dto = price2num(GETPOST("dto_".$reg[1].'_'.$reg[2]), '');
276 if (empty($dto)) {
277 $dto = 0;
278 }
279
280 //update supplier price
281 if (GETPOSTISSET($saveprice)) {
282 // TODO Use class
283 $sql = "UPDATE ".MAIN_DB_PREFIX."product_fournisseur_price";
284 $sql .= " SET unitprice='".price2num(GETPOST($pu), 'MU')."'";
285 $sql .= ", price=".price2num(GETPOST($pu), 'MU')."*quantity";
286 $sql .= ", remise_percent = ".((float) $dto);
287 $sql .= " WHERE fk_soc=".((int) $object->socid);
288 $sql .= " AND fk_product=".(GETPOSTINT($prod));
289
290 $resql = $db->query($sql);
291 }
292 }
293 }
294 }
295 }
296 }
297 }
298 if ($error > 0) {
299 $db->rollback();
300 setEventMessages($langs->trans("Error"), $errors, 'errors');
301 } else {
302 $db->commit();
303 setEventMessages($langs->trans("ReceptionUpdated"), null);
304
305 header("Location: ".DOL_URL_ROOT.'/reception/dispatch.php?id='.$object->id);
306 exit;
307 }
308}
309
310
311/*
312 * View
313 */
314
315$now = dol_now();
316
317$form = new Form($db);
318$formproduct = new FormProduct($db);
319$warehouse_static = new Entrepot($db);
320$supplierorderdispatch = new CommandeFournisseurDispatch($db);
321
322$title = $object->ref." - ".$langs->trans('ReceptionDistribution');
323$help_url = 'EN:Module_Suppliers_Orders|FR:CommandeFournisseur|ES:Módulo_Pedidos_a_proveedores';
324$morejs = array('/fourn/js/lib_dispatch.js.php');
325$numline = 0;
326
327llxHeader('', $title, $help_url, '', 0, 0, $morejs, '', '', 'mod-reception page-card_dispatch');
328
329if ($id > 0 || !empty($ref)) {
330 $typeobject = '';
331 if (!empty($object->origin) && $object->origin_id > 0) {
332 $typeobject = $object->origin;
333 $origin = $object->origin;
334 $origin_id = $object->origin_id;
335 $object->fetch_origin(); // Load property $object->origin_object, $object->commande, $object->propal, ...
336 }
337 $soc = new Societe($db);
338 $soc->fetch($object->socid);
339
340 $author = new User($db);
341 $author->fetch($object->user_author_id);
342
343 $head = reception_prepare_head($object);
344
345 $title = $langs->trans("SupplierOrder");
346 print dol_get_fiche_head($head, 'dispatch', $langs->trans("Reception"), -1, 'dollyrevert');
347
348
349 $formconfirm = '';
350
351 // Confirmation to delete line
352 if ($action == 'ask_deleteline') {
353 $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id.'&lineid='.$lineid, $langs->trans('DeleteLine'), $langs->trans('ConfirmDeleteLine'), 'confirm_deleteline', '', 0, 1);
354 }
355
356 // Call Hook formConfirm
357 $parameters = array('lineid' => $lineid);
358 // Note that $action and $object may be modified by hook
359 $reshook = $hookmanager->executeHooks('formConfirm', $parameters, $object, $action);
360 if (empty($reshook)) {
361 $formconfirm .= $hookmanager->resPrint;
362 } elseif ($reshook > 0) {
363 $formconfirm = $hookmanager->resPrint;
364 }
365
366 // Print form confirm
367 print $formconfirm;
368
369 // Reception card
370 $linkback = '<a href="'.DOL_URL_ROOT.'/reception/list.php?restore_lastsearch_values=1'.(!empty($socid) ? '&socid='.$socid : '').'">'.$langs->trans("BackToList").'</a>';
371 $morehtmlref = '<div class="refidno">';
372 // Ref customer reception
373
374 $morehtmlref .= $form->editfieldkey("RefSupplier", 'ref_supplier', $object->ref_supplier, $object, $user->hasRight('reception', 'creer'), 'string', '', 0, 1);
375 $morehtmlref .= $form->editfieldval("RefSupplier", 'ref_supplier', $object->ref_supplier, $object, $user->hasRight('reception', 'creer'), 'string', '', null, null, '', 1);
376
377 // Thirdparty
378 $morehtmlref .= '<br>'.$object->thirdparty->getNomUrl(1);
379 // Project
380 if (isModEnabled('project')) {
381 $langs->load("projects");
382 $morehtmlref .= '<br>';
383 if (0) { // @phpstan-ignore-line Do not change on reception
384 $morehtmlref .= img_picto($langs->trans("Project"), 'project', 'class="pictofixedwidth"');
385 if ($action != 'classify' && $permissiontoadd) {
386 $morehtmlref .= '<a class="editfielda" href="'.dolBuildUrl($_SERVER['PHP_SELF'], ['action' => 'classify', 'id' => $object->id], true).'">'.img_edit($langs->transnoentitiesnoconv('SetProject')).'</a> ';
387 }
388 $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');
389 } else {
390 if (!empty($objectsrc) && !empty($objectsrc->fk_project)) {
391 $proj = new Project($db);
392 $proj->fetch($objectsrc->fk_project);
393 $morehtmlref .= $proj->getNomUrl(1);
394 if ($proj->title) {
395 $morehtmlref .= '<span class="opacitymedium"> - '.dol_escape_htmltag($proj->title).'</span>';
396 }
397 }
398 }
399 }
400 $morehtmlref .= '</div>';
401
402 dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref);
403
404
405 print '<div class="fichecenter">';
406 print '<div class="underbanner clearboth"></div>';
407
408 print '<table class="border tableforfield" width="100%">';
409
410 // Linked documents
411 if ($typeobject == 'commande' && $object->origin_object->id && isModEnabled('order')) {
412 print '<tr><td>';
413 print $langs->trans("RefOrder").'</td>';
414 print '<td colspan="3">';
415 print $objectsrc->getNomUrl(1, 'commande');
416 print "</td>\n";
417 print '</tr>';
418 }
419 if ($typeobject == 'propal' && $object->origin_object->id && isModEnabled("propal")) {
420 print '<tr><td>';
421 print $langs->trans("RefProposal").'</td>';
422 print '<td colspan="3">';
423 print $objectsrc->getNomUrl(1, 'reception');
424 print "</td>\n";
425 print '</tr>';
426 }
427 if (($typeobject == 'supplier_order' || $typeobject == 'order_supplier') && $object->origin_object->id && isModEnabled("propal")) {
428 print '<tr><td>';
429 print $langs->trans("SupplierOrder").'</td>';
430 print '<td colspan="3">';
431 print $objectsrc->getNomUrl(1, 'reception');
432 print "</td>\n";
433 print '</tr>';
434 }
435
436 // Date creation
437 print '<tr><td class="titlefield">'.$langs->trans("DateCreation").'</td>';
438 print '<td colspan="3">'.dol_print_date($object->date_creation, "dayhour", "tzuserrel")."</td>\n";
439 print '</tr>';
440
441 // Delivery date planned
442 print '<tr><td height="10">';
443 print '<table class="nobordernopadding" width="100%"><tr><td>';
444 print $langs->trans('DateDeliveryPlanned');
445 print '</td>';
446 print '</tr></table>';
447 print '</td><td colspan="2">';
448 print $object->date_delivery ? dol_print_date($object->date_delivery, 'dayhour') : '&nbsp;';
449 print '</td>';
450 print '</tr>';
451 print '</table>';
452
453 print '<br><br><center>';
454 print '<a href="#" id="resetalltoexpected" class="marginrightonly paddingright marginleftonly paddingleft">'.img_picto("", 'autofill', 'class="pictofixedwidth"').$langs->trans("RestoreWithCurrentQtySaved").'</a></td>';
455 // Link to clear qty
456 print '<a href="#" id="autoreset" class="marginrightonly paddingright marginleftonly paddingleft">'.img_picto("", 'eraser', 'class="pictofixedwidth"').$langs->trans("ClearQtys").'</a></td>';
457 print '<center>';
458
459 print '<br>';
460 $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.
461
462 $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)
463
464 if ($object->statut == Reception::STATUS_DRAFT || ($object->statut == Reception::STATUS_VALIDATED && !getDolGlobalString('STOCK_CALCULATE_ON_RECEPTION'))) {
465 require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php';
466 $formproduct = new FormProduct($db);
467 $formproduct->loadWarehouses();
468 $entrepot = new Entrepot($db);
469 $listwarehouses = $entrepot->list_array(1);
470
471 print '<form method="post" action="'.dolBuildUrl($_SERVER["PHP_SELF"]).'">';
472
473 print '<input type="hidden" name="token" value="'.newToken().'">';
474 print '<input type="hidden" name="action" value="updatelines">';
475 print '<input type="hidden" name="id" value="'.$object->id.'">';
476
477 print '<div class="div-table-responsive-no-min">';
478 print '<table class="noborder centpercent">';
479
480 // Get list of lines from the original Order into $products_dispatched with qty dispatched for each product id
481 $products_dispatched = array();
482 $sql = "SELECT l.rowid, cfd.fk_product, sum(cfd.qty) as qty";
483 $sql .= " FROM ".MAIN_DB_PREFIX."receptiondet_batch as cfd";
484 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."receptiondet_batch as l on l.rowid = cfd.fk_elementdet";
485 $sql .= " WHERE cfd.fk_reception = ".((int) $object->id);
486 $sql .= " GROUP BY l.rowid, cfd.fk_product";
487
488 $resql = $db->query($sql);
489 if ($resql) {
490 $num = $db->num_rows($resql);
491 $i = 0;
492
493 if ($num) {
494 while ($i < $num) {
495 $objd = $db->fetch_object($resql);
496 $products_dispatched[$objd->rowid] = price2num($objd->qty, 'MS');
497 $i++;
498 }
499 }
500 $db->free($resql);
501 }
502
503
504 //$sql = "SELECT l.rowid, l.fk_product, l.subprice, l.remise_percent, l.ref AS sref, SUM(l.qty) as qty,";
505 $sql = "SELECT l.rowid, l.fk_product, l.subprice, l.remise_percent, l.ref AS sref, l.qty as qty,";
506 $sql .= " p.ref, p.label, p.tobatch, p.fk_default_warehouse";
507 // Enable hooks to alter the SQL query (SELECT)
508 $parameters = array();
509 $reshook = $hookmanager->executeHooks(
510 'printFieldListSelect',
511 $parameters,
512 $object,
513 $action
514 );
515 if ($reshook < 0) {
516 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
517 }
518 $sql .= $hookmanager->resPrint;
519 $sql .= " FROM ".MAIN_DB_PREFIX."commande_fournisseurdet as l";
520 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product as p ON l.fk_product=p.rowid";
521 $sql .= " WHERE l.fk_commande = ".((int) $objectsrc->id);
522 if (!getDolGlobalString('STOCK_SUPPORTS_SERVICES')) {
523 $sql .= " AND l.product_type = 0";
524 }
525 // Enable hooks to alter the SQL query (WHERE)
526 $parameters = array();
527 $reshook = $hookmanager->executeHooks(
528 'printFieldListWhere',
529 $parameters,
530 $object,
531 $action
532 );
533 if ($reshook < 0) {
534 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
535 }
536 $sql .= $hookmanager->resPrint;
537
538 //$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
539 $sql .= " ORDER BY l.rang, p.ref, p.label";
540
541 $resql = $db->query($sql);
542 if ($resql) {
543 $num = $db->num_rows($resql);
544 $i = 0;
545
546 if ($num) {
547 print '<tr class="liste_titre">';
548
549 print '<td>'.$langs->trans("Description").'</td>';
550 if (isModEnabled('productbatch')) {
551 print '<td class="dispatch_batch_number_title">'.$langs->trans("batch_number").'</td>';
552 if (!getDolGlobalString('PRODUCT_DISABLE_SELLBY')) {
553 print '<td class="dispatch_dlc_title">'.$langs->trans("SellByDate").'</td>';
554 }
555 if (!getDolGlobalString('PRODUCT_DISABLE_EATBY')) {
556 print '<td class="dispatch_dluo_title">'.$langs->trans("EatByDate").'</td>';
557 }
558 } else {
559 print '<td></td>';
560 print '<td></td>';
561 print '<td></td>';
562 }
563 print '<td class="right">'.$langs->trans("SupplierRef").'</td>';
564 print '<td class="right">'.$langs->trans("QtyOrdered").'</td>';
565 if ($object->status == Reception::STATUS_DRAFT) {
566 print '<td class="right">'.$langs->trans("QtyToReceive"); // Qty to dispatch (sum for all lines of batch detail if there is)
567 } else {
568 print '<td class="right">'.$langs->trans("QtyDispatchedShort").'</td>';
569 }
570 print '<td class="right">'.$langs->trans("Details");
571 print '<td width="32"></td>';
572
573 if (getDolGlobalString('SUPPLIER_ORDER_CAN_UPDATE_BUYINGPRICE_DURING_RECEIPT')) {
574 if (!isModEnabled("multicurrency") && empty($conf->dynamicprices->enabled)) {
575 print '<td class="right">'.$langs->trans("Price").'</td>';
576 print '<td class="right">'.$langs->trans("ReductionShort").' (%)</td>';
577 print '<td class="right">'.$langs->trans("UpdatePrice").'</td>';
578 }
579 }
580
581 print '<td align="right">'.$langs->trans("Warehouse");
582
583 // Select warehouse to force it everywhere
584 if (count($listwarehouses) > 1) {
585 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);
586 } elseif (count($listwarehouses) == 1) {
587 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);
588 }
589
590 print '</td>';
591
592 // Enable hooks to append additional columns
593 $parameters = array();
594 $reshook = $hookmanager->executeHooks(
595 'printFieldListTitle',
596 $parameters,
597 $object,
598 $action
599 );
600 if ($reshook < 0) {
601 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
602 }
603 print $hookmanager->resPrint;
604
605 print "</tr>\n";
606 }
607
608 $nbfreeproduct = 0; // Nb of lines of free products/services
609 // or nb of line that remain to dispatch if SUPPLIER_ORDER_DISABLE_STOCK_DISPATCH_WHEN_TOTAL_REACHED is on.
610
611 $conf->cache['product'] = array();
612
613 // Loop on each source order line (may be more or less than current number of lines in llx_commande_fournisseurdet)
614 while ($i < $num) {
615 $objp = $db->fetch_object($resql);
616
617 // Hide the free products
618 if (!$objp->fk_product > 0) {
619 $nbfreeproduct++;
620 } else {
621 $alreadydispatched = isset($products_dispatched[$objp->rowid]) ? $products_dispatched[$objp->rowid] : 0;
622 $remaintodispatch = price2num($objp->qty, 5); // Calculation of dispatched
623 if ($remaintodispatch < 0 && !getDolGlobalString('SUPPLIER_ORDER_ALLOW_NEGATIVE_QTY_FOR_SUPPLIER_ORDER_RETURN')) {
624 $remaintodispatch = 0;
625 }
626
627 if ($remaintodispatch || !getDolGlobalString('SUPPLIER_ORDER_DISABLE_STOCK_DISPATCH_WHEN_TOTAL_REACHED')) {
628 $nbproduct++;
629
630 // To show detail cref and description value, we must make calculation by cref
631 // print ($objp->cref?' ('.$objp->cref.')':'');
632 // if ($objp->description) print '<br>'.nl2br($objp->description);
633 $suffix = '_0_'.$i;
634
635 print "\n";
636 print '<!-- Line to dispatch '.$suffix.' -->'."\n";
637 // hidden fields for js function
638 print '<input id="qty_ordered'.$suffix.'" type="hidden" value="'.$objp->qty.'">';
639 print '<input id="qty_dispatched'.$suffix.'" type="hidden" data-dispatched="'.((float) $alreadydispatched).'" value="'.(float) $alreadydispatched.'">';
640 print '<tr class="oddeven">';
641
642 if (empty($conf->cache['product'][$objp->fk_product])) {
643 $tmpproduct = new Product($db);
644 $tmpproduct->fetch($objp->fk_product);
645 $conf->cache['product'][$objp->fk_product] = $tmpproduct;
646 } else {
647 $tmpproduct = $conf->cache['product'][$objp->fk_product];
648 }
649
650 $linktoprod = $tmpproduct->getNomUrl(1);
651 $linktoprod .= ' - '.$objp->label."\n";
652
653 if (isModEnabled('productbatch')) {
654 if ($objp->tobatch) {
655 // Product
656 print '<td class="tdoverflowmax200">';
657 print $linktoprod;
658 print "</td>";
659 print '<td class="dispatch_batch_number"></td>';
660 if (!getDolGlobalString('PRODUCT_DISABLE_SELLBY')) {
661 print '<td class="dispatch_dlc"></td>';
662 }
663 if (!getDolGlobalString('PRODUCT_DISABLE_EATBY')) {
664 print '<td class="dispatch_dluo"></td>';
665 }
666 } else {
667 // Product
668 print '<td class="tdoverflowmax200">';
669 print $linktoprod;
670 print "</td>";
671 print '<td class="dispatch_batch_number">';
672 print '<span class="opacitymedium small">'.$form->textwithpicto($langs->transnoentitiesnoconv("NA"), $langs->transnoentitiesnoconv("ProductDoesNotUseBatchSerial")).'</small>';
673 print '</td>';
674 if (!getDolGlobalString('PRODUCT_DISABLE_SELLBY')) {
675 print '<td class="dispatch_dlc"></td>';
676 }
677 if (!getDolGlobalString('PRODUCT_DISABLE_EATBY')) {
678 print '<td class="dispatch_dluo"></td>';
679 }
680 }
681 } else {
682 print '<td colspan="4">';
683 print $linktoprod;
684 print "</td>";
685 }
686
687 // Define unit price for PMP calculation
688 $up_ht_disc = $objp->subprice;
689 if (!empty($objp->remise_percent) && !getDolGlobalString('STOCK_EXCLUDE_DISCOUNT_FOR_PMP')) {
690 $up_ht_disc = price2num($up_ht_disc * (100 - $objp->remise_percent) / 100, 'MU');
691 }
692
693 // Supplier ref
694 print '<td class="right">'.$objp->sref.'</td>';
695
696 // Qty ordered
697 print '<td class="right">'.$objp->qty.'</td>';
698
699 // Already dispatched
700 print '<td class="right">'.$alreadydispatched.'</td>';
701
702 print '<td class="right">';
703 print '</td>'; // Qty to dispatch
704 print '<td>';
705 print '</td>'; // Dispatch column
706 print '<td></td>'; // Warehouse column
707
708 $sql = "SELECT cfd.rowid, cfd.qty, cfd.fk_entrepot, cfd.batch, cfd.eatby, cfd.sellby, cfd.fk_product";
709 $sql .= " FROM ".MAIN_DB_PREFIX."receptiondet_batch as cfd";
710 $sql .= " WHERE cfd.fk_reception = ".((int) $object->id);
711 $sql .= " AND cfd.fk_element = ".((int) $objectsrc->id);
712 $sql .= " AND cfd.fk_elementdet = ".(int) $objp->rowid;
713
714 //print $sql;
715 $resultsql = $db->query($sql);
716 $j = 0;
717 if ($resultsql) {
718 $numd = $db->num_rows($resultsql);
719
720 while ($j < $numd) {
721 $suffix = "_".$j."_".$i;
722 $objd = $db->fetch_object($resultsql);
723
724 if (isModEnabled('productbatch') && (!empty($objd->batch) || (is_null($objd->batch) && $tmpproduct->status_batch > 0))) {
725 $type = 'batch';
726
727 // Enable hooks to append additional columns
728 $parameters = array(
729 // allows hook to distinguish between the rows with information and the rows with dispatch form input
730 'is_information_row' => true,
731 'j' => $j,
732 'suffix' => $suffix,
733 'objd' => $objd,
734 );
735 $reshook = $hookmanager->executeHooks(
736 'printFieldListValue',
737 $parameters,
738 $object,
739 $action
740 );
741 if ($reshook < 0) {
742 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
743 }
744 print $hookmanager->resPrint;
745
746 print '</tr>';
747
748 print '<!-- line for batch '.$numline.' -->';
749 print '<tr class="oddeven autoresettr" name="'.$type.$suffix.'" data-remove="clear">';
750 print '<td>';
751 print '<input id="fk_commandefourndet'.$suffix.'" name="fk_commandefourndet'.$suffix.'" type="hidden" value="'.$objp->rowid.'">';
752 print '<input id="idline'.$suffix.'" name="idline'.$suffix.'" type="hidden" value="'.$objd->rowid.'">';
753 print '<input name="product_batch'.$suffix.'" type="hidden" value="'.$objd->fk_product.'">';
754
755 print '<!-- This is a U.P. (may include discount or not depending on STOCK_EXCLUDE_DISCOUNT_FOR_PMP. will be used for PMP calculation) -->';
756 if (getDolGlobalString('SUPPLIER_ORDER_EDIT_BUYINGPRICE_DURING_RECEIPT')) { // Not tested !
757 print $langs->trans("BuyingPrice").': <input class="maxwidth75" name="pu'.$suffix.'" type="text" value="'.price2num($up_ht_disc, 'MU').'">';
758 } else {
759 print '<input class="maxwidth75" name="pu'.$suffix.'" type="hidden" value="'.price2num($up_ht_disc, 'MU').'">';
760 }
761
762 print '</td>';
763
764 print '<td>';
765 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).'">';
766 print '</td>';
767 if (!getDolGlobalString('PRODUCT_DISABLE_SELLBY')) {
768 print '<td class="nowraponall">';
769 $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'));
770 print $form->selectDate($dlcdatesuffix, 'dlc'.$suffix, 0, 0, 1, '');
771 print '</td>';
772 }
773 if (!getDolGlobalString('PRODUCT_DISABLE_EATBY')) {
774 print '<td class="nowraponall">';
775 $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'));
776 print $form->selectDate($dluodatesuffix, 'dluo'.$suffix, 0, 0, 1, '');
777 print '</td>';
778 }
779 print '<td colspan="3">&nbsp;</td>'; // Supplier ref + Qty ordered + qty already dispatched
780 } else {
781 $type = 'dispatch';
782 $colspan = 7;
783 $colspan = (getDolGlobalString('PRODUCT_DISABLE_SELLBY')) ? --$colspan : $colspan;
784 $colspan = (getDolGlobalString('PRODUCT_DISABLE_EATBY')) ? --$colspan : $colspan;
785
786 // Enable hooks to append additional columns
787 $parameters = array(
788 // allows hook to distinguish between the rows with information and the rows with dispatch form input
789 'is_information_row' => true,
790 'j' => $j,
791 'suffix' => $suffix,
792 'objd' => $objd,
793 );
794 $reshook = $hookmanager->executeHooks(
795 'printFieldListValue',
796 $parameters,
797 $object,
798 $action
799 );
800 if ($reshook < 0) {
801 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
802 }
803 print $hookmanager->resPrint;
804
805 print '</tr>';
806
807 print '<!-- line no batch '.$numline.' -->';
808 print '<tr class="oddeven autoresettr" name="'.$type.$suffix.'" data-remove="clear">';
809 print '<td colspan="'.$colspan.'">';
810 print '<input id="fk_commandefourndet'.$suffix.'" name="fk_commandefourndet'.$suffix.'" type="hidden" value="'.$objp->rowid.'">';
811 print '<input id="idline'.$suffix.'" name="idline'.$suffix.'" type="hidden" value="'.$objd->rowid.'">';
812 print '<input name="product'.$suffix.'" type="hidden" value="'.$objd->fk_product.'">';
813
814 print '<!-- This is a up (may include discount or not depending on STOCK_EXCLUDE_DISCOUNT_FOR_PMP. will be used for PMP calculation) -->';
815 if (getDolGlobalString('SUPPLIER_ORDER_EDIT_BUYINGPRICE_DURING_RECEIPT')) { // Not tested !
816 print $langs->trans("BuyingPrice").': <input class="maxwidth75" name="pu'.$suffix.'" type="text" value="'.price2num($up_ht_disc, 'MU').'">';
817 } else {
818 print '<input class="maxwidth75" name="pu'.$suffix.'" type="hidden" value="'.price2num($up_ht_disc, 'MU').'">';
819 }
820
821 print '</td>';
822 }
823 // Qty to dispatch
824 print '<td class="right nowraponall">';
825 print '<a href="#" id="reset'.$suffix.'" class="resetline">'.img_picto($langs->trans("Reset"), 'eraser', 'class="pictofixedwidth opacitymedium"').'</a>';
826 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.'">';
827 print '</td>';
828 print '<td>';
829 if (isModEnabled('productbatch') && $objp->tobatch > 0) {
830 $type = 'batch';
831 print img_picto($langs->trans('AddStockLocationLine'), 'split', 'class="splitbutton" '.($numd != $j + 1 ? 'style="display:none"' : '').' onClick="addDispatchLine('.$i.', \''.$type.'\')"');
832 if ($objp->tobatch == 2) {
833 // Product managed with unique serial numbers: allow to enter several serial numbers at once (one line per serial)
834 print img_picto($langs->trans('EnterMultipleSerialNumbers'), 'barcode', 'class="splitbutton marginleftonly" '.($numd != $j + 1 ? 'style="display:none"' : '').' onClick="addDispatchLinesFromSerialList('.$i.', \''.$type.'\')"');
835 }
836 } else {
837 $type = 'dispatch';
838 print img_picto($langs->trans('AddStockLocationLine'), 'split', 'class="splitbutton" '.($numd != $j + 1 ? 'style="display:none"' : '').' onClick="addDispatchLine('.$i.', \''.$type.'\')"');
839 }
840
841 print '</td>';
842
843 if (getDolGlobalString('SUPPLIER_ORDER_CAN_UPDATE_BUYINGPRICE_DURING_RECEIPT')) {
844 if (!isModEnabled("multicurrency") && empty($conf->dynamicprices->enabled)) {
845 // Price
846 print '<td class="right">';
847 print '<input id="pu'.$suffix.'" name="pu'.$suffix.'" type="text" size="8" value="'.price((GETPOST('pu'.$suffix) != '' ? price2num(GETPOST('pu'.$suffix)) : $up_ht_disc)).'">';
848 print '</td>';
849
850 // Discount
851 print '<td class="right">';
852 print '<input id="dto'.$suffix.'" name="dto'.$suffix.'" type="text" size="8" value="'.(GETPOST('dto'.$suffix) != '' ? GETPOST('dto'.$suffix) : '').'">';
853 print '</td>';
854
855 // Save price
856 print '<td class="center">';
857 print '<input class="flat checkformerge" type="checkbox" name="saveprice'.$suffix.'" value="'.(GETPOST('saveprice'.$suffix) != '' ? GETPOST('saveprice'.$suffix) : '').'">';
858 print '</td>';
859 }
860 }
861
862 // Warehouse
863 print '<td class="right">';
864 if (count($listwarehouses) > 1) {
865 print $formproduct->selectWarehouses(GETPOST("entrepot".$suffix) ? GETPOST("entrepot".$suffix) : $objd->fk_entrepot, "entrepot".$suffix, '', 1, 0, $objp->fk_product, '', 1, 0, array(), 'csswarehouse'.$suffix);
866 } elseif (count($listwarehouses) == 1) {
867 print $formproduct->selectWarehouses(GETPOST("entrepot".$suffix) ? GETPOST("entrepot".$suffix) : $objd->fk_entrepot, "entrepot".$suffix, '', 0, 0, $objp->fk_product, '', 1, 0, array(), 'csswarehouse'.$suffix);
868 } else {
869 $langs->load("errors");
870 print $langs->trans("ErrorNoWarehouseDefined");
871 }
872 print "</td>\n";
873
874 // Enable hooks to append additional columns
875 $parameters = array(
876 'is_information_row' => false, // this is a dispatch form row
877 'i' => $i,
878 'suffix' => $suffix,
879 'objp' => $objp,
880 );
881 $reshook = $hookmanager->executeHooks(
882 'printFieldListValue',
883 $parameters,
884 $object,
885 $action
886 );
887 if ($reshook < 0) {
888 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
889 }
890 print $hookmanager->resPrint;
891
892 print "</tr>\n";
893 $j++;
894
895 $numline++;
896 }
897 $suffix = "_".$j."_".$i;
898 }
899
900 if ($j == 0) {
901 if (isModEnabled('productbatch') && !empty($objp->tobatch)) {
902 $type = 'batch';
903
904 // Enable hooks to append additional columns
905 $parameters = array(
906 // allows hook to distinguish between the rows with information and the rows with dispatch form input
907 'is_information_row' => true,
908 'j' => $j,
909 'suffix' => $suffix,
910 'objp' => $objp,
911 );
912 $reshook = $hookmanager->executeHooks(
913 'printFieldListValue',
914 $parameters,
915 $object,
916 $action
917 );
918 if ($reshook < 0) {
919 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
920 }
921 print $hookmanager->resPrint;
922
923 print '</tr>';
924
925 print '<!-- line for batch '.$numline.' (not dispatched line yet for this order line) -->';
926 print '<tr class="oddeven autoresettr" name="'.$type.$suffix.'">';
927 print '<td>';
928 print '<input id="fk_commandefourndet'.$suffix.'" name="fk_commandefourndet'.$suffix.'" type="hidden" value="'.$objp->rowid.'">';
929 print '<input id="idline'.$suffix.'" name="idline'.$suffix.'" type="hidden" value="-1">';
930 print '<input name="product_batch'.$suffix.'" type="hidden" value="'.$objp->fk_product.'">';
931
932 print '<!-- This is a up (may include discount or not depending on STOCK_EXCLUDE_DISCOUNT_FOR_PMP. will be used for PMP calculation) -->';
933 if (getDolGlobalString('SUPPLIER_ORDER_EDIT_BUYINGPRICE_DURING_RECEIPT')) { // Not tested !
934 print $langs->trans("BuyingPrice").': <input class="maxwidth75" name="pu'.$suffix.'" type="text" value="'.price2num($up_ht_disc, 'MU').'">';
935 } else {
936 print '<input class="maxwidth75" name="pu'.$suffix.'" type="hidden" value="'.price2num($up_ht_disc, 'MU').'">';
937 }
938
939 print '</td>';
940
941 print '<td>';
942 print '<input type="text" class="inputlotnumber quatrevingtquinzepercent" id="lot_number'.$suffix.'" name="lot_number'.$suffix.'" value="'.GETPOST('lot_number'.$suffix).'">';
943 print '</td>';
944 if (!getDolGlobalString('PRODUCT_DISABLE_SELLBY')) {
945 print '<td class="nowraponall">';
946 $dlcdatesuffix = dol_mktime(0, 0, 0, GETPOSTINT('dlc'.$suffix.'month'), GETPOSTINT('dlc'.$suffix.'day'), GETPOSTINT('dlc'.$suffix.'year'));
947 print $form->selectDate($dlcdatesuffix, 'dlc'.$suffix, 0, 0, 1, '');
948 print '</td>';
949 }
950 if (!getDolGlobalString('PRODUCT_DISABLE_EATBY')) {
951 print '<td class="nowraponall">';
952 $dluodatesuffix = dol_mktime(0, 0, 0, GETPOSTINT('dluo'.$suffix.'month'), GETPOSTINT('dluo'.$suffix.'day'), GETPOSTINT('dluo'.$suffix.'year'));
953 print $form->selectDate($dluodatesuffix, 'dluo'.$suffix, 0, 0, 1, '');
954 print '</td>';
955 }
956 print '<td colspan="3">&nbsp;</td>'; // Supplier ref + Qty ordered + qty already dispatched
957 } else {
958 $type = 'dispatch';
959 $colspan = 7;
960 $colspan = (getDolGlobalString('PRODUCT_DISABLE_SELLBY')) ? --$colspan : $colspan;
961 $colspan = (getDolGlobalString('PRODUCT_DISABLE_EATBY')) ? --$colspan : $colspan;
962
963 // Enable hooks to append additional columns
964 $parameters = array(
965 // allows hook to distinguish between the rows with information and the rows with dispatch form input
966 'is_information_row' => true,
967 'j' => $j,
968 'suffix' => $suffix,
969 'objp' => $objp,
970 );
971 $reshook = $hookmanager->executeHooks(
972 'printFieldListValue',
973 $parameters,
974 $object,
975 $action
976 );
977 if ($reshook < 0) {
978 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
979 }
980 print $hookmanager->resPrint;
981
982 print '</tr>';
983
984 print '<!-- line no batch '.$numline.' (not dispatched line yet for this order line) -->';
985 print '<tr class="oddeven autoresettr" name="'.$type.$suffix.'" data-remove="clear">';
986 print '<td colspan="'.$colspan.'">';
987 print '<input id="fk_commandefourndet'.$suffix.'" name="fk_commandefourndet'.$suffix.'" type="hidden" value="'.$objp->rowid.'">';
988 print '<input id="idline'.$suffix.'" name="idline'.$suffix.'" type="hidden" value="-1">';
989 print '<input name="product'.$suffix.'" type="hidden" value="'.$objp->fk_product.'">';
990
991 print '<!-- This is a up (may include discount or not depending on STOCK_EXCLUDE_DISCOUNT_FOR_PMP. will be used for PMP calculation) -->';
992 if (getDolGlobalString('SUPPLIER_ORDER_EDIT_BUYINGPRICE_DURING_RECEIPT')) { // Not tested !
993 print $langs->trans("BuyingPrice").': <input class="maxwidth75" name="pu'.$suffix.'" data-type="text" value="'.price2num($up_ht_disc, 'MU').'">';
994 } else {
995 print '<input class="maxwidth75" name="pu'.$suffix.'" type="hidden" value="'.price2num($up_ht_disc, 'MU').'">';
996 }
997
998 print '</td>';
999 }
1000 // Qty to dispatch
1001 print '<td class="right">';
1002 print '<a href="#" id="reset'.$suffix.'" class="resetline">'.img_picto($langs->trans("Reset"), 'eraser', 'class="pictofixedwidth opacitymedium"').'</a>';
1003 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.'">';
1004 print '</td>';
1005 print '<td>';
1006 if (isModEnabled('productbatch') && $objp->tobatch > 0) {
1007 $type = 'batch';
1008 print img_picto($langs->trans('AddStockLocationLine'), 'split', 'class="splitbutton" onClick="addDispatchLine('.$i.', \''.$type.'\')"');
1009 if ($objp->tobatch == 2) {
1010 // Product managed with unique serial numbers: allow to enter several serial numbers at once (one line per serial)
1011 print img_picto($langs->trans('EnterMultipleSerialNumbers'), 'barcode', 'class="splitbutton marginleftonly" onClick="addDispatchLinesFromSerialList('.$i.', \''.$type.'\')"');
1012 }
1013 } else {
1014 $type = 'dispatch';
1015 print img_picto($langs->trans('AddStockLocationLine'), 'split', 'class="splitbutton" onClick="addDispatchLine('.$i.', \''.$type.'\')"');
1016 }
1017
1018 print '</td>';
1019
1020 if (getDolGlobalString('SUPPLIER_ORDER_CAN_UPDATE_BUYINGPRICE_DURING_RECEIPT')) {
1021 if (!isModEnabled("multicurrency") && empty($conf->dynamicprices->enabled)) {
1022 // Price
1023 print '<td class="right">';
1024 print '<input id="pu'.$suffix.'" name="pu'.$suffix.'" type="text" size="8" value="'.price((GETPOST('pu'.$suffix) != '' ? price2num(GETPOST('pu'.$suffix)) : $up_ht_disc)).'">';
1025 print '</td>';
1026
1027 // Discount
1028 print '<td class="right">';
1029 print '<input id="dto'.$suffix.'" name="dto'.$suffix.'" type="text" size="8" value="'.(GETPOST('dto'.$suffix) != '' ? GETPOST('dto'.$suffix) : '').'">';
1030 print '</td>';
1031
1032 // Save price
1033 print '<td class="center">';
1034 print '<input class="flat checkformerge" type="checkbox" name="saveprice'.$suffix.'" value="'.(GETPOST('saveprice'.$suffix) != '' ? GETPOST('saveprice'.$suffix) : '').'">';
1035 print '</td>';
1036 }
1037 }
1038
1039 // Warehouse
1040 print '<td class="right">';
1041 if (count($listwarehouses) > 1) {
1042 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);
1043 } elseif (count($listwarehouses) == 1) {
1044 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);
1045 } else {
1046 $langs->load("errors");
1047 print $langs->trans("ErrorNoWarehouseDefined");
1048 }
1049 print "</td>\n";
1050
1051 // Enable hooks to append additional columns
1052 $parameters = array(
1053 'is_information_row' => false, // this is a dispatch form row
1054 'i' => $i,
1055 'suffix' => $suffix,
1056 'objp' => $objp,
1057 );
1058 $reshook = $hookmanager->executeHooks(
1059 'printFieldListValue',
1060 $parameters,
1061 $object,
1062 $action
1063 );
1064 if ($reshook < 0) {
1065 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
1066 }
1067 print $hookmanager->resPrint;
1068 print "</tr>\n";
1069 }
1070 }
1071 }
1072 $i++;
1073 }
1074 $db->free($resql);
1075 } else {
1076 dol_print_error($db);
1077 }
1078
1079 print "</table>\n";
1080 print '</div>';
1081
1082 if ($nbproduct) {
1083 print '<div class="center">';
1084 $parameters = array();
1085 $reshook = $hookmanager->executeHooks('addMoreActionsButtons', $parameters, $object, $action); // Note that $action and $object may have been
1086 // modified by hook
1087 if (empty($reshook)) {
1088 /*$checkboxlabel = $langs->trans("CloseReceivedSupplierOrdersAutomatically", $langs->transnoentitiesnoconv('StatusOrderReceivedAll'));
1089
1090 if (empty($conf->reception->enabled)) {
1091 print $langs->trans("Comment").' : ';
1092 print '<input type="text" class="minwidth400" maxlength="128" name="comment" value="';
1093 print GETPOSTISSET("comment") ? GETPOST("comment") : $langs->trans("DispatchSupplierOrder", $object->ref);
1094 // print ' / '.$object->ref_supplier; // Not yet available
1095 print '" class="flat"><br>';
1096
1097 print '<input type="checkbox" checked="checked" name="closeopenorder"> '.$checkboxlabel;
1098 }
1099
1100 $dispatchBt = empty($conf->reception->enabled) ? $langs->trans("Receive") : $langs->trans("CreateReception");
1101
1102 print '<br>';
1103 */
1104
1105 print '<input type="submit" id="submitform" class="button" name="dispatch" value="'.$langs->trans("Save").'"';
1106 $disabled = 0;
1107 if (!$permissiontoreceive) {
1108 $disabled = 1;
1109 }
1110 if (count($listwarehouses) <= 0) {
1111 $disabled = 1;
1112 }
1113 if ($disabled) {
1114 print ' disabled';
1115 }
1116
1117 print '>';
1118 }
1119 print '</div>';
1120 }
1121
1122 // Message if nothing to dispatch
1123 if (!$nbproduct) {
1124 print "<br>\n";
1125 if (!getDolGlobalString('SUPPLIER_ORDER_DISABLE_STOCK_DISPATCH_WHEN_TOTAL_REACHED')) {
1126 print '<div class="opacitymedium">'.$langs->trans("NoPredefinedProductToDispatch").'</div>'; // No predefined line at all
1127 } else {
1128 print '<div class="opacitymedium">'.$langs->trans("NoMorePredefinedProductToDispatch").'</div>'; // No predefined line that remain to be dispatched.
1129 }
1130 }
1131
1132 print '</form>';
1133 }
1134
1135 print dol_get_fiche_end();
1136
1137 // Handling of the default warehouse
1138 print '<script type="text/javascript">
1139 $(document).ready(function () {
1140 $("select[name=fk_default_warehouse]").change(function() {
1141 var fk_default_warehouse = $("option:selected", this).val();
1142 $("select[name^=entrepot_]").val(fk_default_warehouse).change();
1143 });
1144
1145 $("#autoreset").click(function() {
1146 $(".autoresettr").each(function(){
1147 id = $(this).attr("name");
1148 idtab = id.split("_");
1149 if ($(this).data("remove") == "clear"){
1150 console.log("We clear the object to expected value")
1151 $("#qty_"+idtab[1]+"_"+idtab[2]).val("");
1152 /*
1153 qtyexpected = $("#qty_"+idtab[1]+"_"+idtab[2]).data("expected")
1154 console.log(qtyexpected);
1155 $("#qty_"+idtab[1]+"_"+idtab[2]).val(qtyexpected);
1156 qtydispatched = $("#qty_dispatched_0_"+idtab[2]).data("dispatched")
1157 $("#qty_dispatched_0_"+idtab[2]).val(qtydispatched);
1158 */
1159 } else {
1160 console.log("We remove the object")
1161 $(this).remove();
1162 $("tr[name^=\'"+idtab[0]+"_\'][name$=\'_"+idtab[2]+"\']:last .splitbutton").show();
1163 }
1164 });
1165 return false;
1166 });
1167
1168 $("#resetalltoexpected").click(function(){
1169 $(".qtydispatchinput").each(function(){
1170 console.log("We reset to expected "+$(this).attr("id")+" qty to dispatch");
1171 $(this).val($(this).data("expected"));
1172 });
1173 return false;
1174 });
1175
1176 $(".resetline").click(function(e){
1177 e.preventDefault();
1178 id = $(this).attr("id");
1179 id = id.split("reset_");
1180 console.log("Reset trigger for id = qty_"+id[1]);
1181 $("#qty_"+id[1]).val("");
1182 return false;
1183 });
1184 });
1185 </script>';
1186}
1187
1188// End of page
1189llxFooter();
1190$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, $processnotimeasnoon=0)
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:442
if(!isModEnabled('ai')||!getDolGlobalString('AI_ASSISTANT_ENABLED')) global $conf
The main.inc.php has been included so the following variable are now defined:
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).
GETPOSTISSET($paramname)
Return true if we are in a context of submitting the parameter $paramname from a POST of a form.
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.
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:540
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:140
restrictedArea(User $user, $features, $object=0, $tableandshare='', $feature2='', $dbt_keyfield='fk_soc', $dbt_select='rowid', $isdraft=0, $nodie=0, $mode='')
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.