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