dolibarr 20.0.0
replenish.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2013 Cédric Salvador <csalvador@gpcsolutions.fr>
3 * Copyright (C) 2013-2018 Laurent Destaileur <ely@users.sourceforge.net>
4 * Copyright (C) 2014 Regis Houssin <regis.houssin@inodbox.com>
5 * Copyright (C) 2016 Juanjo Menent <jmenent@2byte.es>
6 * Copyright (C) 2016 ATM Consulting <support@atm-consulting.fr>
7 * Copyright (C) 2019 Frédéric France <frederic.france@netlogic.fr>
8 * Copyright (C) 2021 Ferran Marcet <fmarcet@2byte.es>
9 * Copyright (C) 2021 Antonin MARCHAL <antonin@letempledujeu.fr>
10 *
11 * This program is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation, either version 3 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program. If not, see <https://www.gnu.org/licenses/>.
23 */
24
31// Load Dolibarr environment
32require '../../main.inc.php';
33require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
34require_once DOL_DOCUMENT_ROOT . '/core/class/html.formother.class.php';
35require_once DOL_DOCUMENT_ROOT . '/core/class/html.form.class.php';
36require_once DOL_DOCUMENT_ROOT . '/fourn/class/fournisseur.commande.class.php';
37require_once DOL_DOCUMENT_ROOT . '/product/class/html.formproduct.class.php';
38require_once './lib/replenishment.lib.php';
39
40// Load translation files required by the page
41$langs->loadLangs(array('products', 'stocks', 'orders'));
42
43// Security check
44if ($user->socid) {
45 $socid = $user->socid;
46}
47$result = restrictedArea($user, 'produit|service');
48
49// Initialize technical object to manage hooks of page. Note that conf->hooks_modules contains array of hook context
50$hookmanager->initHooks(array('stockreplenishlist'));
51
52//checks if a product has been ordered
53
54$action = GETPOST('action', 'aZ09');
55$search_ref = GETPOST('search_ref', 'alpha');
56$search_label = GETPOST('search_label', 'alpha');
57$sall = trim((GETPOST('search_all', 'alphanohtml') != '') ? GETPOST('search_all', 'alphanohtml') : GETPOST('sall', 'alphanohtml'));
58$type = GETPOSTINT('type');
59$tobuy = GETPOSTINT('tobuy');
60$salert = GETPOST('salert', 'alpha');
61$includeproductswithoutdesiredqty = GETPOST('includeproductswithoutdesiredqty', 'alpha');
62$mode = GETPOST('mode', 'alpha');
63$draftorder = GETPOST('draftorder', 'alpha');
64
65
66$fourn_id = GETPOSTINT('fourn_id');
67$fk_supplier = GETPOSTINT('fk_supplier');
68$fk_entrepot = GETPOSTINT('fk_entrepot');
69
70// List all visible warehouses
71$resWar = $db->query("SELECT rowid FROM " . MAIN_DB_PREFIX . "entrepot WHERE entity IN (" . $db->sanitize(getEntity('stock')) . ")");
72$listofqualifiedwarehousesid = "";
73$count = 0;
74while ($tmpobj = $db->fetch_object($resWar)) {
75 if (!empty($listofqualifiedwarehousesid)) {
76 $listofqualifiedwarehousesid .= ",";
77 }
78 $listofqualifiedwarehousesid .= $tmpobj->rowid;
79 $lastWarehouseID = $tmpobj->rowid;
80 $count++;
81}
82
83//MultiCompany : If only 1 Warehouse is visible, filter will automatically be set to it.
84if ($count == 1 && (empty($fk_entrepot) || $fk_entrepot <= 0) && getDolGlobalString('MULTICOMPANY_PRODUCT_SHARING_ENABLED')) {
85 $fk_entrepot = $lastWarehouseID;
86}
87
88$texte = '';
89
90$sortfield = GETPOST('sortfield', 'aZ09comma');
91$sortorder = GETPOST('sortorder', 'aZ09comma');
92$page = GETPOSTISSET('pageplusone') ? (GETPOSTINT('pageplusone') - 1) : GETPOSTINT("page");
93if (empty($page) || $page == -1) {
94 $page = 0;
95} // If $page is not defined, or '' or -1
96$limit = GETPOSTINT('limit') ? GETPOSTINT('limit') : $conf->liste_limit;
97$offset = $limit * $page;
98
99if (!$sortfield) {
100 $sortfield = 'p.ref';
101}
102
103if (!$sortorder) {
104 $sortorder = 'ASC';
105}
106
107// Define virtualdiffersfromphysical
108$virtualdiffersfromphysical = 0;
109if (getDolGlobalString('STOCK_CALCULATE_ON_SHIPMENT')
110 || getDolGlobalString('STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER')
111 || getDolGlobalString('STOCK_CALCULATE_ON_SHIPMENT_CLOSE')
112 || getDolGlobalString('STOCK_CALCULATE_ON_RECEPTION')
113 || getDolGlobalString('STOCK_CALCULATE_ON_RECEPTION_CLOSE')
114 || isModEnabled('mrp')) {
115 $virtualdiffersfromphysical = 1; // According to increase/decrease stock options, virtual and physical stock may differs.
116}
117
118if ($virtualdiffersfromphysical) {
119 $usevirtualstock = !getDolGlobalString('STOCK_USE_REAL_STOCK_BY_DEFAULT_FOR_REPLENISHMENT') ? 1 : 0;
120} else {
121 $usevirtualstock = 0;
122}
123if ($mode == 'physical') {
124 $usevirtualstock = 0;
125}
126if ($mode == 'virtual') {
127 $usevirtualstock = 1;
128}
129
130$parameters = array();
131$reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
132if ($reshook < 0) {
133 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
134}
135
136
137/*
138 * Actions
139 */
140
141if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x', 'alpha') || GETPOST('button_removefilter', 'alpha')) { // Both test are required to be compatible with all browsers
142 $search_ref = '';
143 $search_label = '';
144 $sall = '';
145 $salert = '';
146 $includeproductswithoutdesiredqty = '';
147 $draftorder = '';
148}
149$draftchecked = "";
150if ($draftorder == 'on') {
151 $draftchecked = "checked";
152}
153
154// Create orders
155if ($action == 'order' && GETPOST('valid')) {
156 $linecount = GETPOSTINT('linecount');
157 $box = 0;
158 $errorQty = 0;
159 unset($_POST['linecount']);
160 if ($linecount > 0) {
161 $db->begin();
162
163 $suppliers = array();
164 require_once DOL_DOCUMENT_ROOT . '/fourn/class/fournisseur.product.class.php';
165 $productsupplier = new ProductFournisseur($db);
166 for ($i = 0; $i < $linecount; $i++) {
167 if (GETPOST('choose'.$i) === 'on' && GETPOSTINT('fourn'.$i) > 0) {
168 //one line
169 $box = $i;
170 $supplierpriceid = GETPOSTINT('fourn'.$i);
171 //get all the parameters needed to create a line
172 $qty = GETPOSTINT('tobuy'.$i);
173 $idprod = $productsupplier->get_buyprice($supplierpriceid, $qty);
174 $res = $productsupplier->fetch($idprod);
175 if ($res && $idprod > 0) {
176 if ($qty) {
177 //might need some value checks
178 $line = new CommandeFournisseurLigne($db);
179 $line->qty = $qty;
180 $line->fk_product = $idprod;
181
182 //$product = new Product($db);
183 //$product->fetch($obj->fk_product);
184 if (getDolGlobalInt('MAIN_MULTILANGS')) {
185 $productsupplier->getMultiLangs();
186 }
187
188 // if we use supplier description of the products
189 if (!empty($productsupplier->desc_supplier) && getDolGlobalString('PRODUIT_FOURN_TEXTS')) {
190 $desc = $productsupplier->desc_supplier;
191 } else {
192 $desc = $productsupplier->description;
193 }
194 $line->desc = $desc;
195 if (getDolGlobalInt('MAIN_MULTILANGS')) {
196 // TODO Get desc in language of thirdparty
197 }
198
199 // If we use multicurrency
200 if (isModEnabled('multicurrency') && !empty($productsupplier->fourn_multicurrency_code) && $productsupplier->fourn_multicurrency_code != $conf->currency) {
201 $line->multicurrency_code = $productsupplier->fourn_multicurrency_code;
202 $line->fk_multicurrency = $productsupplier->fourn_multicurrency_id;
203 $line->multicurrency_subprice = $productsupplier->fourn_multicurrency_unitprice;
204 }
205
206 $line->tva_tx = $productsupplier->vatrate_supplier;
207 $line->subprice = $productsupplier->fourn_pu;
208 $line->total_ht = $productsupplier->fourn_pu * $qty;
209 $tva = $line->tva_tx / 100;
210 $line->total_tva = $line->total_ht * $tva;
211 $line->total_ttc = $line->total_ht + $line->total_tva;
212 $line->remise_percent = $productsupplier->remise_percent;
213 $line->ref_fourn = $productsupplier->ref_supplier;
214 $line->type = $productsupplier->type;
215 $line->fk_unit = $productsupplier->fk_unit;
216 $suppliers[$productsupplier->fourn_socid]['lines'][] = $line;
217 }
218 } elseif ($idprod == -1) {
219 $errorQty++;
220 } else {
221 $error = $db->lasterror();
222 dol_print_error($db);
223 }
224
225 unset($_POST['fourn' . $i]);
226 }
227 unset($_POST[$i]);
228 }
229
230 //we now know how many orders we need and what lines they have
231 $i = 0;
232 $fail = 0;
233 $orders = array();
234 $suppliersid = array_keys($suppliers); // array of ids of suppliers
235 foreach ($suppliers as $supplier) {
236 $order = new CommandeFournisseur($db);
237
238 // Check if an order for the supplier exists
239 $sql = "SELECT rowid FROM " . MAIN_DB_PREFIX . "commande_fournisseur";
240 $sql .= " WHERE fk_soc = " . ((int) $suppliersid[$i]);
241 $sql .= " AND source = " . ((int) $order::SOURCE_ID_REPLENISHMENT) . " AND fk_statut = " . ((int) $order::STATUS_DRAFT);
242 $sql .= " AND entity IN (" . getEntity('commande_fournisseur') . ")";
243 $sql .= " ORDER BY date_creation DESC";
244 $resql = $db->query($sql);
245 if ($resql && $db->num_rows($resql) > 0) {
246 $obj = $db->fetch_object($resql);
247
248 $order->fetch($obj->rowid);
249 $order->fetch_thirdparty();
250
251 foreach ($supplier['lines'] as $line) {
252 if (empty($line->remise_percent)) {
253 $line->remise_percent = $order->thirdparty->remise_supplier_percent;
254 }
255 $result = $order->addline(
256 $line->desc,
257 $line->subprice,
258 $line->qty,
259 $line->tva_tx,
260 $line->localtax1_tx,
261 $line->localtax2_tx,
262 $line->fk_product,
263 0,
264 $line->ref_fourn,
265 $line->remise_percent,
266 'HT',
267 0,
268 $line->type,
269 0,
270 false,
271 null,
272 null,
273 0,
274 $line->fk_unit,
275 $line->multicurrency_subprice ?? 0
276 );
277 }
278 if ($result < 0) {
279 $fail++;
280 $msg = $langs->trans('OrderFail') . "&nbsp;:&nbsp;";
281 $msg .= $order->error;
282 setEventMessages($msg, null, 'errors');
283 } else {
284 $id = $result;
285 }
286 $i++;
287 } else {
288 $order->socid = $suppliersid[$i];
289 $order->fetch_thirdparty();
290 $order->multicurrency_code = $order->thirdparty->multicurrency_code;
291
292 // Trick to know which orders have been generated using the replenishment feature
293 $order->source = $order::SOURCE_ID_REPLENISHMENT;
294
295 foreach ($supplier['lines'] as $line) {
296 if (empty($line->remise_percent)) {
297 $line->remise_percent = $order->thirdparty->remise_supplier_percent;
298 }
299 $order->lines[] = $line;
300 }
301 $order->cond_reglement_id = $order->thirdparty->cond_reglement_supplier_id;
302 $order->mode_reglement_id = $order->thirdparty->mode_reglement_supplier_id;
303
304 $id = $order->create($user);
305 if ($id < 0) {
306 $fail++;
307 $msg = $langs->trans('OrderFail') . "&nbsp;:&nbsp;";
308 $msg .= $order->error;
309 setEventMessages($msg, null, 'errors');
310 }
311 $i++;
312 }
313 }
314
315 if ($errorQty) {
316 setEventMessages($langs->trans('ErrorOrdersNotCreatedQtyTooLow'), null, 'warnings');
317 }
318
319 if (!$fail && $id) {
320 $db->commit();
321
322 setEventMessages($langs->trans('OrderCreated'), null, 'mesgs');
323 header('Location: replenishorders.php');
324 exit;
325 } else {
326 $db->rollback();
327 }
328 }
329 if ($box == 0) {
330 setEventMessages($langs->trans('SelectProductWithNotNullQty'), null, 'warnings');
331 }
332}
333
334
335/*
336 * View
337 */
338
339$form = new Form($db);
340$formproduct = new FormProduct($db);
341$prod = new Product($db);
342
343$title = $langs->trans('MissingStocks');
344
345if (getDolGlobalString('STOCK_ALLOW_ADD_LIMIT_STOCK_BY_WAREHOUSE') && $fk_entrepot > 0) {
346 $sqldesiredtock = $db->ifsql("pse.desiredstock IS NULL", "p.desiredstock", "pse.desiredstock");
347 $sqlalertstock = $db->ifsql("pse.seuil_stock_alerte IS NULL", "p.seuil_stock_alerte", "pse.seuil_stock_alerte");
348} else {
349 $sqldesiredtock = 'p.desiredstock';
350 $sqlalertstock = 'p.seuil_stock_alerte';
351}
352
353$sql = 'SELECT p.rowid, p.ref, p.label, p.description, p.price,';
354$sql .= ' p.price_ttc, p.price_base_type, p.fk_product_type,';
355$sql .= ' p.tms as datem, p.duration, p.tobuy,';
356$sql .= ' p.desiredstock, p.seuil_stock_alerte,';
357if (getDolGlobalString('STOCK_ALLOW_ADD_LIMIT_STOCK_BY_WAREHOUSE') && $fk_entrepot > 0) {
358 $sql .= ' pse.desiredstock as desiredstockpse, pse.seuil_stock_alerte as seuil_stock_alertepse,';
359}
360$sql .= " " . $sqldesiredtock . " as desiredstockcombined, " . $sqlalertstock . " as seuil_stock_alertecombined,";
361$sql .= ' s.fk_product,';
362$sql .= " SUM(".$db->ifsql("s.reel IS NULL", "0", "s.reel").') as stock_physique';
363if (getDolGlobalString('STOCK_ALLOW_ADD_LIMIT_STOCK_BY_WAREHOUSE') && $fk_entrepot > 0) {
364 $sql .= ", SUM(".$db->ifsql("s.reel IS NULL OR s.fk_entrepot <> ".((int) $fk_entrepot), "0", "s.reel").') as stock_real_warehouse';
365}
366
367// Add fields from hooks
368$parameters = array();
369$reshook = $hookmanager->executeHooks('printFieldListSelect', $parameters); // Note that $action and $object may have been modified by hook
370$sql .= $hookmanager->resPrint;
371
372$list_warehouse = (empty($listofqualifiedwarehousesid) ? '0' : $listofqualifiedwarehousesid);
373
374$sql .= ' FROM ' . MAIN_DB_PREFIX . 'product as p';
375$sql .= ' LEFT JOIN ' . MAIN_DB_PREFIX . 'product_stock as s ON p.rowid = s.fk_product';
376$sql .= ' AND s.fk_entrepot IN (' . $db->sanitize($list_warehouse) . ')';
377
378$list_warehouse_selected = ($fk_entrepot < 0 || empty($fk_entrepot)) ? $list_warehouse : $fk_entrepot;
379$sql .= ' AND s.fk_entrepot IN (' . $db->sanitize($list_warehouse_selected) . ')';
380
381
382//$sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'entrepot AS ent ON s.fk_entrepot = ent.rowid AND ent.entity IN('.getEntity('stock').')';
383if (getDolGlobalString('STOCK_ALLOW_ADD_LIMIT_STOCK_BY_WAREHOUSE') && $fk_entrepot > 0) {
384 $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'product_warehouse_properties AS pse ON (p.rowid = pse.fk_product AND pse.fk_entrepot = '.((int) $fk_entrepot).')';
385}
386// Add fields from hooks
387$parameters = array();
388$reshook = $hookmanager->executeHooks('printFieldListJoin', $parameters); // Note that $action and $object may have been modified by hook
389$sql .= $hookmanager->resPrint;
390
391$sql .= ' WHERE p.entity IN (' . getEntity('product') . ')';
392if ($sall) {
393 $sql .= natural_search(array('p.ref', 'p.label', 'p.description', 'p.note'), $sall);
394}
395// if the type is not 1, we show all products (type = 0,2,3)
396if (dol_strlen($type)) {
397 if ($type == 1) {
398 $sql .= ' AND p.fk_product_type = 1';
399 } else {
400 $sql .= ' AND p.fk_product_type <> 1';
401 }
402}
403if ($search_ref) {
404 $sql .= natural_search('p.ref', $search_ref);
405}
406if ($search_label) {
407 $sql .= natural_search('p.label', $search_label);
408}
409$sql .= ' AND p.tobuy = 1';
410if (isModEnabled('variants') && !getDolGlobalString('VARIANT_ALLOW_STOCK_MOVEMENT_ON_VARIANT_PARENT')) { // Add test to exclude products that has variants
411 $sql .= ' AND p.rowid NOT IN (SELECT pac.fk_product_parent FROM '.MAIN_DB_PREFIX.'product_attribute_combination as pac WHERE pac.entity IN ('.getEntity('product').'))';
412}
413if ($fk_supplier > 0) {
414 $sql .= ' AND EXISTS (SELECT pfp.rowid FROM ' . MAIN_DB_PREFIX . 'product_fournisseur_price as pfp WHERE pfp.fk_product = p.rowid AND pfp.fk_soc = ' . ((int) $fk_supplier) . ' AND pfp.entity IN (' . getEntity('product_fournisseur_price') . '))';
415}
416// Add where from hooks
417$parameters = array();
418$reshook = $hookmanager->executeHooks('printFieldListWhere', $parameters); // Note that $action and $object may have been modified by hook
419$sql .= $hookmanager->resPrint;
420
421$sql .= ' GROUP BY p.rowid, p.ref, p.label, p.description, p.price';
422$sql .= ', p.price_ttc, p.price_base_type,p.fk_product_type, p.tms';
423$sql .= ', p.duration, p.tobuy';
424$sql .= ', p.desiredstock';
425$sql .= ', p.seuil_stock_alerte';
426if (getDolGlobalString('STOCK_ALLOW_ADD_LIMIT_STOCK_BY_WAREHOUSE') && $fk_entrepot > 0) {
427 $sql .= ', pse.desiredstock';
428 $sql .= ', pse.seuil_stock_alerte';
429}
430$sql .= ', s.fk_product';
431
432if ($usevirtualstock) {
433 if (isModEnabled('order')) {
434 $sqlCommandesCli = "(SELECT ".$db->ifsql("SUM(cd1.qty) IS NULL", "0", "SUM(cd1.qty)")." as qty"; // We need the ifsql because if result is 0 for product p.rowid, we must return 0 and not NULL
435 $sqlCommandesCli .= " FROM ".MAIN_DB_PREFIX."commandedet as cd1, ".MAIN_DB_PREFIX."commande as c1";
436 $sqlCommandesCli .= " WHERE c1.rowid = cd1.fk_commande AND c1.entity IN (".getEntity(getDolGlobalString('STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE') ? 'stock' : 'commande').")";
437 $sqlCommandesCli .= " AND cd1.fk_product = p.rowid";
438 $sqlCommandesCli .= " AND c1.fk_statut IN (1,2))";
439 } else {
440 $sqlCommandesCli = '0';
441 }
442
443 if (isModEnabled("shipping")) {
444 $sqlExpeditionsCli = "(SELECT ".$db->ifsql("SUM(ed2.qty) IS NULL", "0", "SUM(ed2.qty)")." as qty"; // We need the ifsql because if result is 0 for product p.rowid, we must return 0 and not NULL
445 $sqlExpeditionsCli .= " FROM ".MAIN_DB_PREFIX."expedition as e2,";
446 $sqlExpeditionsCli .= " ".MAIN_DB_PREFIX."expeditiondet as ed2,";
447 $sqlExpeditionsCli .= " ".MAIN_DB_PREFIX."commande as c2,";
448 $sqlExpeditionsCli .= " ".MAIN_DB_PREFIX."commandedet as cd2";
449 $sqlExpeditionsCli .= " WHERE ed2.fk_expedition = e2.rowid AND cd2.rowid = ed2.fk_elementdet AND e2.entity IN (".getEntity(getDolGlobalString('STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE') ? 'stock' : 'expedition').")";
450 $sqlExpeditionsCli .= " AND cd2.fk_commande = c2.rowid";
451 $sqlExpeditionsCli .= " AND c2.fk_statut IN (1,2)";
452 $sqlExpeditionsCli .= " AND cd2.fk_product = p.rowid";
453 $sqlExpeditionsCli .= " AND e2.fk_statut IN (1,2))";
454 } else {
455 $sqlExpeditionsCli = '0';
456 }
457
458 if (isModEnabled("supplier_order")) {
459 $sqlCommandesFourn = "(SELECT " . $db->ifsql("SUM(cd3.qty) IS NULL", "0", "SUM(cd3.qty)") . " as qty"; // We need the ifsql because if result is 0 for product p.rowid, we must return 0 and not NULL
460 $sqlCommandesFourn .= " FROM " . MAIN_DB_PREFIX . "commande_fournisseurdet as cd3,";
461 $sqlCommandesFourn .= " " . MAIN_DB_PREFIX . "commande_fournisseur as c3";
462 $sqlCommandesFourn .= " WHERE c3.rowid = cd3.fk_commande";
463 $sqlCommandesFourn .= " AND c3.entity IN (".getEntity(getDolGlobalString('STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE') ? 'stock' : 'supplier_order').")";
464 $sqlCommandesFourn .= " AND cd3.fk_product = p.rowid";
465 $sqlCommandesFourn .= " AND c3.fk_statut IN (3,4))";
466
467 $sqlReceptionFourn = "(SELECT ".$db->ifsql("SUM(fd4.qty) IS NULL", "0", "SUM(fd4.qty)")." as qty"; // We need the ifsql because if result is 0 for product p.rowid, we must return 0 and not NULL
468 $sqlReceptionFourn .= " FROM ".MAIN_DB_PREFIX."commande_fournisseur as cf4,";
469 $sqlReceptionFourn .= " ".MAIN_DB_PREFIX."receptiondet_batch as fd4";
470 $sqlReceptionFourn .= " WHERE fd4.fk_element = cf4.rowid AND cf4.entity IN (".getEntity(getDolGlobalString('STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE') ? 'stock' : 'supplier_order').")";
471 $sqlReceptionFourn .= " AND fd4.fk_product = p.rowid";
472 $sqlReceptionFourn .= " AND cf4.fk_statut IN (3,4))";
473 } else {
474 $sqlCommandesFourn = '0';
475 $sqlReceptionFourn = '0';
476 }
477
478 if (isModEnabled('mrp')) {
479 $sqlProductionToConsume = "(SELECT GREATEST(0, ".$db->ifsql("SUM(".$db->ifsql("mp5.role = 'toconsume'", 'mp5.qty', '- mp5.qty').") IS NULL", "0", "SUM(".$db->ifsql("mp5.role = 'toconsume'", 'mp5.qty', '- mp5.qty').")").") as qty"; // We need the ifsql because if result is 0 for product p.rowid, we must return 0 and not NULL
480 $sqlProductionToConsume .= " FROM ".MAIN_DB_PREFIX."mrp_mo as mm5,";
481 $sqlProductionToConsume .= " ".MAIN_DB_PREFIX."mrp_production as mp5";
482 $sqlProductionToConsume .= " WHERE mm5.rowid = mp5.fk_mo AND mm5.entity IN (".getEntity(getDolGlobalString('STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE') ? 'stock' : 'mo').")";
483 $sqlProductionToConsume .= " AND mp5.fk_product = p.rowid";
484 $sqlProductionToConsume .= " AND mp5.role IN ('toconsume', 'consumed')";
485 $sqlProductionToConsume .= " AND mm5.status IN (1,2))";
486
487 $sqlProductionToProduce = "(SELECT GREATEST(0, ".$db->ifsql("SUM(".$db->ifsql("mp5.role = 'toproduce'", 'mp5.qty', '- mp5.qty').") IS NULL", "0", "SUM(".$db->ifsql("mp5.role = 'toproduce'", 'mp5.qty', '- mp5.qty').")").") as qty"; // We need the ifsql because if result is 0 for product p.rowid, we must return 0 and not NULL
488 $sqlProductionToProduce .= " FROM ".MAIN_DB_PREFIX."mrp_mo as mm5,";
489 $sqlProductionToProduce .= " ".MAIN_DB_PREFIX."mrp_production as mp5";
490 $sqlProductionToProduce .= " WHERE mm5.rowid = mp5.fk_mo AND mm5.entity IN (".getEntity(getDolGlobalString('STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE') ? 'stock' : 'mo').")";
491 $sqlProductionToProduce .= " AND mp5.fk_product = p.rowid";
492 $sqlProductionToProduce .= " AND mp5.role IN ('toproduce', 'produced')";
493 $sqlProductionToProduce .= " AND mm5.status IN (1,2))";
494 } else {
495 $sqlProductionToConsume = '0';
496 $sqlProductionToProduce = '0';
497 }
498
499 $sql .= ' HAVING (';
500 $sql .= " (" . $sqldesiredtock . " >= 0 AND (" . $sqldesiredtock . " > SUM(" . $db->ifsql("s.reel IS NULL", "0", "s.reel") . ')';
501 $sql .= " - (" . $sqlCommandesCli . " - " . $sqlExpeditionsCli . ") + (" . $sqlCommandesFourn . " - " . $sqlReceptionFourn . ") + (" . $sqlProductionToProduce . " - " . $sqlProductionToConsume . ")))";
502 $sql .= ' OR';
503 if ($includeproductswithoutdesiredqty == 'on') {
504 $sql .= " ((" . $sqlalertstock . " >= 0 OR " . $sqlalertstock . " IS NULL) AND (" . $db->ifsql($sqlalertstock . " IS NULL", "0", $sqlalertstock) . " > SUM(" . $db->ifsql("s.reel IS NULL", "0", "s.reel") . ")";
505 } else {
506 $sql .= " (" . $sqlalertstock . " >= 0 AND (" . $sqlalertstock . " > SUM(" . $db->ifsql("s.reel IS NULL", "0", "s.reel") . ')';
507 }
508 $sql .= " - (" . $sqlCommandesCli . " - " . $sqlExpeditionsCli . ") + (" . $sqlCommandesFourn . " - " . $sqlReceptionFourn . ") + (" . $sqlProductionToProduce . " - " . $sqlProductionToConsume . ")))";
509 $sql .= ")";
510 if (getDolGlobalString('STOCK_ALLOW_ADD_LIMIT_STOCK_BY_WAREHOUSE') && $fk_entrepot > 0) {
511 $sql .= " AND (";
512 $sql .= " pse.desiredstock > 0)";
513 }
514
515 if ($salert == 'on') { // Option to see when stock is lower than alert
516 $sql .= ' AND (';
517 if ($includeproductswithoutdesiredqty == 'on') {
518 $sql .= "(" . $sqlalertstock . " >= 0 OR " . $sqlalertstock . " IS NULL) AND (" . $db->ifsql($sqlalertstock . " IS NULL", "0", $sqlalertstock) . " > SUM(" . $db->ifsql("s.reel IS NULL", "0", "s.reel") . ")";
519 } else {
520 $sql .= $sqlalertstock . " >= 0 AND (" . $sqlalertstock . " > SUM(" . $db->ifsql("s.reel IS NULL", "0", "s.reel") . ")";
521 }
522 $sql .= " - (" . $sqlCommandesCli . " - " . $sqlExpeditionsCli . ") + (" . $sqlCommandesFourn . " - " . $sqlReceptionFourn . ") + (" . $sqlProductionToProduce . " - " . $sqlProductionToConsume . "))";
523 $sql .= ")";
524 $alertchecked = 'checked';
525 }
526} else {
527 $sql .= ' HAVING (';
528 $sql .= "(" . $sqldesiredtock . " >= 0 AND (" . $sqldesiredtock . " > SUM(" . $db->ifsql("s.reel IS NULL", "0", "s.reel") . ")))";
529 $sql .= ' OR';
530 if ($includeproductswithoutdesiredqty == 'on') {
531 $sql .= " ((" . $sqlalertstock . " >= 0 OR " . $sqlalertstock . " IS NULL) AND (" . $db->ifsql($sqlalertstock . " IS NULL", "0", $sqlalertstock) . " > SUM(" . $db->ifsql("s.reel IS NULL", "0", "s.reel") . ')))';
532 } else {
533 $sql .= " (" . $sqlalertstock . " >= 0 AND (" . $sqlalertstock . " > SUM(" . $db->ifsql("s.reel IS NULL", "0", "s.reel") . ')))';
534 }
535 $sql .= ')';
536 if (getDolGlobalString('STOCK_ALLOW_ADD_LIMIT_STOCK_BY_WAREHOUSE') && $fk_entrepot > 0) {
537 $sql .= " AND (";
538 $sql .= " pse.desiredstock > 0)";
539 }
540
541 if ($salert == 'on') { // Option to see when stock is lower than alert
542 $sql .= " AND (";
543 if ($includeproductswithoutdesiredqty == 'on') {
544 $sql .= " (" . $sqlalertstock . " >= 0 OR " . $sqlalertstock . " IS NULL) AND (" . $db->ifsql($sqlalertstock . " IS NULL", "0", $sqlalertstock) . " > SUM(" . $db->ifsql("s.reel IS NULL", "0", "s.reel") . "))";
545 } else {
546 $sql .= " " . $sqlalertstock . " >= 0 AND (" . $sqlalertstock . " > SUM(" . $db->ifsql("s.reel IS NULL", "0", "s.reel") . '))';
547 }
548 $sql .= ')';
549 $alertchecked = 'checked';
550 }
551}
552
553$includeproductswithoutdesiredqtychecked = '';
554if ($includeproductswithoutdesiredqty == 'on') {
555 $includeproductswithoutdesiredqtychecked = 'checked';
556}
557
558$nbtotalofrecords = '';
559if (!getDolGlobalInt('MAIN_DISABLE_FULL_SCANLIST')) {
560 $result = $db->query($sql);
561 $nbtotalofrecords = $db->num_rows($result);
562 if (($page * $limit) > $nbtotalofrecords) {
563 $page = 0;
564 $offset = 0;
565 }
566}
567
568$sql .= $db->order($sortfield, $sortorder);
569$sql .= $db->plimit($limit + 1, $offset);
570
571//print $sql;
572$resql = $db->query($sql);
573if (empty($resql)) {
574 dol_print_error($db);
575 exit;
576}
577
578$num = $db->num_rows($resql);
579$i = 0;
580
581$helpurl = 'EN:Module_Stocks_En|FR:Module_Stock|';
582$helpurl .= 'ES:M&oacute;dulo_Stocks';
583
584llxHeader('', $title, $helpurl, '', 0, 0, '', '', '', 'mod-product page-stock_replenish');
585
586$head = array();
587
588$head[0][0] = DOL_URL_ROOT . '/product/stock/replenish.php';
589$head[0][1] = $title;
590$head[0][2] = 'replenish';
591
592$head[1][0] = DOL_URL_ROOT . '/product/stock/replenishorders.php';
593$head[1][1] = $langs->trans("ReplenishmentOrders");
594$head[1][2] = 'replenishorders';
595
596
597print load_fiche_titre($langs->trans('Replenishment'), '', 'stock');
598
599print dol_get_fiche_head($head, 'replenish', '', -1, '');
600
601print '<span class="opacitymedium">' . $langs->trans("ReplenishmentStatusDesc") . '</span>' . "\n";
602
603//$link = '<a title=' .$langs->trans("MenuNewWarehouse"). ' href="'.DOL_URL_ROOT.'/product/stock/card.php?action=create">'.$langs->trans("MenuNewWarehouse").'</a>';
604
605if (empty($fk_entrepot) && getDolGlobalString('STOCK_ALLOW_ADD_LIMIT_STOCK_BY_WAREHOUSE')) {
606 print '<span class="opacitymedium">'.$langs->trans("ReplenishmentStatusDescPerWarehouse").'</span>'."\n";
607}
608print '<br><br>';
609if ($usevirtualstock == 1) {
610 print $langs->trans("CurentSelectionMode") . ': ';
611 print '<span class="a-mesure">' . $langs->trans("UseVirtualStock") . '</span>';
612 print ' <a class="a-mesure-disabled" href="' . $_SERVER["PHP_SELF"] . '?mode=physical' . ($fk_supplier > 0 ? '&fk_supplier=' . $fk_supplier : '') . ($fk_entrepot > 0 ? '&fk_entrepot=' . $fk_entrepot : '') . '">' . $langs->trans("UsePhysicalStock") . '</a>';
613 print '<br>';
614}
615if ($usevirtualstock == 0) {
616 print $langs->trans("CurentSelectionMode") . ': ';
617 print '<a class="a-mesure-disabled" href="' . $_SERVER["PHP_SELF"] . '?mode=virtual' . ($fk_supplier > 0 ? '&fk_supplier=' . $fk_supplier : '') . ($fk_entrepot > 0 ? '&fk_entrepot=' . $fk_entrepot : '') . '">' . $langs->trans("UseVirtualStock") . '</a>';
618 print ' <span class="a-mesure">' . $langs->trans("UsePhysicalStock") . '</span>';
619 print '<br>';
620}
621print '<br>' . "\n";
622
623print '<form name="formFilterWarehouse" method="POST" action="' . $_SERVER["PHP_SELF"] . '">';
624print '<input type="hidden" name="token" value="' . newToken() . '">';
625print '<input type="hidden" name="action" value="filter">';
626print '<input type="hidden" name="search_ref" value="' . $search_ref . '">';
627print '<input type="hidden" name="search_label" value="' . $search_label . '">';
628print '<input type="hidden" name="salert" value="' . $salert . '">';
629print '<input type="hidden" name="includeproductswithoutdesiredqty" value="' . $includeproductswithoutdesiredqty . '">';
630print '<input type="hidden" name="draftorder" value="' . $draftorder . '">';
631print '<input type="hidden" name="mode" value="' . $mode . '">';
632if ($limit > 0 && $limit != $conf->liste_limit) {
633 print '<input type="hidden" name="limit" value="' . $limit . '">';
634}
635if (getDolGlobalString('STOCK_ALLOW_ADD_LIMIT_STOCK_BY_WAREHOUSE')) {
636 print '<div class="inline-block valignmiddle" style="padding-right: 20px;">';
637 print $langs->trans('Warehouse') . ' ' . $formproduct->selectWarehouses($fk_entrepot, 'fk_entrepot', '', 1);
638 print '</div>';
639}
640print '<div class="inline-block valignmiddle" style="padding-right: 20px;">';
641$filter = '(fournisseur:=:1)';
642print $langs->trans('Supplier') . ' ' . $form->select_company($fk_supplier, 'fk_supplier', $filter, 1);
643print '</div>';
644
645$parameters = array();
646$reshook = $hookmanager->executeHooks('printFieldPreListTitle', $parameters); // Note that $action and $object may have been modified by hook
647if (empty($reshook)) {
648 print $hookmanager->resPrint;
649}
650
651print '<div class="inline-block valignmiddle">';
652print '<input type="submit" class="button smallpaddingimp" name="valid" value="' . $langs->trans('ToFilter') . '">';
653print '</div>';
654
655print '</form>';
656
657print '<form action="' . $_SERVER["PHP_SELF"] . '" method="POST" name="formulaire">';
658print '<input type="hidden" name="token" value="' . newToken() . '">';
659print '<input type="hidden" name="fk_supplier" value="' . $fk_supplier . '">';
660print '<input type="hidden" name="fk_entrepot" value="' . $fk_entrepot . '">';
661print '<input type="hidden" name="sortfield" value="' . $sortfield . '">';
662print '<input type="hidden" name="sortorder" value="' . $sortorder . '">';
663print '<input type="hidden" name="type" value="' . $type . '">';
664print '<input type="hidden" name="linecount" value="' . $num . '">';
665print '<input type="hidden" name="action" value="order">';
666print '<input type="hidden" name="mode" value="' . $mode . '">';
667
668
669if ($search_ref || $search_label || $sall || $salert || $draftorder || GETPOST('search', 'alpha')) {
670 $filters = '&search_ref=' . urlencode($search_ref) . '&search_label=' . urlencode($search_label);
671 $filters .= '&sall=' . urlencode($sall);
672 $filters .= '&salert=' . urlencode($salert);
673 $filters .= '&draftorder=' . urlencode($draftorder);
674 $filters .= '&mode=' . urlencode($mode);
675 if ($fk_supplier > 0) {
676 $filters .= '&fk_supplier='.urlencode((string) ($fk_supplier));
677 }
678 if ($fk_entrepot > 0) {
679 $filters .= '&fk_entrepot='.urlencode((string) ($fk_entrepot));
680 }
681} else {
682 $filters = '&search_ref='.urlencode($search_ref).'&search_label='.urlencode($search_label);
683 $filters .= '&fourn_id='.urlencode((string) ($fourn_id));
684 $filters .= (isset($type) ? '&type='.urlencode((string) ($type)) : '');
685 $filters .= '&salert='.urlencode($salert);
686 $filters .= '&draftorder='.urlencode($draftorder);
687 $filters .= '&mode='.urlencode($mode);
688 if ($fk_supplier > 0) {
689 $filters .= '&fk_supplier='.urlencode((string) ($fk_supplier));
690 }
691 if ($fk_entrepot > 0) {
692 $filters .= '&fk_entrepot='.urlencode((string) ($fk_entrepot));
693 }
694}
695if ($limit > 0 && $limit != $conf->liste_limit) {
696 $filters .= '&limit=' . ((int) $limit);
697}
698if (!empty($includeproductswithoutdesiredqty)) {
699 $filters .= '&includeproductswithoutdesiredqty='.urlencode($includeproductswithoutdesiredqty);
700}
701if (!empty($salert)) {
702 $filters .= '&salert='.urlencode($salert);
703}
704
705$param = (isset($type) ? '&type='.urlencode((string) ($type)) : '');
706$param .= '&fourn_id='.urlencode((string) ($fourn_id)).'&search_label='.urlencode((string) ($search_label)).'&includeproductswithoutdesiredqty='.urlencode((string) ($includeproductswithoutdesiredqty)).'&salert='.urlencode((string) ($salert)).'&draftorder='.urlencode((string) ($draftorder));
707$param .= '&search_ref='.urlencode($search_ref);
708$param .= '&mode='.urlencode($mode);
709$param .= '&fk_supplier='.urlencode((string) ($fk_supplier));
710$param .= '&fk_entrepot='.urlencode((string) ($fk_entrepot));
711if (!empty($includeproductswithoutdesiredqty)) {
712 $param .= '&includeproductswithoutdesiredqty='.urlencode($includeproductswithoutdesiredqty);
713}
714if (!empty($salert)) {
715 $param .= '&salert='.urlencode($salert);
716}
717
718$stocklabel = $langs->trans('Stock');
719$stocklabelbis = $langs->trans('Stock');
720$stocktooltip = '';
721if ($usevirtualstock == 1) {
722 $stocklabel = $langs->trans('VirtualStock');
723 $stocktooltip = $langs->trans("VirtualStockDesc");
724}
725if ($usevirtualstock == 0) {
726 $stocklabel = $langs->trans('PhysicalStock');
727}
728if (getDolGlobalString('STOCK_ALLOW_ADD_LIMIT_STOCK_BY_WAREHOUSE') && $fk_entrepot > 0) {
729 $stocklabelbis = $stocklabel.' (Selected warehouse)';
730 $stocklabel .= ' ('.$langs->trans("AllWarehouses").')';
731}
732$texte = $langs->trans('Replenishment');
733
734print '<br>';
735
736
737if (getDolGlobalString('REPLENISH_ALLOW_VARIABLESIZELIST')) {
739 $texte,
740 $page,
741 'replenish.php',
742 $filters,
743 $sortfield,
744 $sortorder,
745 '',
746 $num,
747 $nbtotalofrecords,
748 '',
749 0,
750 '',
751 '',
752 $limit
753 );
754} else {
756 $texte,
757 $page,
758 'replenish.php',
759 $filters,
760 $sortfield,
761 $sortorder,
762 '',
763 $num,
764 $nbtotalofrecords,
765 ''
766 );
767}
768
769
770print '<div class="div-table-responsive-no-min">';
771print '<table class="liste centpercent">';
772
773// Fields title search
774print '<tr class="liste_titre_filter">';
775print '<td class="liste_titre">&nbsp;</td>';
776print '<td class="liste_titre"><input class="flat" type="text" name="search_ref" size="8" value="' . dol_escape_htmltag($search_ref) . '"></td>';
777print '<td class="liste_titre"><input class="flat" type="text" name="search_label" size="8" value="' . dol_escape_htmltag($search_label) . '"></td>';
778if (isModEnabled("service") && $type == 1) {
779 print '<td class="liste_titre">&nbsp;</td>';
780}
781print '<td class="liste_titre right">' . $form->textwithpicto($langs->trans('IncludeEmptyDesiredStock'), $langs->trans('IncludeProductWithUndefinedAlerts')) . '&nbsp;<input type="checkbox" id="includeproductswithoutdesiredqty" name="includeproductswithoutdesiredqty" ' . (!empty($includeproductswithoutdesiredqtychecked) ? $includeproductswithoutdesiredqtychecked : '') . '></td>';
782print '<td class="liste_titre right"></td>';
783print '<td class="liste_titre right">'.$langs->trans('AlertOnly').'&nbsp;<input type="checkbox" id="salert" name="salert" '.(!empty($alertchecked) ? $alertchecked : '').'></td>';
784if (getDolGlobalString('STOCK_ALLOW_ADD_LIMIT_STOCK_BY_WAREHOUSE') && $fk_entrepot > 0) {
785 print '<td class="liste_titre">&nbsp;</td>';
786}
787print '<td class="liste_titre right">';
788if (getDolGlobalString('STOCK_REPLENISH_ADD_CHECKBOX_INCLUDE_DRAFT_ORDER')) {
789 print $langs->trans('IncludeAlsoDraftOrders').'&nbsp;<input type="checkbox" id="draftorder" name="draftorder" '.(!empty($draftchecked) ? $draftchecked : '').'>';
790}
791print '</td>';
792print '<td class="liste_titre">&nbsp;</td>';
793// Fields from hook
794$parameters = array('param' => $param, 'sortfield' => $sortfield, 'sortorder' => $sortorder);
795$reshook = $hookmanager->executeHooks('printFieldListOption', $parameters); // Note that $action and $object may have been modified by hook
796print $hookmanager->resPrint;
797
798print '<td class="liste_titre maxwidthsearch right">';
799$searchpicto = $form->showFilterAndCheckAddButtons(0);
800print $searchpicto;
801print '</td>';
802print '</tr>';
803
804// Lines of title
805print '<tr class="liste_titre">';
806print_liste_field_titre('<input type="checkbox" onClick="toggle(this)" />', $_SERVER["PHP_SELF"], '');
807print_liste_field_titre('ProductRef', $_SERVER["PHP_SELF"], 'p.ref', $param, '', '', $sortfield, $sortorder);
808print_liste_field_titre('Label', $_SERVER["PHP_SELF"], 'p.label', $param, '', '', $sortfield, $sortorder);
809if (isModEnabled("service") && $type == 1) {
810 print_liste_field_titre('Duration', $_SERVER["PHP_SELF"], 'p.duration', $param, '', '', $sortfield, $sortorder, 'center ');
811}
812print_liste_field_titre('DesiredStock', $_SERVER["PHP_SELF"], 'p.desiredstock', $param, '', '', $sortfield, $sortorder, 'right ');
813print_liste_field_titre('StockLimitShort', $_SERVER["PHP_SELF"], 'p.seuil_stock_alerte', $param, '', '', $sortfield, $sortorder, 'right ');
814print_liste_field_titre($stocklabel, $_SERVER["PHP_SELF"], 'stock_physique', $param, '', '', $sortfield, $sortorder, 'right ', $stocktooltip);
815if (getDolGlobalString('STOCK_ALLOW_ADD_LIMIT_STOCK_BY_WAREHOUSE') && $fk_entrepot > 0) {
816 print_liste_field_titre($stocklabelbis, $_SERVER["PHP_SELF"], 'stock_real_warehouse', $param, '', '', $sortfield, $sortorder, 'right ');
817}
818print_liste_field_titre('Ordered', $_SERVER["PHP_SELF"], '', $param, '', '', $sortfield, $sortorder, 'right ');
819print_liste_field_titre('StockToBuy', $_SERVER["PHP_SELF"], '', $param, '', '', $sortfield, $sortorder, 'right ');
820print_liste_field_titre('SupplierRef', $_SERVER["PHP_SELF"], '', $param, '', '', $sortfield, $sortorder, 'right ');
821
822// Hook fields
823$parameters = array('param' => $param, 'sortfield' => $sortfield, 'sortorder' => $sortorder);
824$reshook = $hookmanager->executeHooks('printFieldListTitle', $parameters); // Note that $action and $object may have been modified by hook
825print $hookmanager->resPrint;
826
827print "</tr>\n";
828
829while ($i < ($limit ? min($num, $limit) : $num)) {
830 $objp = $db->fetch_object($resql);
831
832 if (getDolGlobalString('STOCK_SUPPORTS_SERVICES') || $objp->fk_product_type == 0) {
833 $result = $prod->fetch($objp->rowid);
834 if ($result < 0) {
835 dol_print_error($db);
836 exit;
837 }
838
839 $prod->load_stock('warehouseopen, warehouseinternal'.(!$usevirtualstock ? ', novirtual' : ''), $draftchecked);
840
841 // Multilangs
842 if (getDolGlobalInt('MAIN_MULTILANGS')) {
843 $sql = 'SELECT label,description';
844 $sql .= ' FROM ' . MAIN_DB_PREFIX . 'product_lang';
845 $sql .= ' WHERE fk_product = ' . ((int) $objp->rowid);
846 $sql .= " AND lang = '" . $db->escape($langs->getDefaultLang()) . "'";
847 $sql .= ' LIMIT 1';
848
849 $resqlm = $db->query($sql);
850 if ($resqlm) {
851 $objtp = $db->fetch_object($resqlm);
852 if (!empty($objtp->description)) {
853 $objp->description = $objtp->description;
854 }
855 if (!empty($objtp->label)) {
856 $objp->label = $objtp->label;
857 }
858 }
859 }
860
861 $stockwarehouse = 0;
862 if ($usevirtualstock) {
863 // If option to increase/decrease is not on an object validation, virtual stock may differs from physical stock.
864 $stock = $prod->stock_theorique;
865 //if conf active, stock virtual by warehouse is calculated
866 if (getDolGlobalString('STOCK_ALLOW_VIRTUAL_STOCK_PER_WAREHOUSE')) {
867 $stockwarehouse = $prod->stock_warehouse[$fk_entrepot]->virtual;
868 }
869 } else {
870 $stock = $prod->stock_reel;
871 if (getDolGlobalString('STOCK_ALLOW_ADD_LIMIT_STOCK_BY_WAREHOUSE') && $fk_entrepot > 0) {
872 $stockwarehouse = $prod->stock_warehouse[$fk_entrepot]->real;
873 }
874 }
875
876 // Force call prod->load_stats_xxx to choose status to count (otherwise it is loaded by load_stock function)
877 if (isset($draftchecked)) {
878 $result = $prod->load_stats_commande_fournisseur(0, '0,1,2,3,4');
879 } elseif (!$usevirtualstock) {
880 $result = $prod->load_stats_commande_fournisseur(0, '1,2,3,4');
881 }
882
883 if (!$usevirtualstock) {
884 $result = $prod->load_stats_reception(0, '4');
885 }
886
887 //print $prod->stats_commande_fournisseur['qty'].'<br>'."\n";
888 //print $prod->stats_reception['qty'];
889 $ordered = $prod->stats_commande_fournisseur['qty'] - $prod->stats_reception['qty'];
890
891 $desiredstock = $objp->desiredstock;
892 $alertstock = $objp->seuil_stock_alerte;
893 $desiredstockwarehouse = (!empty($objp->desiredstockpse) ? $objp->desiredstockpse : 0);
894 $alertstockwarehouse = (!empty($objp->seuil_stock_alertepse) ? $objp->seuil_stock_alertepse : 0);
895
896 $warning = '';
897 if ($alertstock && ($stock < $alertstock)) {
898 $warning = img_warning($langs->trans('StockTooLow')) . ' ';
899 }
900 $warningwarehouse = '';
901 if ($alertstockwarehouse && ($stockwarehouse < $alertstockwarehouse)) {
902 $warningwarehouse = img_warning($langs->trans('StockTooLow')) . ' ';
903 }
904
905 //depending on conf, use either physical stock or
906 //virtual stock to compute the stock to buy value
907
908 if (empty($usevirtualstock)) {
909 $stocktobuy = max(max($desiredstock, $alertstock) - $stock - $ordered, 0);
910 } else {
911 $stocktobuy = max(max($desiredstock, $alertstock) - $stock, 0); //ordered is already in $stock in virtual mode
912 }
913 if (empty($usevirtualstock)) {
914 $stocktobuywarehouse = max(max($desiredstockwarehouse, $alertstockwarehouse) - $stockwarehouse - $ordered, 0);
915 } else {
916 $stocktobuywarehouse = max(max($desiredstockwarehouse, $alertstockwarehouse) - $stockwarehouse, 0); //ordered is already in $stock in virtual mode
917 }
918
919 $picto = '';
920 if ($ordered > 0) {
921 $stockforcompare = ($usevirtualstock ? $stock : $stock + $ordered);
922 /*if ($stockforcompare >= $desiredstock)
923 {
924 $picto = img_picto('', 'help');
925 } else {
926 $picto = img_picto('', 'help');
927 }*/
928 } else {
929 $picto = img_picto($langs->trans("NoPendingReceptionOnSupplierOrder"), 'help');
930 }
931
932 print '<tr class="oddeven">';
933
934 // Select field
935 print '<td><input type="checkbox" class="check" name="choose' . $i . '"></td>';
936
937 print '<td class="nowrap">' . $prod->getNomUrl(1, 'stock') . '</td>';
938
939 print '<td class="tdoverflowmax200" title="' . dol_escape_htmltag($objp->label) . '">';
940 print dol_escape_htmltag($objp->label);
941 print '<input type="hidden" name="desc' . $i . '" value="' . dol_escape_htmltag($objp->description) . '">'; // TODO Remove this and make a fetch to get description when creating order instead of a GETPOST
942 print '</td>';
943
944 if (isModEnabled("service") && $type == 1) {
945 $regs = array();
946 if (preg_match('/([0-9]+)y/i', $objp->duration, $regs)) {
947 $duration = $regs[1] . ' ' . $langs->trans('DurationYear');
948 } elseif (preg_match('/([0-9]+)m/i', $objp->duration, $regs)) {
949 $duration = $regs[1] . ' ' . $langs->trans('DurationMonth');
950 } elseif (preg_match('/([0-9]+)d/i', $objp->duration, $regs)) {
951 $duration = $regs[1] . ' ' . $langs->trans('DurationDay');
952 } else {
953 $duration = $objp->duration;
954 }
955 print '<td class="center">' . $duration . '</td>';
956 }
957
958 // Desired stock
959 print '<td class="right">'.((getDolGlobalString('STOCK_ALLOW_ADD_LIMIT_STOCK_BY_WAREHOUSE') && $fk_entrepot > 0) > 0 ? $desiredstockwarehouse : $desiredstock).'</td>';
960
961 // Limit stock for alert
962 print '<td class="right">'.((getDolGlobalString('STOCK_ALLOW_ADD_LIMIT_STOCK_BY_WAREHOUSE') && $fk_entrepot > 0) > 0 ? $alertstockwarehouse : $alertstock).'</td>';
963
964 // Current stock (all warehouses)
965 print '<td class="right">' . $warning . $stock;
966 print '<!-- stock returned by main sql is ' . $objp->stock_physique . ' -->';
967 print '</td>';
968
969 // Current stock (warehouse selected only)
970 if (getDolGlobalString('STOCK_ALLOW_ADD_LIMIT_STOCK_BY_WAREHOUSE') && $fk_entrepot > 0) {
971 print '<td class="right">'.$warningwarehouse.$stockwarehouse.'</td>';
972 }
973
974 // Already ordered
975 print '<td class="right"><a href="replenishorders.php?search_product=' . $prod->id . '">' . $ordered . '</a> ' . $picto . '</td>';
976
977 // To order
978 $tobuy = ((getDolGlobalString('STOCK_ALLOW_ADD_LIMIT_STOCK_BY_WAREHOUSE') && $fk_entrepot > 0) > 0 ? $stocktobuywarehouse : $stocktobuy);
979 print '<td class="right"><input type="text" size="4" name="tobuy'.$i.'" value="'.$tobuy.'"></td>';
980
981 // Supplier
982 print '<td class="right">';
983 print $form->select_product_fourn_price($prod->id, 'fourn' . $i, $fk_supplier);
984 print '</td>';
985
986 // Fields from hook
987 $parameters = array('objp' => $objp, 'i' => $i, 'tobuy' => $tobuy);
988 $reshook = $hookmanager->executeHooks('printFieldListValue', $parameters); // Note that $action and $object may have been modified by hook
989 print $hookmanager->resPrint;
990
991 print '</tr>';
992 }
993 $i++;
994}
995
996if ($num == 0) {
997 $colspan = 9;
998 if (isModEnabled("service") && $type == 1) {
999 $colspan++;
1000 }
1001 if (getDolGlobalString('STOCK_ALLOW_ADD_LIMIT_STOCK_BY_WAREHOUSE') && $fk_entrepot > 0) {
1002 $colspan++;
1003 }
1004 print '<tr><td colspan="' . $colspan . '">';
1005 print '<span class="opacitymedium">';
1006 print $langs->trans("None");
1007 print '</span>';
1008 print '</td></tr>';
1009}
1010
1011$parameters = array('sql' => $sql);
1012$reshook = $hookmanager->executeHooks('printFieldListFooter', $parameters); // Note that $action and $object may have been modified by hook
1013print $hookmanager->resPrint;
1014
1015print '</table>';
1016print '</div>';
1017
1018$db->free($resql);
1019
1020print dol_get_fiche_end();
1021
1022
1023$value = $langs->trans("CreateOrders");
1024print '<div class="center"><input type="submit" class="button" name="valid" value="' . $value . '"></div>';
1025
1026
1027print '</form>';
1028
1029
1030// TODO Replace this with jquery
1031print '
1032<script type="text/javascript">
1033function toggle(source)
1034{
1035 checkboxes = document.getElementsByClassName("check");
1036 for (var i=0; i < checkboxes.length;i++) {
1037 if (!checkboxes[i].disabled) {
1038 checkboxes[i].checked = source.checked;
1039 }
1040 }
1041}
1042</script>';
1043
1044
1045llxFooter();
1046
1047$db->close();
if( $user->socid > 0) if(! $user->hasRight('accounting', 'chartofaccount')) $object
Definition card.php:58
if(!defined('NOREQUIRESOC')) if(!defined( 'NOREQUIRETRAN')) if(!defined('NOTOKENRENEWAL')) if(!defined( 'NOREQUIREMENU')) if(!defined('NOREQUIREHTML')) if(!defined( 'NOREQUIREAJAX')) llxHeader()
Empty header.
Definition wrapper.php:55
llxFooter()
Empty footer.
Definition wrapper.php:69
Class to manage predefined suppliers products.
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 predefined suppliers products.
Class to manage products or services.
load_fiche_titre($title, $morehtmlright='', $picto='generic', $pictoisfullpath=0, $id='', $morecssontable='', $morehtmlcenter='')
Load a title with picto.
img_warning($titlealt='default', $moreatt='', $morecss='pictowarning')
Show warning logo.
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2)
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)
Show tabs of a record.
dol_get_fiche_end($notab=0)
Return tab footer of a card.
natural_search($fields, $value, $mode=0, $nofirstand=0)
Generate natural SQL search string for a criteria (this criteria can be tested on one or several fiel...
dol_strlen($string, $stringencoding='UTF-8')
Make a strlen call.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
newToken()
Return the value of token currently saved into session with name 'newtoken'.
print_liste_field_titre($name, $file="", $field="", $begin="", $moreparam="", $moreattrib="", $sortfield="", $sortorder="", $prefix="", $tooltip="", $forcenowrapcolumntitle=0)
Show title line of an array.
print_barre_liste($title, $page, $file, $options='', $sortfield='', $sortorder='', $morehtmlcenter='', $num=-1, $totalnboflines='', $picto='generic', $pictoisfullpath=0, $morehtmlright='', $morecss='', $limit=-1, $hideselectlimit=0, $hidenavigation=0, $pagenavastextinput=0, $morehtmlrightbeforearrow='')
Print a title with navigation controls for pagination.
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='', $noduplicate=0)
Set event messages in dol_events session object.
dol_print_error($db=null, $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
getDolGlobalString($key, $default='')
Return dolibarr global constant string value.
getEntity($element, $shared=1, $currentobject=null)
Get list of entity id to use.
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...
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.