dolibarr 24.0.0-beta
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-2023 Laurent Destailleur <eldy@users.sourceforge.net>
4 * Copyright (C) 2005 Eric Seigne <eric.seigne@ryxeo.com>
5 * Copyright (C) 2005-2009 Regis Houssin <regis.houssin@inodbox.com>
6 * Copyright (C) 2010-2021 Juanjo Menent <jmenent@2byte.es>
7 * Copyright (C) 2014 Cedric Gross <c.gross@kreiz-it.fr>
8 * Copyright (C) 2016 Florian Henry <florian.henry@atm-consulting.fr>
9 * Copyright (C) 2017-2022 Ferran Marcet <fmarcet@2byte.es>
10 * Copyright (C) 2018-2026 Frédéric France <frederic.france@free.fr>
11 * Copyright (C) 2019-2020 Christophe Battarel <christophe@altairis.fr>
12 * Copyright (C) 2024-2026 MDW <mdeweerd@users.noreply.github.com>
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 3 of the License, or
17 * (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program. If not, see <https://www.gnu.org/licenses/>.
26 */
27
34// Load Dolibarr environment
35require '../../main.inc.php';
36
45require_once DOL_DOCUMENT_ROOT.'/core/modules/supplier_order/modules_commandefournisseur.php';
46require_once DOL_DOCUMENT_ROOT.'/product/stock/class/entrepot.class.php';
47require_once DOL_DOCUMENT_ROOT.'/core/lib/fourn.lib.php';
48require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.commande.class.php';
49require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.commande.dispatch.class.php';
50require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php';
51require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
52require_once DOL_DOCUMENT_ROOT.'/product/stock/class/productlot.class.php';
53
54if (isModEnabled('project')) {
55 require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
56}
57
58// Load translation files required by the page
59$langs->loadLangs(array("bills", "orders", "sendings", "companies", "products", "stocks", "receptions"));
60
61if (isModEnabled('productbatch')) {
62 $langs->load('productbatch');
63}
64
65// Security check
66$id = GETPOSTINT("id");
67$ref = GETPOST('ref');
68$lineid = GETPOSTINT('lineid');
69$action = GETPOST('action', 'aZ09');
70$fk_default_warehouse = GETPOSTINT('fk_default_warehouse');
71$cancel = GETPOST('cancel', 'alpha');
72$confirm = GETPOST('confirm', 'alpha');
73
74if ($user->isExternalUser()) {
75 $socid = $user->isExternalUser();
76}
77
78$hookmanager->initHooks(array('ordersupplierdispatch'));
79
80// Get id of project
81$projectid = 0;
82if (GETPOSTISSET("projectid")) {
83 $projectid = GETPOSTINT("projectid");
84}
85
87
88if ($id > 0 || !empty($ref)) {
89 $result = $object->fetch($id, $ref);
90 if ($result < 0) {
91 setEventMessages($object->error, $object->errors, 'errors');
92 }
93 $result = $object->fetch_thirdparty();
94 if ($result < 0) {
95 setEventMessages($object->error, $object->errors, 'errors');
96 }
97}
98
99if (empty($conf->reception->enabled)) {
100 $permissiontoreceive = $user->hasRight("fournisseur", "commande", "receptionner");
101 $permissiontocontrol = ((!getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && $user->hasRight("fournisseur", "commande", "receptionner")) || (getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && $user->hasRight("fournisseur", "commande_advance", "check")));
102} else {
103 $permissiontoreceive = $user->hasRight("reception", "creer");
104 $permissiontocontrol = ((!getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && $user->hasRight("reception", "creer")) || (getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && $user->hasRight("reception", "reception_advance", "validate")));
105}
106
107// $id is id of a purchase order.
108$result = restrictedArea($user, 'fournisseur', $object, 'commande_fournisseur', 'commande');
109
110if (!isModEnabled('stock')) {
112}
113
114$usercancreate = ($user->hasRight("fournisseur", "commande", "creer") || $user->hasRight("supplier_order", "creer"));
115$permissiontoadd = $usercancreate; // Used by the include of actions_addupdatedelete.inc.php
116
117
118/*
119 * Actions
120 */
121
122$error = 0;
123$errors = [];
124$parameters = array();
125$reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
126if ($reshook < 0) {
127 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
128}
129
130if ($action == 'checkdispatchline' && $permissiontocontrol) {
131 $supplierorderdispatch = new CommandeFournisseurDispatch($db);
132
133 $db->begin();
134
135 $result = $supplierorderdispatch->fetch($lineid);
136 if (!$result) {
137 $error++;
138 setEventMessages($supplierorderdispatch->error, $supplierorderdispatch->errors, 'errors');
139 $action = '';
140 }
141
142 if (!$error) {
143 $result = $supplierorderdispatch->setStatut(1);
144 if ($result < 0) {
145 setEventMessages($supplierorderdispatch->error, $supplierorderdispatch->errors, 'errors');
146 $error++;
147 $action = '';
148 }
149 }
150
151 if (!$error) {
152 $result = $object->calcAndSetStatusDispatch($user);
153 if ($result < 0) {
154 setEventMessages($object->error, $object->errors, 'errors');
155 $error++;
156 $action = '';
157 }
158 }
159 if (!$error) {
160 $db->commit();
161 } else {
162 $db->rollback();
163 }
164}
165
166if ($action == 'uncheckdispatchline' && $permissiontocontrol) {
167 $supplierorderdispatch = new CommandeFournisseurDispatch($db);
168
169 $db->begin();
170
171 $result = $supplierorderdispatch->fetch($lineid);
172 if (!$result) {
173 $error++;
174 setEventMessages($supplierorderdispatch->error, $supplierorderdispatch->errors, 'errors');
175 $action = '';
176 }
177
178 if (!$error) {
179 $result = $supplierorderdispatch->setStatut(0);
180 if ($result < 0) {
181 setEventMessages($supplierorderdispatch->error, $supplierorderdispatch->errors, 'errors');
182 $error++;
183 $action = '';
184 }
185 }
186 if (!$error) {
187 $result = $object->calcAndSetStatusDispatch($user);
188 if ($result < 0) {
189 setEventMessages($object->error, $object->errors, 'errors');
190 $error++;
191 $action = '';
192 }
193 }
194 if (!$error) {
195 $db->commit();
196 } else {
197 $db->rollback();
198 }
199}
200
201if ($action == 'denydispatchline' && $permissiontocontrol) {
202 $supplierorderdispatch = new CommandeFournisseurDispatch($db);
203
204 $db->begin();
205
206 $result = $supplierorderdispatch->fetch($lineid);
207 if (!$result) {
208 $error++;
209 setEventMessages($supplierorderdispatch->error, $supplierorderdispatch->errors, 'errors');
210 $action = '';
211 }
212
213 if (!$error) {
214 $result = $supplierorderdispatch->setStatut(2);
215 if ($result < 0) {
216 setEventMessages($supplierorderdispatch->error, $supplierorderdispatch->errors, 'errors');
217 $error++;
218 $action = '';
219 }
220 }
221 if (!$error) {
222 $result = $object->calcAndSetStatusDispatch($user);
223 if ($result < 0) {
224 setEventMessages($object->error, $object->errors, 'errors');
225 $error++;
226 $action = '';
227 }
228 }
229 if (!$error) {
230 $db->commit();
231 } else {
232 $db->rollback();
233 }
234}
235
236$saveprice = "savepriceIsNotSet";
237if ($action == 'dispatch' && $permissiontoreceive) {
238 $notrigger = 0;
239
240 $db->begin();
241
242 $pos = 0;
243 $comment = (string) GETPOST('comment', 'alpha');
244
245 foreach ($_POST as $key => $value) {
246 // without batch module enabled
247 $reg = array();
248 if (preg_match('/^product_([0-9]+)_([0-9]+)$/i', $key, $reg)) {
249 $pos++;
250
251 // $numline=$reg[2] + 1; // line of product
252 $numline = $pos;
253 $prod = "product_".$reg[1].'_'.$reg[2];
254 $qty = "qty_".$reg[1].'_'.$reg[2];
255 $ent = "entrepot_".$reg[1].'_'.$reg[2];
256 if (empty(GETPOST($ent))) {
257 $ent = $fk_default_warehouse;
258 }
259 $pu = "pu_".$reg[1].'_'.$reg[2]; // This is unit price including discount
260 $fk_commandefourndet = "fk_commandefourndet_".$reg[1].'_'.$reg[2];
261
262 if (getDolGlobalString('SUPPLIER_ORDER_CAN_UPDATE_BUYINGPRICE_DURING_RECEIPT')) {
263 if (!isModEnabled("multicurrency") && empty($conf->dynamicprices->enabled)) {
264 $dto = GETPOSTINT("dto_".$reg[1].'_'.$reg[2]);
265 if (!empty($dto)) {
266 $unit_price = price2num((float) GETPOST("pu_".$reg[1]) * (100 - $dto) / 100, 'MU');
267 }
268 $saveprice = "saveprice_".$reg[1].'_'.$reg[2];
269 }
270 }
271
272 // We ask to move a qty
273 $qtytomove = GETPOSTFLOAT($qty);
274 $puformove = GETPOSTFLOAT($pu);
275 if ($qtytomove != 0) {
276 if (!(GETPOSTINT($ent) > 0)) {
277 dol_syslog('No dispatch for line '.$key.' as no warehouse was chosen.');
278 $text = $langs->transnoentities('Warehouse').', '.$langs->transnoentities('Line').' '.($numline);
279 setEventMessages($langs->trans('ErrorFieldRequired', $text), null, 'errors');
280 $error++;
281 }
282
283 if (!$error) {
284 $result = $object->dispatchProduct($user, GETPOSTINT($prod), $qtytomove, GETPOSTINT($ent), $puformove, GETPOST('comment'), '', '', '', GETPOSTINT($fk_commandefourndet), $notrigger);
285 if ($result < 0) {
286 setEventMessages($object->error, $object->errors, 'errors');
287 $error++;
288 }
289
290 if (!$error && getDolGlobalString('SUPPLIER_ORDER_CAN_UPDATE_BUYINGPRICE_DURING_RECEIPT')) {
291 if (!isModEnabled("multicurrency") && empty($conf->dynamicprices->enabled)) {
292 $dto = price2num(GETPOST("dto_".$reg[1].'_'.$reg[2]), '');
293 if (empty($dto)) {
294 $dto = 0;
295 }
296
297 //update supplier price
298 if (GETPOSTISSET($saveprice)) {
299 // TODO Use class
300 $sql = "UPDATE ".MAIN_DB_PREFIX."product_fournisseur_price";
301 $sql .= " SET unitprice='".price2num(GETPOST($pu), 'MU')."'";
302 $sql .= ", price=".price2num(GETPOST($pu), 'MU')."*quantity";
303 $sql .= ", remise_percent = ".((float) $dto);
304 $sql .= " WHERE fk_soc=".((int) $object->socid);
305 $sql .= " AND fk_product=".(GETPOSTINT($prod));
306
307 $resql = $db->query($sql);
308 }
309 }
310 }
311 }
312 }
313 }
314 // with batch module enabled
315 if (preg_match('/^product_batch_([0-9]+)_([0-9]+)$/i', $key, $reg)) {
316 $pos++;
317
318 // eat-by date dispatch
319 // $numline=$reg[2] + 1; // line of product
320 $numline = $pos;
321 $prod = 'product_batch_'.$reg[1].'_'.$reg[2];
322 $qty = 'qty_'.$reg[1].'_'.$reg[2];
323 $ent = 'entrepot_'.$reg[1].'_'.$reg[2];
324 $pu = 'pu_'.$reg[1].'_'.$reg[2];
325 $fk_commandefourndet = 'fk_commandefourndet_'.$reg[1].'_'.$reg[2];
326 $lot = 'lot_number_'.$reg[1].'_'.$reg[2];
327 $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'));
328 $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'));
329
330 $fk_commandefourndet = 'fk_commandefourndet_'.$reg[1].'_'.$reg[2];
331
332 if (getDolGlobalString('SUPPLIER_ORDER_CAN_UPDATE_BUYINGPRICE_DURING_RECEIPT')) {
333 if (!isModEnabled("multicurrency") && empty($conf->dynamicprices->enabled)) {
334 $dto = GETPOSTFLOAT("dto_".$reg[1].'_'.$reg[2]);
335 if (!empty($dto)) {
336 $unit_price = price2num((float) GETPOST("pu_".$reg[1]) * (100 - $dto) / 100, 'MU');
337 }
338 $saveprice = "saveprice_".$reg[1].'_'.$reg[2];
339 }
340 }
341
342 // We ask to move a qty
343 $qtytomove = GETPOSTFLOAT($qty);
344 $puformove = GETPOSTFLOAT($pu);
345 if ($qtytomove > 0) {
346 $productId = GETPOSTINT($prod);
347
348 if (!(GETPOSTINT($ent) > 0)) {
349 dol_syslog('No dispatch for line '.$key.' as no warehouse was chosen.');
350 $text = $langs->transnoentities('Warehouse').', '.$langs->transnoentities('Line').' '.($numline).'-'.((int) $reg[1] + 1);
351 setEventMessages($langs->trans('ErrorFieldRequired', $text), null, 'errors');
352 $error++;
353 }
354
355 // check sell-by / eat-by date is mandatory
356 /* Not required. Mandatory is checked when we insert the lot. Once lot has been recorded and is known, user can just enter the lot/serial
357 $errorMsgArr = Productlot::checkSellOrEatByMandatoryFromProductIdAndDates($productId, $dDLC, $dDLUO);
358 if (!(GETPOST($lot, 'alpha')) || !empty($errorMsgArr)) {
359 dol_syslog('No dispatch for line '.$key.' as serial/eat-by/sellby date are not set');
360 $text = $langs->transnoentities('atleast1batchfield').', '.$langs->transnoentities('Line').' '.($numline).'-'.($reg[1] + 1);
361 setEventMessages($langs->trans('ErrorFieldRequired', $text), null, 'errors');
362 $error++;
363 }*/
364 if (!GETPOST($lot, 'alpha') && !$dDLUO && !$dDLC) {
365 dol_syslog('No dispatch for line '.$key.' as serial/eat-by/sellby date are not set');
366 $text = $langs->transnoentities('atleast1batchfield').', '.$langs->transnoentities('Line').' '.($numline).'-'.((int) $reg[1] + 1);
367 setEventMessages($langs->trans('ErrorFieldRequired', $text), null, 'errors');
368 $error++;
369 }
370
371 if (!$error) {
372 $result = $object->dispatchProduct($user, $productId, $qtytomove, GETPOSTINT($ent), $puformove, GETPOST('comment'), $dDLUO, $dDLC, GETPOST($lot, 'alpha'), GETPOSTINT($fk_commandefourndet), $notrigger);
373 if ($result < 0) {
374 setEventMessages($object->error, $object->errors, 'errors');
375 $error++;
376 }
377
378 if (!$error && getDolGlobalString('SUPPLIER_ORDER_CAN_UPDATE_BUYINGPRICE_DURING_RECEIPT')) {
379 if (!isModEnabled("multicurrency") && empty($conf->dynamicprices->enabled)) {
380 $dto = GETPOSTFLOAT("dto_".$reg[1].'_'.$reg[2]);
381 //update supplier price
382 if (GETPOSTISSET($saveprice)) {
383 // TODO Use class
384 $sql = "UPDATE ".MAIN_DB_PREFIX."product_fournisseur_price";
385 $sql .= " SET unitprice = ".price2num(GETPOST($pu), 'MU', 2);
386 $sql .= ", price = ".price2num(GETPOST($pu), 'MU', 2)." * quantity";
387 $sql .= ", remise_percent = ".price2num((empty($dto) ? 0 : $dto), 3, 2);
388 $sql .= " WHERE fk_soc = ".((int) $object->socid);
389 $sql .= " AND fk_product=".((int) $productId);
390
391 $resql = $db->query($sql);
392 }
393 }
394 }
395 }
396 }
397 }
398 }
399
400 if (!$error) {
401 $result = $object->calcAndSetStatusDispatch($user, GETPOST('closeopenorder') ? 1 : 0, GETPOST('comment'));
402 if ($result < 0) {
403 setEventMessages($object->error, $object->errors, 'errors');
404 $error++;
405 }
406 }
407
408 if ($result >= 0 && !$error) {
409 $db->commit();
410
411 setEventMessages($langs->trans("ReceptionsRecorded"), null, 'mesgs');
412
413 header("Location: dispatch.php?id=".$id);
414 exit();
415 } else {
416 $db->rollback();
417 }
418}
419
420$batch = '';
421$eatby = null;
422$sellby = 0;
423$qty = 0;
424$price = '0';
425$entrepot = 0;
426$product = 0;
427
428// Remove a dispatched line
429if ($action == 'confirm_deleteline' && $confirm == 'yes' && $permissiontoreceive) {
430 $db->begin();
431
432 $comment = '';
433
434 $supplierorderdispatch = new CommandeFournisseurDispatch($db);
435 $result = $supplierorderdispatch->fetch($lineid);
436 if ($result > 0) {
437 $qty = $supplierorderdispatch->qty;
438 $entrepot = $supplierorderdispatch->fk_entrepot;
439 $product = $supplierorderdispatch->fk_product;
440 $price = price2num(GETPOST('price', 'alpha'), 'MU');
441 $comment = $supplierorderdispatch->comment;
442 $eatby = $supplierorderdispatch->eatby;
443 $sellby = $supplierorderdispatch->sellby;
444 $batch = $supplierorderdispatch->batch;
445
446 $result = $supplierorderdispatch->delete($user);
447 }
448 if ($result < 0) {
449 $errors = $object->errors;
450 $error++;
451 } else {
452 // If module stock is enabled and the stock increase is done on purchase order dispatching
453 if ($entrepot > 0 && isModEnabled('stock') && getDolGlobalString('STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER') && empty($supplierorderdispatch->fk_reception)) {
454 $mouv = new MouvementStock($db);
455 if ($product > 0) {
456 $mouv->origin = &$object;
457 $mouv->setOrigin($object->element, $object->id);
458 $result = $mouv->livraison($user, $product, $entrepot, $qty, (float) $price, (string) $comment, '', (int) $eatby, (int) $sellby, $batch);
459 if ($result < 0) {
460 $errors = $mouv->errors;
461 $error++;
462 }
463 }
464 }
465 }
466 if ($error > 0) {
467 $db->rollback();
468 setEventMessages(null, $errors, 'errors');
469 } else {
470 $db->commit();
471 }
472}
473
474// Update a dispatched line
475if ($action == 'updateline' && $permissiontoreceive && empty($cancel)) {
476 $db->begin();
477
478 $comment = '';
479
480 $supplierorderdispatch = new CommandeFournisseurDispatch($db);
481 $result = $supplierorderdispatch->fetch($lineid);
482 if ($result > 0) {
483 $qty = $supplierorderdispatch->qty;
484 $entrepot = $supplierorderdispatch->fk_entrepot;
485 $product = $supplierorderdispatch->fk_product;
486 $price = GETPOSTFLOAT('price');
487 $comment = $supplierorderdispatch->comment;
488 $eatby = $supplierorderdispatch->eatby;
489 $sellby = $supplierorderdispatch->sellby;
490 $batch = $supplierorderdispatch->batch;
491
492 $supplierorderdispatch->qty = GETPOSTFLOAT('qty', 'MS');
493 $supplierorderdispatch->fk_entrepot = GETPOSTINT('fk_entrepot');
494 $result = $supplierorderdispatch->update($user);
495 }
496 if ($result < 0) {
497 $error++;
498 $errors = $supplierorderdispatch->errors;
499 } else {
500 // If module stock is enabled and the stock increase is done on purchase order dispatching
501 if ($entrepot > 0 && isModEnabled('stock') && getDolGlobalString('STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER')) {
502 $mouv = new MouvementStock($db);
503 if ($product > 0) {
504 $mouv->origin = &$object;
505 $mouv->setOrigin($object->element, $object->id);
506 $result = $mouv->livraison($user, $product, $entrepot, $qty, $price, (string) $comment, '', (int) $eatby, (int) $sellby, $batch);
507 if ($result < 0) {
508 $errors = $mouv->errors;
509 $error++;
510 } else {
511 $mouv->origin = &$object;
512 $result = $mouv->reception($user, $product, $supplierorderdispatch->fk_entrepot, $supplierorderdispatch->qty, $price, (string) $comment, (int) $eatby, (int) $sellby, $batch);
513 if ($result < 0) {
514 $errors = $mouv->errors;
515 $error++;
516 }
517 }
518 }
519 }
520 }
521 if ($error > 0) {
522 $db->rollback();
523 setEventMessages($langs->trans("Error"), $errors, 'errors');
524 } else {
525 $db->commit();
526 }
527}
528
529
530/*
531 * View
532 */
533
534$now = dol_now();
535
536$form = new Form($db);
537$formproduct = new FormProduct($db);
538$warehouse_static = new Entrepot($db);
539$supplierorderdispatch = new CommandeFournisseurDispatch($db);
540
541$title = $object->ref." - ".$langs->trans('OrderDispatch');
542$help_url = 'EN:Module_Suppliers_Orders|FR:CommandeFournisseur|ES:Módulo_Pedidos_a_proveedores';
543$morejs = array('/fourn/js/lib_dispatch.js.php');
544
545llxHeader('', $title, $help_url, '', 0, 0, $morejs, '', '', 'mod-supplier-order page-card_dispatch');
546
547if ($id > 0 || !empty($ref)) {
548 $soc = new Societe($db);
549 $soc->fetch($object->socid);
550
551 $author = new User($db);
552 $author->fetch($object->user_author_id);
553
554 $head = ordersupplier_prepare_head($object);
555
556 $title = $langs->trans("SupplierOrder");
557 print dol_get_fiche_head($head, 'dispatch', $title, -1, 'order');
558
559 $formconfirm = '';
560
561 // Confirmation to delete line
562 if ($action == 'ask_deleteline') {
563 $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id.'&lineid='.$lineid, $langs->trans('DeleteLine'), $langs->trans('ConfirmDeleteLine'), 'confirm_deleteline', '', 0, 1);
564 }
565
566 // Call Hook formConfirm
567 $parameters = array('lineid' => $lineid);
568 // Note that $action and $object may be modified by hook
569 $reshook = $hookmanager->executeHooks('formConfirm', $parameters, $object, $action);
570 if (empty($reshook)) {
571 $formconfirm .= $hookmanager->resPrint;
572 } elseif ($reshook > 0) {
573 $formconfirm = $hookmanager->resPrint;
574 }
575
576 // Print form confirm
577 print $formconfirm;
578
579 // Supplier order card
580
581 $linkback = '<a href="'.DOL_URL_ROOT.'/fourn/commande/list.php'.(!empty($socid) ? '?socid='.$socid : '').'">'.$langs->trans("BackToList").'</a>';
582
583 $morehtmlref = '<div class="refidno">';
584 // Ref supplier
585 $morehtmlref .= $form->editfieldkey("RefSupplier", 'ref_supplier', $object->ref_supplier, $object, 0, 'string', '', 0, 1);
586 $morehtmlref .= $form->editfieldval("RefSupplier", 'ref_supplier', $object->ref_supplier, $object, 0, 'string', '', null, null, '', 1);
587 // Thirdparty
588 $morehtmlref .= '<br>'.$object->thirdparty->getNomUrl(1);
589 // Project
590 if (isModEnabled('project')) {
591 $langs->load("projects");
592 $morehtmlref .= '<br>';
593 if (0) { // @phpstan-ignore-line
594 $caneditproject = false; // For static analysis
595 $morehtmlref .= img_picto($langs->trans("Project"), 'project', 'class="pictofixedwidth"');
596 if ($action != 'classify' && $caneditproject) {
597 $morehtmlref .= '<a class="editfielda" href="'.dolBuildUrl($_SERVER['PHP_SELF'], ['action' => 'classify', 'id' => $object->id], true).'">'.img_edit($langs->transnoentitiesnoconv('SetProject')).'</a> ';
598 }
599 $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');
600 } else {
601 if (!empty($object->fk_project)) {
602 $proj = new Project($db);
603 $proj->fetch($object->fk_project);
604 $morehtmlref .= $proj->getNomUrl(1);
605 if ($proj->title) {
606 $morehtmlref .= '<span class="opacitymedium"> - '.dol_escape_htmltag($proj->title).'</span>';
607 }
608 }
609 }
610 }
611 $morehtmlref .= '</div>';
612
613
614 dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref);
615
616
617 print '<div class="fichecenter">';
618 print '<div class="underbanner clearboth"></div>';
619
620 print '<table class="border tableforfield" width="100%">';
621
622 // Date
623 if ($object->methode_commande_id > 0) {
624 print '<tr><td class="titlefield">'.$langs->trans("Date").'</td><td>';
625 if ($object->date_commande) {
626 print dol_print_date($object->date_commande, "dayhour")."\n";
627 }
628 print "</td></tr>";
629
630 if ($object->methode_commande) {
631 print '<tr><td>'.$langs->trans("Method").'</td><td>'.$object->getInputMethod().'</td></tr>';
632 }
633 }
634
635 // Author
636 print '<tr><td class="titlefield">'.$langs->trans("AuthorRequest").'</td>';
637 print '<td>'.$author->getNomUrl(-1, '', 0, 0, 0).'</td>';
638 print '</tr>';
639
640 $parameters = array();
641 $reshook = $hookmanager->executeHooks('formObjectOptions', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
642
643 print "</table>";
644
645 print '</div>';
646
647 // if ($mesg) print $mesg;
648 print '<br>';
649
650 $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.
651
652 // Line of orders
654 print '<br><span class="opacitymedium">'.$langs->trans("OrderStatusNotReadyToDispatch").'</span>';
655 }
656
657
658 print '<br>';
659
660 $listwarehouses = array();
661
665 require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php';
666 $formproduct = new FormProduct($db);
667 $formproduct->loadWarehouses();
668 $entrepot = new Entrepot($db);
669 $listwarehouses = $entrepot->list_array(1);
670
671
672 if (empty($conf->reception->enabled)) {
673 print '<form method="POST" action="dispatch.php?id='.$object->id.'">';
674 } else {
675 print '<form method="post" action="'.dol_buildpath('/reception/card.php', 1).'?originid='.$object->id.'&origin=supplierorder">';
676 }
677
678 print '<input type="hidden" name="token" value="'.newToken().'">';
679 if (empty($conf->reception->enabled)) {
680 print '<input type="hidden" name="action" value="dispatch">';
681 } else {
682 print '<input type="hidden" name="action" value="create">';
683 }
684
685 print '<div class="div-table-responsive-no-min">';
686 print '<table class="noborder centpercent">';
687
688 // Set $products_dispatched with qty dispatched for each product id
689 $products_dispatched = array();
690 $sql = "SELECT l.rowid, cfd.fk_product, sum(cfd.qty) as qty";
691 $sql .= " FROM ".MAIN_DB_PREFIX."receptiondet_batch as cfd";
692 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."commande_fournisseurdet as l on l.rowid = cfd.fk_elementdet";
693 $sql .= " WHERE cfd.fk_element = ".((int) $object->id);
694 $sql .= " GROUP BY l.rowid, cfd.fk_product";
695
696 $resql = $db->query($sql);
697 if ($resql) {
698 $num = $db->num_rows($resql);
699 $i = 0;
700
701 if ($num) {
702 while ($i < $num) {
703 $objd = $db->fetch_object($resql);
704 $products_dispatched[$objd->rowid] = price2num($objd->qty, 'MS');
705 $i++;
706 }
707 }
708 $db->free($resql);
709 }
710
711 //$sql = "SELECT l.rowid, l.fk_product, l.subprice, l.remise_percent, l.ref AS sref, SUM(l.qty) as qty,";
712 $sql = "SELECT l.rowid, l.fk_product, l.subprice, l.remise_percent, l.ref AS sref, l.qty as qty,";
713 $sql .= " p.ref, p.label, p.tobatch, p.fk_default_warehouse";
714
715 // Enable hooks to alter the SQL query (SELECT)
716 $parameters = array();
717 $reshook = $hookmanager->executeHooks(
718 'printFieldListSelect',
719 $parameters,
720 $object,
721 $action
722 );
723 if ($reshook < 0) {
724 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
725 }
726 $sql .= $hookmanager->resPrint;
727
728 $sql .= " FROM ".MAIN_DB_PREFIX."commande_fournisseurdet as l";
729 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product as p ON l.fk_product=p.rowid";
730 $sql .= " WHERE l.fk_commande = ".((int) $object->id);
731 if (!getDolGlobalString('STOCK_SUPPORTS_SERVICES')) {
732 $sql .= " AND l.product_type = 0";
733 }
734
735 // Enable hooks to alter the SQL query (WHERE)
736 $parameters = array();
737 $reshook = $hookmanager->executeHooks(
738 'printFieldListWhere',
739 $parameters,
740 $object,
741 $action
742 );
743 if ($reshook < 0) {
744 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
745 }
746 $sql .= $hookmanager->resPrint;
747
748 //$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
749 $sql .= " ORDER BY l.rang, p.ref, p.label";
750
751 // Nb of predefined product lines to dispatch (already done or not) if SUPPLIER_ORDER_DISABLE_STOCK_DISPATCH_WHEN_TOTAL_REACHED is off (default)
752 // or nb of line that remain to dispatch if SUPPLIER_ORDER_DISABLE_STOCK_DISPATCH_WHEN_TOTAL_REACHED is on.
753 $nbproduct = 0;
754
755 $resql = $db->query($sql);
756 if ($resql) {
757 $num = $db->num_rows($resql);
758 $i = 0;
759
760 if ($num) {
761 print '<tr class="liste_titre">';
762
763 print '<td>'.$langs->trans("Description").'</td>';
764 if (isModEnabled('productbatch')) {
765 print '<td class="dispatch_batch_number_title">'.$langs->trans("batch_number").'</td>';
766 if (!getDolGlobalString('PRODUCT_DISABLE_SELLBY')) {
767 print '<td class="dispatch_dlc_title">'.$langs->trans("SellByDate").'</td>';
768 }
769 if (!getDolGlobalString('PRODUCT_DISABLE_EATBY')) {
770 print '<td class="dispatch_dluo_title">'.$langs->trans("EatByDate").'</td>';
771 }
772 } else {
773 print '<td></td>';
774 print '<td></td>';
775 print '<td></td>';
776 }
777 print '<td class="right">'.$langs->trans("SupplierRef").'</td>';
778 print '<td class="right">'.$langs->trans("QtyOrdered").'</td>';
779 print '<td class="right">'.$langs->trans("QtyDispatchedShort").'</td>';
780 print ' <td class="right">'.$langs->trans("QtyToDispatchShort");
781 print '<br><a href="#" id="autoreset">'.img_picto($langs->trans("Reset"), 'eraser', 'class="pictofixedwidth opacitymedium"').$langs->trans("Reset").'</a></td>';
782 print '<td width="32"></td>';
783
784 if (getDolGlobalString('SUPPLIER_ORDER_CAN_UPDATE_BUYINGPRICE_DURING_RECEIPT')) {
785 if (!isModEnabled("multicurrency") && empty($conf->dynamicprices->enabled)) {
786 print '<td class="right">'.$langs->trans("Price").'</td>';
787 print '<td class="right">'.$langs->trans("ReductionShort").' (%)</td>';
788 print '<td class="right">'.$langs->trans("UpdatePrice").'</td>';
789 }
790 }
791
792 print '<td align="right">'.$langs->trans("Warehouse");
793
794 // Select warehouse to force it everywhere
795 if (count($listwarehouses) > 1) {
796 print '<br>'.$form->selectarray('fk_default_warehouse', $listwarehouses, $fk_default_warehouse, $langs->trans("ForceTo"), 0, 0, '', 0, 0, $disabled, '', 'minwidth100 maxwidth300', 1);
797 } elseif (count($listwarehouses) == 1) {
798 print '<br>'.$form->selectarray('fk_default_warehouse', $listwarehouses, $fk_default_warehouse, 0, 0, 0, '', 0, 0, $disabled, '', 'minwidth100 maxwidth300', 1);
799 }
800
801 print '</td>';
802
803 // Enable hooks to append additional columns
804 $parameters = array();
805 $reshook = $hookmanager->executeHooks(
806 'printFieldListTitle',
807 $parameters,
808 $object,
809 $action
810 );
811 if ($reshook < 0) {
812 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
813 }
814 print $hookmanager->resPrint;
815
816 print "</tr>\n";
817 }
818
819 $nbfreeproduct = 0; // Nb of lines of free products/services
820
821 $conf->cache['product'] = array();
822
823 // Loop on each source order line (may be more or less than current number of lines in llx_commande_fournisseurdet)
824 while ($i < $num) {
825 $objp = $db->fetch_object($resql);
826
827 // We don't display free products
828 if (!$objp->fk_product > 0) {
829 $nbfreeproduct++;
830 } else {
831 $alreadydispatched = isset($products_dispatched[$objp->rowid]) ? $products_dispatched[$objp->rowid] : 0;
832 $remaintodispatch = price2num($objp->qty - ((float) $alreadydispatched), 5); // Calculation of dispatched
833 if ($remaintodispatch < 0 && !getDolGlobalString('SUPPLIER_ORDER_ALLOW_NEGATIVE_QTY_FOR_SUPPLIER_ORDER_RETURN')) {
834 $remaintodispatch = 0;
835 }
836
837 if ($remaintodispatch || !getDolGlobalString('SUPPLIER_ORDER_DISABLE_STOCK_DISPATCH_WHEN_TOTAL_REACHED')) {
838 $nbproduct++;
839
840 // To show detail cref and description value, we must make calculation by cref
841 // print ($objp->cref?' ('.$objp->cref.')':'');
842 // if ($objp->description) print '<br>'.nl2br($objp->description);
843 $suffix = '_0_'.$i;
844
845 print "\n";
846 print '<!-- Line to dispatch '.$suffix.' -->'."\n";
847 // hidden fields for js function
848 print '<input id="qty_ordered'.$suffix.'" type="hidden" value="'.$objp->qty.'">';
849 print '<input id="qty_dispatched'.$suffix.'" type="hidden" value="'.(float) $alreadydispatched.'">';
850 print '<tr class="oddeven">';
851
852 if (empty($conf->cache['product'][$objp->fk_product])) {
853 $tmpproduct = new Product($db);
854 $tmpproduct->fetch($objp->fk_product);
855 $conf->cache['product'][$objp->fk_product] = $tmpproduct;
856 } else {
857 $tmpproduct = $conf->cache['product'][$objp->fk_product];
858 }
859
860 $linktoprod = $tmpproduct->getNomUrl(1);
861 $linktoprod .= ' - '.$objp->label."\n";
862
863 if (isModEnabled('productbatch')) {
864 if ($objp->tobatch) {
865 // Product
866 print '<td>';
867 print $linktoprod;
868 print "</td>";
869 print '<td class="dispatch_batch_number"></td>';
870 if (!getDolGlobalString('PRODUCT_DISABLE_SELLBY')) {
871 print '<td class="dispatch_dlc"></td>';
872 }
873 if (!getDolGlobalString('PRODUCT_DISABLE_EATBY')) {
874 print '<td class="dispatch_dluo"></td>';
875 }
876 } else {
877 // Product
878 print '<td>';
879 print $linktoprod;
880 print "</td>";
881 print '<td class="dispatch_batch_number">';
882 print '<span class="opacitymedium small">'.$langs->trans("ProductDoesNotUseBatchSerial").'</small>';
883 print '</td>';
884 if (!getDolGlobalString('PRODUCT_DISABLE_SELLBY')) {
885 print '<td class="dispatch_dlc"></td>';
886 }
887 if (!getDolGlobalString('PRODUCT_DISABLE_EATBY')) {
888 print '<td class="dispatch_dluo"></td>';
889 }
890 }
891 } else {
892 print '<td colspan="4">';
893 print $linktoprod;
894 print "</td>";
895 }
896
897 // Define unit price for PMP calculation
898 $up_ht_disc = $objp->subprice;
899 if (!empty($objp->remise_percent) && !getDolGlobalString('STOCK_EXCLUDE_DISCOUNT_FOR_PMP')) {
900 $up_ht_disc = price2num($up_ht_disc * (100 - $objp->remise_percent) / 100, 'MU');
901 }
902
903 // Supplier ref
904 print '<td class="right">'.$objp->sref.'</td>';
905
906 // Qty ordered
907 print '<td class="right">'.$objp->qty.'</td>';
908
909 // Already dispatched
910 print '<td class="right">'.$alreadydispatched.'</td>';
911
912 if (isModEnabled('productbatch') && $objp->tobatch > 0) {
913 $type = 'batch';
914 print '<td class="right">';
915 print '</td>'; // Qty to dispatch
916 print '<td>';
917 //print img_picto($langs->trans('AddDispatchBatchLine'), 'split', 'class="splitbutton" onClick="addDispatchLine(' . $i . ',\'' . $type . '\')"');
918 print '</td>'; // Dispatch column
919 print '<td></td>'; // Warehouse column
920
921 // Enable hooks to append additional columns
922 $parameters = array(
923 // allows hook to distinguish between the rows with information and the rows with dispatch form input
924 'is_information_row' => true,
925 'i' => $i,
926 'suffix' => $suffix,
927 'objp' => $objp,
928 );
929 $reshook = $hookmanager->executeHooks(
930 'printFieldListValue',
931 $parameters,
932 $object,
933 $action
934 );
935 if ($reshook < 0) {
936 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
937 }
938 print $hookmanager->resPrint;
939
940 print '</tr>';
941
942 print '<tr class="oddeven" name="'.$type.$suffix.'">';
943 print '<td>';
944 print '<input name="fk_commandefourndet'.$suffix.'" type="hidden" value="'.$objp->rowid.'">';
945 print '<input name="product_batch'.$suffix.'" type="hidden" value="'.$objp->fk_product.'">';
946
947 print '<!-- This is a up (may include discount or not depending on STOCK_EXCLUDE_DISCOUNT_FOR_PMP. will be used for PMP calculation) -->';
948 if (getDolGlobalString('SUPPLIER_ORDER_EDIT_BUYINGPRICE_DURING_RECEIPT')) { // Not tested !
949 print $langs->trans("BuyingPrice").': <input class="maxwidth75" name="pu'.$suffix.'" type="text" value="'.price($up_ht_disc).'">';
950 } else {
951 print '<input class="maxwidth75" name="pu'.$suffix.'" type="hidden" value="'.price($up_ht_disc).'">';
952 }
953
954 print '</td>';
955
956 print '<td>';
957 print '<input type="text" class="inputlotnumber quatrevingtquinzepercent" id="lot_number'.$suffix.'" name="lot_number'.$suffix.'" value="'.GETPOST('lot_number'.$suffix).'">';
958 print '</td>';
959 if (!getDolGlobalString('PRODUCT_DISABLE_SELLBY')) {
960 print '<td class="nowraponall">';
961 $dlcdatesuffix = dol_mktime(0, 0, 0, GETPOSTINT('dlc'.$suffix.'month'), GETPOSTINT('dlc'.$suffix.'day'), GETPOSTINT('dlc'.$suffix.'year'));
962 print $form->selectDate($dlcdatesuffix, 'dlc'.$suffix, 0, 0, 1, '');
963 print '</td>';
964 }
965 if (!getDolGlobalString('PRODUCT_DISABLE_EATBY')) {
966 print '<td class="nowraponall">';
967 $dluodatesuffix = dol_mktime(0, 0, 0, GETPOSTINT('dluo'.$suffix.'month'), GETPOSTINT('dluo'.$suffix.'day'), GETPOSTINT('dluo'.$suffix.'year'));
968 print $form->selectDate($dluodatesuffix, 'dluo'.$suffix, 0, 0, 1, '');
969 print '</td>';
970 }
971 print '<td colspan="3">&nbsp;</td>'; // Supplier ref + Qty ordered + qty already dispatched
972 } else {
973 $type = 'dispatch';
974 $colspan = 7;
975 $colspan = (getDolGlobalString('PRODUCT_DISABLE_SELLBY')) ? --$colspan : $colspan;
976 $colspan = (getDolGlobalString('PRODUCT_DISABLE_EATBY')) ? --$colspan : $colspan;
977 print '<td class="right">';
978 print '</td>'; // Qty to dispatch
979 print '<td>';
980 //print img_picto($langs->trans('AddStockLocationLine'), 'split', 'class="splitbutton" onClick="addDispatchLine(' . $i . ',\'' . $type . '\')"');
981 print '</td>'; // Dispatch column
982 print '<td></td>'; // Warehouse column
983
984 // Enable hooks to append additional columns
985 $parameters = array(
986 // allows hook to distinguish between the rows with information and the rows with dispatch form input
987 'is_information_row' => true,
988 'i' => $i,
989 'suffix' => $suffix,
990 'objp' => $objp,
991 );
992 $reshook = $hookmanager->executeHooks(
993 'printFieldListValue',
994 $parameters,
995 $object,
996 $action
997 );
998 if ($reshook < 0) {
999 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
1000 }
1001 print $hookmanager->resPrint;
1002
1003 print '</tr>';
1004
1005 print '<tr class="oddeven" name="'.$type.$suffix.'">';
1006 print '<td colspan="'.$colspan.'">';
1007 print '<input name="fk_commandefourndet'.$suffix.'" type="hidden" value="'.$objp->rowid.'">';
1008 print '<input name="product'.$suffix.'" type="hidden" value="'.$objp->fk_product.'">';
1009
1010 print '<!-- This is a up (may include discount or not depending on STOCK_EXCLUDE_DISCOUNT_FOR_PMP. will be used for PMP calculation) -->';
1011 if (getDolGlobalString('SUPPLIER_ORDER_EDIT_BUYINGPRICE_DURING_RECEIPT')) { // Not tested !
1012 print $langs->trans("BuyingPrice").': <input class="maxwidth75" name="pu'.$suffix.'" type="text" value="'.price2num($up_ht_disc, 'MU').'">';
1013 } else {
1014 print '<input class="maxwidth75" name="pu'.$suffix.'" type="hidden" value="'.price2num($up_ht_disc, 'MU').'">';
1015 }
1016
1017 print '</td>';
1018 }
1019
1020 // Qty to dispatch
1021 print '<td class="right nowrap">';
1022 if ($remaintodispatch > 0) {
1023 $btnLabel = $langs->trans("Fill").' : '.$remaintodispatch;
1024 print '<button class="auto-fill-qty btn-low-emphasis --btn-icon" data-rowname="qty'.$suffix.'" data-value="'.$remaintodispatch.'" title="'.dol_escape_htmltag($btnLabel).'" aria-label="'.dol_escape_htmltag($btnLabel).'" >'.img_picto($btnLabel, 'fa-arrow-right', 'aria-hidden="true"', 0, 0, 1).'</button>';
1025 }
1026 print '<input id="qty'.$suffix.'" name="qty'.$suffix.'" type="number" step="any" class="width50 right qtydispatchinput" value="'.(GETPOSTISSET('qty'.$suffix) ? GETPOSTINT('qty'.$suffix) : (!getDolGlobalString('SUPPLIER_ORDER_DISPATCH_FORCE_QTY_INPUT_TO_ZERO') ? $remaintodispatch : 0)).'">';
1027 print '<button class="resetline btn-low-emphasis --btn-icon" id="reset'.$suffix.'" title="'.dol_escape_htmltag($langs->trans("Reset")).'" >'.img_picto($langs->trans("Reset"), 'eraser', 'aria-hidden="true"', 0, 0, 1).'</button>';
1028 print '</td>';
1029
1030 print '<td>';
1031 if (isModEnabled('productbatch') && $objp->tobatch > 0) {
1032 $type = 'batch';
1033 print img_picto($langs->trans('AddStockLocationLine'), 'split', 'class="splitbutton" onClick="addDispatchLine('.$i.', \''.$type.'\')"');
1034 } else {
1035 $type = 'dispatch';
1036 print img_picto($langs->trans('AddStockLocationLine'), 'split', 'class="splitbutton" onClick="addDispatchLine('.$i.', \''.$type.'\')"');
1037 }
1038 print '</td>';
1039
1040 if (getDolGlobalString('SUPPLIER_ORDER_CAN_UPDATE_BUYINGPRICE_DURING_RECEIPT')) {
1041 if (!isModEnabled("multicurrency") && empty($conf->dynamicprices->enabled)) {
1042 // Price
1043 print '<td class="right">';
1044 print '<input id="pu'.$suffix.'" name="pu'.$suffix.'" type="text" size="8" value="'.price((GETPOST('pu'.$suffix) != '' ? price2num(GETPOST('pu'.$suffix)) : $up_ht_disc)).'">';
1045 print '</td>';
1046
1047 // Discount
1048 print '<td class="right">';
1049 print '<input id="dto'.$suffix.'" name="dto'.$suffix.'" type="text" size="8" value="'.(GETPOST('dto'.$suffix) != '' ? GETPOST('dto'.$suffix) : '').'">';
1050 print '</td>';
1051
1052 // Save price
1053 print '<td class="center">';
1054 print '<input class="flat checkformerge" type="checkbox" name="saveprice'.$suffix.'" value="'.(GETPOST('saveprice'.$suffix) != '' ? GETPOST('saveprice'.$suffix) : '').'">';
1055 print '</td>';
1056 }
1057 }
1058
1059 // Warehouse
1060 print '<td class="right">';
1061 if (count($listwarehouses) > 1) {
1062 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);
1063 } elseif (count($listwarehouses) == 1) {
1064 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);
1065 } else {
1066 $langs->load("errors");
1067 print $langs->trans("ErrorNoWarehouseDefined");
1068 }
1069 print "</td>\n";
1070
1071 // Enable hooks to append additional columns
1072 $parameters = array(
1073 'is_information_row' => false, // this is a dispatch form row
1074 'i' => $i,
1075 'suffix' => $suffix,
1076 'objp' => $objp,
1077 );
1078 $reshook = $hookmanager->executeHooks(
1079 'printFieldListValue',
1080 $parameters,
1081 $object,
1082 $action
1083 );
1084 if ($reshook < 0) {
1085 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
1086 }
1087 print $hookmanager->resPrint;
1088
1089 print "</tr>\n";
1090 }
1091 }
1092 $i++;
1093 }
1094 $db->free($resql);
1095 } else {
1096 dol_print_error($db);
1097 }
1098
1099 print "</table>\n";
1100 print '</div>';
1101
1102 if ($nbproduct) {
1103 $checkboxlabel = $langs->trans("CloseReceivedSupplierOrdersAutomatically", $langs->transnoentitiesnoconv('StatusOrderReceivedAll'));
1104
1105 print '<div class="center">';
1106 $parameters = array();
1107 $reshook = $hookmanager->executeHooks('addMoreActionsButtons', $parameters, $object, $action); // Note that $action and $object may have been
1108 // modified by hook
1109 if (empty($reshook)) {
1110 if (empty($conf->reception->enabled)) {
1111 print $langs->trans("Comment").' : ';
1112 print '<input type="text" class="minwidth400" maxlength="128" name="comment" value="';
1113 print GETPOSTISSET("comment") ? GETPOST("comment") : $langs->trans("DispatchSupplierOrder", $object->ref);
1114 // print ' / '.$object->ref_supplier; // Not yet available
1115 print '" class="flat"><br>';
1116
1117 print '<input type="checkbox" checked="checked" name="closeopenorder"> '.$checkboxlabel;
1118 }
1119
1120 $dispatchBt = empty($conf->reception->enabled) ? $langs->trans("Receive") : $langs->trans("CreateReception");
1121
1122 print '<br>';
1123 print '<input type="hidden" name="backtopageforcancel" value="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'">';
1124 print '<input type="submit" class="button" name="dispatch" value="'.dol_escape_htmltag($dispatchBt).'"';
1125 $disabled = 0;
1126 if (!$permissiontoreceive) {
1127 $disabled = 1;
1128 }
1129 if (count($listwarehouses) <= 0) {
1130 $disabled = 1;
1131 }
1132 if ($disabled) {
1133 print ' disabled';
1134 }
1135
1136 print '>';
1137 }
1138 print '</div>';
1139 }
1140
1141 // Message if nothing to dispatch
1142 if (!$nbproduct) {
1143 print "<br>\n";
1144 if (!getDolGlobalString('SUPPLIER_ORDER_DISABLE_STOCK_DISPATCH_WHEN_TOTAL_REACHED')) {
1145 print '<div class="opacitymedium">'.$langs->trans("NoPredefinedProductToDispatch").'</div>'; // No predefined line at all
1146 } else {
1147 print '<div class="opacitymedium">'.$langs->trans("NoMorePredefinedProductToDispatch").'</div>'; // No predefined line that remain to be dispatched.
1148 }
1149 }
1150
1151 print '</form>';
1152 }
1153
1154 print dol_get_fiche_end();
1155
1156 // default warehouse processing
1157 print '<script type="text/javascript">
1158 $(document).ready(function () {
1159 $("select[name=fk_default_warehouse]").change(function() {
1160 var fk_default_warehouse = $("option:selected", this).val();
1161 $("select[name^=entrepot_]").val(fk_default_warehouse).change();
1162 });
1163
1164 $(".auto-fill-qty").on("click touchstart", function(e){
1165 e.preventDefault();
1166 $("input[name="+$(this).data("rowname")+"]").val($(this).data("value")).trigger("change");
1167 });
1168
1169 $("#autoreset").click(function() {
1170 $(".qtydispatchinput").each(function(){
1171 id = $(this).attr("id");
1172 idtab = id.split("_");
1173 if(idtab[1] == 0){
1174 console.log(idtab);
1175 $(this).val("");
1176 $("#qty_dispatched_0_"+idtab[2]).val("0");
1177 } else {
1178 obj = $(this).parent().parent();
1179 nameobj = obj.attr("name");
1180 nametab = nameobj.split("_");
1181 obj.remove();
1182 $("tr[name^=\'"+nametab[0]+"_\'][name$=\'_"+nametab[2]+"\']:last .splitbutton").show();
1183 }
1184 });
1185 });
1186
1187 $(".resetline").click(function(e){
1188 e.preventDefault();
1189 id = $(this).attr("id");
1190 id = id.split("reset_");
1191 console.log("Reset trigger for id = qty_"+id[1]);
1192 $("#qty_"+id[1]).val("");
1193 });
1194 });
1195 </script>';
1196
1197 // List of lines already dispatched
1198 $sql = "SELECT p.rowid as pid, p.ref, p.label,";
1199 $sql .= " e.rowid as warehouse_id, e.ref as entrepot,";
1200 $sql .= " cfd.rowid as dispatchlineid, cfd.fk_product, cfd.qty, cfd.eatby, cfd.sellby, cfd.batch, cfd.comment, cfd.status, cfd.datec";
1201 $sql .= " ,cd.rowid, cd.subprice";
1202 if (isModEnabled('reception')) {
1203 $sql .= ", cfd.fk_reception, r.date_delivery";
1204 }
1205 $sql .= " FROM ".MAIN_DB_PREFIX."product as p,";
1206 $sql .= " ".MAIN_DB_PREFIX."receptiondet_batch as cfd";
1207 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."commande_fournisseurdet as cd ON cd.rowid = cfd.fk_elementdet";
1208 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."entrepot as e ON cfd.fk_entrepot = e.rowid";
1209 if (isModEnabled('reception')) {
1210 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."reception as r ON cfd.fk_reception = r.rowid";
1211 }
1212 $sql .= " WHERE cfd.fk_element = ".((int) $object->id);
1213 $sql .= " AND cfd.fk_product = p.rowid";
1214 $sql .= " ORDER BY cfd.rowid ASC";
1215
1216 $resql = $db->query($sql);
1217 if ($resql) {
1218 $num = $db->num_rows($resql);
1219 $i = 0;
1220
1221 if ($num > 0) {
1222 print "<br>\n";
1223
1224 print load_fiche_titre($langs->trans("ReceivingForSameOrder"));
1225
1226 print '<div class="div-table-responsive">';
1227 print '<table id="dispatch_received_products" class="noborder centpercent">';
1228
1229 print '<tr class="liste_titre">';
1230 // Reception ref
1231 if (isModEnabled("reception")) {
1232 print '<td>'.$langs->trans("Reception").'</td>';
1233 }
1234 // Product
1235 print '<td>'.$langs->trans("Product").'</td>';
1236 print '<td class="center">'.$langs->trans("DateCreation").'</td>';
1237 print '<td class="center">'.$langs->trans("DateDeliveryPlanned").'</td>';
1238 if (isModEnabled('productbatch')) {
1239 print '<td class="dispatch_batch_number_title">'.$langs->trans("batch_number").'</td>';
1240 if (!getDolGlobalString('PRODUCT_DISABLE_SELLBY')) {
1241 print '<td class="dispatch_dlc_title">'.$langs->trans("SellByDate").'</td>';
1242 }
1243 if (!getDolGlobalString('PRODUCT_DISABLE_EATBY')) {
1244 print '<td class="dispatch_dluo_title">'.$langs->trans("EatByDate").'</td>';
1245 }
1246 }
1247 print '<td class="right">'.$langs->trans("QtyDispatched").'</td>';
1248 print '<td>'.$langs->trans("Warehouse").'</td>';
1249 print '<td>'.$langs->trans("Comment").'</td>';
1250
1251 // Status
1252 if (getDolGlobalString('SUPPLIER_ORDER_USE_DISPATCH_STATUS') && !isModEnabled("reception")) {
1253 print '<td class="center" colspan="2">'.$langs->trans("Status").'</td>';
1254 } elseif (isModEnabled("reception")) {
1255 print '<td class="center"></td>';
1256 }
1257
1258 print '<td class="center" colspan="2"></td>';
1259
1260 print "</tr>\n";
1261
1262
1263 while ($i < $num) {
1264 $objp = $db->fetch_object($resql);
1265
1266 if ($action == 'editline' && $lineid == $objp->dispatchlineid) {
1267 print '<form name="editdispatchedlines" id="editdispatchedlines" action="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'#line_'.GETPOSTINT('lineid').'" method="POST">
1268 <input type="hidden" name="token" value="'.newToken().'">
1269 <input type="hidden" name="action" value="updateline">
1270 <input type="hidden" name="mode" value="">
1271 <input type="hidden" name="lineid" value="'.$objp->dispatchlineid.'">';
1272 }
1273
1274 print '<tr class="oddeven" id="line_'.$objp->dispatchlineid.'" >';
1275
1276 // Reception ref
1277 $reception = null;
1278 if (isModEnabled("reception")) {
1279 print '<td class="nowraponall">';
1280 if (!empty($objp->fk_reception)) {
1281 $reception = new Reception($db);
1282 $reception->fetch($objp->fk_reception);
1283 print $reception->getNomUrl(1);
1284 }
1285
1286 print "</td>";
1287 }
1288
1289 // Product
1290 print '<td class="tdoverflowmax150">';
1291 if (empty($conf->cache['product'][$objp->fk_product])) {
1292 $tmpproduct = new Product($db);
1293 $tmpproduct->fetch($objp->fk_product);
1294 $conf->cache['product'][$objp->fk_product] = $tmpproduct;
1295 } else {
1296 $tmpproduct = $conf->cache['product'][$objp->fk_product];
1297 }
1298 print $tmpproduct->getNomUrl(1);
1299 print ' - '.$objp->label;
1300 print "</td>\n";
1301
1302 // Date creation
1303 print '<td class="center">'.dol_print_date($db->jdate($objp->datec), 'day').'</td>';
1304
1305 // Date delivery of reception
1306 if (isModEnabled('reception')) {
1307 print '<td class="center">';
1308 if (!empty($objp->date_delivery)) {
1309 print dol_print_date($db->jdate($objp->date_delivery), 'day');
1310 }
1311 print '</td>';
1312 } else {
1313 print '<td class="center"></td>';
1314 }
1315
1316 // Batch / Eat by / Sell by
1317 if (isModEnabled('productbatch')) {
1318 if ($objp->batch) {
1319 include_once DOL_DOCUMENT_ROOT.'/product/stock/class/productlot.class.php';
1320 $lot = new Productlot($db);
1321 $lot->fetch(0, $objp->pid, $objp->batch);
1322 print '<td class="dispatch_batch_number" data-col="batch" data-batch="' . dolPrintHTMLForAttribute($objp->batch) . '" data-productid="' . $objp->fk_product . '" >'.$lot->getNomUrl(1).'</td>';
1323 if (!getDolGlobalString('PRODUCT_DISABLE_SELLBY')) {
1324 print '<td class="dispatch_dlc">'.dol_print_date($lot->sellby, 'day').'</td>';
1325 }
1326 if (!getDolGlobalString('PRODUCT_DISABLE_EATBY')) {
1327 print '<td class="dispatch_dluo">'.dol_print_date($lot->eatby, 'day').'</td>';
1328 }
1329 } else {
1330 print '<td class="dispatch_batch_number" data-col="batch" data-batch="" data-productid="' . $objp->fk_product . '" ></td>';
1331 if (!getDolGlobalString('PRODUCT_DISABLE_SELLBY')) {
1332 print '<td class="dispatch_dlc"></td>';
1333 }
1334 if (!getDolGlobalString('PRODUCT_DISABLE_EATBY')) {
1335 print '<td class="dispatch_dluo"></td>';
1336 }
1337 }
1338 }
1339
1340 // Qty
1341 print '<td class="right">';
1342 if ($action == 'editline' && $lineid == $objp->dispatchlineid) {
1343 print '<input style="width: 50px;" type="text" min="1" name="qty" value="'.$objp->qty.'" />';
1344 } else {
1345 print $objp->qty;
1346 }
1347 print '<input type="hidden" name="price" value="'.$objp->subprice.'" />';
1348 print '</td>';
1349 // Warehouse
1350 print '<td class="tdoverflowmax150">';
1351 if ($action == 'editline' && $lineid == $objp->dispatchlineid) {
1352 $warehouse_id = GETPOSTINT("fk_entrepot") ? GETPOSTINT("fk_entrepot") : ($objp->warehouse_id ? $objp->warehouse_id : '');
1353 if (count($listwarehouses) > 1) {
1354 print $formproduct->selectWarehouses($warehouse_id, "fk_entrepot", '', 1, 0, $objp->fk_product, '', 1, 1, array(), 'csswarehouse');
1355 } elseif (count($listwarehouses) == 1) {
1356 print $formproduct->selectWarehouses($warehouse_id, "fk_entrepot", '', 0, 0, $objp->fk_product, '', 1, 1, array(), 'csswarehouse');
1357 } else {
1358 $langs->load("errors");
1359 print $langs->trans("ErrorNoWarehouseDefined");
1360 }
1361 } else {
1362 $warehouse_static->id = $objp->warehouse_id;
1363 $warehouse_static->label = $objp->entrepot;
1364 print $warehouse_static->getNomUrl(1);
1365 }
1366 print '</td>';
1367
1368 // Comment
1369 print '<td class="tdoverflowmax300" style="white-space: pre;">'.$objp->comment.'</td>';
1370
1371 // Status
1372 if (getDolGlobalString('SUPPLIER_ORDER_USE_DISPATCH_STATUS') && !isModEnabled("reception")) {
1373 print '<td class="right">';
1374 $supplierorderdispatch->status = (empty($objp->status) ? 0 : $objp->status);
1375 // print $supplierorderdispatch->status;
1376 print $supplierorderdispatch->getLibStatut(5);
1377 print '</td>';
1378
1379 // Add button to check/uncheck dispatching
1380 print '<td class="center">';
1381 if (!$permissiontocontrol) {
1382 if (empty($objp->status)) {
1383 print '<a class="button buttonRefused" href="#">'.$langs->trans("Approve").'</a>';
1384 print '<a class="button buttonRefused" href="#">'.$langs->trans("Deny").'</a>';
1385 } else {
1386 print '<a class="button buttonRefused" href="#">'.$langs->trans("Disapprove").'</a>';
1387 print '<a class="button buttonRefused" href="#">'.$langs->trans("Deny").'</a>';
1388 }
1389 } else {
1390 $disabled = '';
1391 if ($object->status == $object::STATUS_RECEIVED_COMPLETELY) {
1392 $disabled = 1;
1393 }
1394 if (empty($objp->status)) {
1395 print '<a class="button'.($disabled ? ' buttonRefused' : '').'" href="'.$_SERVER["PHP_SELF"]."?id=".$id."&action=checkdispatchline&lineid=".$objp->dispatchlineid.'">'.$langs->trans("Approve").'</a>';
1396 print '<a class="button'.($disabled ? ' buttonRefused' : '').'" href="'.$_SERVER["PHP_SELF"]."?id=".$id."&action=denydispatchline&lineid=".$objp->dispatchlineid.'">'.$langs->trans("Deny").'</a>';
1397 }
1398 if ($objp->status == 1) {
1399 print '<a class="button'.($disabled ? ' buttonRefused' : '').'" href="'.$_SERVER["PHP_SELF"]."?id=".$id."&action=uncheckdispatchline&lineid=".$objp->dispatchlineid.'">'.$langs->trans("Reinit").'</a>';
1400 print '<a class="button'.($disabled ? ' buttonRefused' : '').'" href="'.$_SERVER["PHP_SELF"]."?id=".$id."&action=denydispatchline&lineid=".$objp->dispatchlineid.'">'.$langs->trans("Deny").'</a>';
1401 }
1402 if ($objp->status == 2) {
1403 print '<a class="button'.($disabled ? ' buttonRefused' : '').'" href="'.$_SERVER["PHP_SELF"]."?id=".$id."&action=uncheckdispatchline&lineid=".$objp->dispatchlineid.'">'.$langs->trans("Reinit").'</a>';
1404 print '<a class="button'.($disabled ? ' buttonRefused' : '').'" href="'.$_SERVER["PHP_SELF"]."?id=".$id."&action=checkdispatchline&lineid=".$objp->dispatchlineid.'">'.$langs->trans("Approve").'</a>';
1405 }
1406 }
1407 print '</td>';
1408 } elseif (isModEnabled("reception")) {
1409 print '<td class="right">';
1410 if ($reception !== null && !empty($reception->id)) {
1411 print $reception->getLibStatut(5);
1412 }
1413 print '</td>';
1414 }
1415
1416 // Action
1417 if ($action != 'editline' || $lineid != $objp->dispatchlineid) {
1418 if (($reception === null) || empty($reception->id) || ($reception->statut == Reception::STATUS_DRAFT)) { // only allow edit on draft reception
1419 print '<td class="linecoledit center">';
1420 print '<a class="reposition" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=editline&token='.newToken().'&lineid='.$objp->dispatchlineid.'#line_'.$objp->dispatchlineid.'">';
1421 print img_edit();
1422 print '</a>';
1423 print '</td>';
1424
1425 print '<td class="linecoldelete center">';
1426 print '<a href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=ask_deleteline&token='.newToken().'&lineid='.$objp->dispatchlineid.'#dispatch_received_products">';
1427 print img_delete();
1428 print '</a>';
1429 print '</td>';
1430 } else {
1431 print '<td></td><td></td>';
1432 }
1433 } else {
1434 print '<td class="center valignmiddle">';
1435 print '<input type="submit" class="button button-save" id="savelinebutton" name="save" value="'.$langs->trans("Save").'" />';
1436 print '</td>';
1437 print '<td class="center valignmiddle">';
1438 print '<input type="submit" class="button button-cancel" id="cancellinebutton" name="cancel" value="'.$langs->trans("Cancel").'" />';
1439 print '</td>';
1440 }
1441
1442
1443 print "</tr>\n";
1444 if ($action == 'editline' && $lineid == $objp->dispatchlineid) {
1445 print '</form>';
1446 }
1447
1448 $i++;
1449 }
1450 $db->free($resql);
1451
1452 print "</table>\n";
1453 print '</div>';
1454 }
1455 } else {
1457 }
1458}
1459
1460// End of page
1461llxFooter();
1462$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.
const STATUS_RECEIVED_PARTIALLY
Received partially.
const STATUS_CANCELED
Order canceled.
const STATUS_RECEIVED_COMPLETELY
Received completely.
const STATUS_ORDERSENT
Order sent, shipment on process.
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 stock movements.
Class to manage products or services.
Class with list of lots and properties.
Class to manage projects.
Class to manage receptions.
Class to manage third parties objects (customers, suppliers, prospects...)
Class to manage Dolibarr users.
if(!isModEnabled('ai')||!getDolGlobalString('AI_ASSISTANT_ENABLED')) global $conf
The main.inc.php has been included so the following variable are now defined:
if(!isModEnabled('ai')||!getDolGlobalString('AI_ASSISTANT_ENABLED')) global $db
API class for accounts.
ordersupplier_prepare_head(CommandeFournisseur $object)
Prepare array with list of tabs.
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)
img_delete($titlealt='default', $other='class="pictodelete"', $morecss='')
Show delete logo.
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.
dolPrintHTMLForAttribute($s, $escapeonlyhtmltags=0, $allowothertags=array())
Return a string ready to be output into an HTML attribute (alt, title, data-html, ....
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).
dol_print_error($db=null, $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
load_fiche_titre($title, $morehtmlright='', $picto='generic', $pictoisfullpath=0, $id='', $morecssontable='', $morehtmlcenter='', $morecssonpicto='widthpictotitle')
Load a title with picto.
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.
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0, $cleanalsojavascript=0)
Returns text escaped for inclusion in HTML alt or title or value tags, or into values of HTML input f...
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.
print $langs trans("Show") . '< td style="' . $timeColor . '" align="center"> s</td > badge status0 badge status4 badge status3 Error badge status8< td align="center">< span class="badge ' . $badge . '"></span ></td >< td align="center">< a href="#" class="button button-small" onclick="openLogModal(this)" data-req="' . dol_escape_htmltag($reqSafe) . '" data-res="' . dol_escape_htmltag($resSafe) . '" data-err="' . dol_escape_htmltag($errSafe) . '">< span class="fa fa-search-plus"></span ></a ></td ></tr >< tr >< td colspan="' . $colspan . '" class="opacitymedium"></td ></tr ></table ></div ></form > logModal none logModal none s a JSON string
buildzip.php
$conf db name
Only used if Module[ID]Name translation string is not found.
Definition repair.php:133
restrictedArea(User $user, $features, $object=0, $tableandshare='', $feature2='', $dbt_keyfield='fk_soc', $dbt_select='rowid', $isdraft=0, $mode=0)
Check permissions of a user to show a page and an object.
accessforbidden($message='', $printheader=1, $printfooter=1, $showonlymessage=0, $params=null)
Show a message to say access is forbidden and stop program.