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