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 $line->tva_tx = $productsupplier->vatrate_supplier;
200 $line->subprice = $productsupplier->fourn_pu;
201 $line->total_ht = $productsupplier->fourn_pu * $qty;
202 $tva = $line->tva_tx / 100;
203 $line->total_tva = $line->total_ht * $tva;
204 $line->total_ttc = $line->total_ht + $line->total_tva;
205 $line->remise_percent = $productsupplier->remise_percent;
206 $line->ref_fourn = $productsupplier->ref_supplier;
207 $line->type = $productsupplier->type;
208 $line->fk_unit = $productsupplier->fk_unit;
209 $suppliers[$productsupplier->fourn_socid]['lines'][] = $line;
210 }
211 } elseif ($idprod == -1) {
212 $errorQty++;
213 } else {
214 $error = $db->lasterror();
215 dol_print_error($db);
216 }
217
218 unset($_POST['fourn' . $i]);
219 }
220 unset($_POST[$i]);
221 }
222
223 //we now know how many orders we need and what lines they have
224 $i = 0;
225 $fail = 0;
226 $orders = array();
227 $suppliersid = array_keys($suppliers); // array of ids of suppliers
228 foreach ($suppliers as $supplier) {
229 $order = new CommandeFournisseur($db);
230
231 // Check if an order for the supplier exists
232 $sql = "SELECT rowid FROM " . MAIN_DB_PREFIX . "commande_fournisseur";
233 $sql .= " WHERE fk_soc = " . ((int) $suppliersid[$i]);
234 $sql .= " AND source = " . ((int) $order::SOURCE_ID_REPLENISHMENT) . " AND fk_statut = " . ((int) $order::STATUS_DRAFT);
235 $sql .= " AND entity IN (" . getEntity('commande_fournisseur') . ")";
236 $sql .= " ORDER BY date_creation DESC";
237 $resql = $db->query($sql);
238 if ($resql && $db->num_rows($resql) > 0) {
239 $obj = $db->fetch_object($resql);
240
241 $order->fetch($obj->rowid);
242 $order->fetch_thirdparty();
243
244 foreach ($supplier['lines'] as $line) {
245 if (empty($line->remise_percent)) {
246 $line->remise_percent = $order->thirdparty->remise_supplier_percent;
247 }
248 $result = $order->addline(
249 $line->desc,
250 $line->subprice,
251 $line->qty,
252 $line->tva_tx,
253 $line->localtax1_tx,
254 $line->localtax2_tx,
255 $line->fk_product,
256 0,
257 $line->ref_fourn,
258 $line->remise_percent,
259 'HT',
260 0,
261 $line->type,
262 0,
263 false,
264 null,
265 null,
266 0,
267 $line->fk_unit
268 );
269 }
270 if ($result < 0) {
271 $fail++;
272 $msg = $langs->trans('OrderFail') . "&nbsp;:&nbsp;";
273 $msg .= $order->error;
274 setEventMessages($msg, null, 'errors');
275 } else {
276 $id = $result;
277 }
278 $i++;
279 } else {
280 $order->socid = $suppliersid[$i];
281 $order->fetch_thirdparty();
282
283 // Trick to know which orders have been generated using the replenishment feature
284 $order->source = $order::SOURCE_ID_REPLENISHMENT;
285
286 foreach ($supplier['lines'] as $line) {
287 if (empty($line->remise_percent)) {
288 $line->remise_percent = $order->thirdparty->remise_supplier_percent;
289 }
290 $order->lines[] = $line;
291 }
292 $order->cond_reglement_id = $order->thirdparty->cond_reglement_supplier_id;
293 $order->mode_reglement_id = $order->thirdparty->mode_reglement_supplier_id;
294
295 $id = $order->create($user);
296 if ($id < 0) {
297 $fail++;
298 $msg = $langs->trans('OrderFail') . "&nbsp;:&nbsp;";
299 $msg .= $order->error;
300 setEventMessages($msg, null, 'errors');
301 }
302 $i++;
303 }
304 }
305
306 if ($errorQty) {
307 setEventMessages($langs->trans('ErrorOrdersNotCreatedQtyTooLow'), null, 'warnings');
308 }
309
310 if (!$fail && $id) {
311 $db->commit();
312
313 setEventMessages($langs->trans('OrderCreated'), null, 'mesgs');
314 header('Location: replenishorders.php');
315 exit;
316 } else {
317 $db->rollback();
318 }
319 }
320 if ($box == 0) {
321 setEventMessages($langs->trans('SelectProductWithNotNullQty'), null, 'warnings');
322 }
323}
324
325
326/*
327 * View
328 */
329
330$form = new Form($db);
331$formproduct = new FormProduct($db);
332$prod = new Product($db);
333
334$title = $langs->trans('MissingStocks');
335
336if (getDolGlobalString('STOCK_ALLOW_ADD_LIMIT_STOCK_BY_WAREHOUSE') && $fk_entrepot > 0) {
337 $sqldesiredtock = $db->ifsql("pse.desiredstock IS NULL", "p.desiredstock", "pse.desiredstock");
338 $sqlalertstock = $db->ifsql("pse.seuil_stock_alerte IS NULL", "p.seuil_stock_alerte", "pse.seuil_stock_alerte");
339} else {
340 $sqldesiredtock = 'p.desiredstock';
341 $sqlalertstock = 'p.seuil_stock_alerte';
342}
343
344$sql = 'SELECT p.rowid, p.ref, p.label, p.description, p.price,';
345$sql .= ' p.price_ttc, p.price_base_type, p.fk_product_type,';
346$sql .= ' p.tms as datem, p.duration, p.tobuy,';
347$sql .= ' p.desiredstock, p.seuil_stock_alerte,';
348if (getDolGlobalString('STOCK_ALLOW_ADD_LIMIT_STOCK_BY_WAREHOUSE') && $fk_entrepot > 0) {
349 $sql .= ' pse.desiredstock as desiredstockpse, pse.seuil_stock_alerte as seuil_stock_alertepse,';
350}
351$sql .= " " . $sqldesiredtock . " as desiredstockcombined, " . $sqlalertstock . " as seuil_stock_alertecombined,";
352$sql .= ' s.fk_product,';
353$sql .= " SUM(".$db->ifsql("s.reel IS NULL", "0", "s.reel").') as stock_physique';
354if (getDolGlobalString('STOCK_ALLOW_ADD_LIMIT_STOCK_BY_WAREHOUSE') && $fk_entrepot > 0) {
355 $sql .= ", SUM(".$db->ifsql("s.reel IS NULL OR s.fk_entrepot <> ".((int) $fk_entrepot), "0", "s.reel").') as stock_real_warehouse';
356}
357
358// Add fields from hooks
359$parameters = array();
360$reshook = $hookmanager->executeHooks('printFieldListSelect', $parameters); // Note that $action and $object may have been modified by hook
361$sql .= $hookmanager->resPrint;
362
363$list_warehouse = (empty($listofqualifiedwarehousesid) ? '0' : $listofqualifiedwarehousesid);
364
365$sql .= ' FROM ' . MAIN_DB_PREFIX . 'product as p';
366$sql .= ' LEFT JOIN ' . MAIN_DB_PREFIX . 'product_stock as s ON p.rowid = s.fk_product';
367$sql .= ' AND s.fk_entrepot IN (' . $db->sanitize($list_warehouse) . ')';
368
369$list_warehouse_selected = ($fk_entrepot < 0 || empty($fk_entrepot)) ? $list_warehouse : $fk_entrepot;
370$sql .= ' AND s.fk_entrepot IN (' . $db->sanitize($list_warehouse_selected) . ')';
371
372
373//$sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'entrepot AS ent ON s.fk_entrepot = ent.rowid AND ent.entity IN('.getEntity('stock').')';
374if (getDolGlobalString('STOCK_ALLOW_ADD_LIMIT_STOCK_BY_WAREHOUSE') && $fk_entrepot > 0) {
375 $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'product_warehouse_properties AS pse ON (p.rowid = pse.fk_product AND pse.fk_entrepot = '.((int) $fk_entrepot).')';
376}
377// Add fields from hooks
378$parameters = array();
379$reshook = $hookmanager->executeHooks('printFieldListJoin', $parameters); // Note that $action and $object may have been modified by hook
380$sql .= $hookmanager->resPrint;
381
382$sql .= ' WHERE p.entity IN (' . getEntity('product') . ')';
383if ($sall) {
384 $sql .= natural_search(array('p.ref', 'p.label', 'p.description', 'p.note'), $sall);
385}
386// if the type is not 1, we show all products (type = 0,2,3)
387if (dol_strlen($type)) {
388 if ($type == 1) {
389 $sql .= ' AND p.fk_product_type = 1';
390 } else {
391 $sql .= ' AND p.fk_product_type <> 1';
392 }
393}
394if ($search_ref) {
395 $sql .= natural_search('p.ref', $search_ref);
396}
397if ($search_label) {
398 $sql .= natural_search('p.label', $search_label);
399}
400$sql .= ' AND p.tobuy = 1';
401if (isModEnabled('variants') && !getDolGlobalString('VARIANT_ALLOW_STOCK_MOVEMENT_ON_VARIANT_PARENT')) { // Add test to exclude products that has variants
402 $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').'))';
403}
404if ($fk_supplier > 0) {
405 $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') . '))';
406}
407// Add where from hooks
408$parameters = array();
409$reshook = $hookmanager->executeHooks('printFieldListWhere', $parameters); // Note that $action and $object may have been modified by hook
410$sql .= $hookmanager->resPrint;
411
412$sql .= ' GROUP BY p.rowid, p.ref, p.label, p.description, p.price';
413$sql .= ', p.price_ttc, p.price_base_type,p.fk_product_type, p.tms';
414$sql .= ', p.duration, p.tobuy';
415$sql .= ', p.desiredstock';
416$sql .= ', p.seuil_stock_alerte';
417if (getDolGlobalString('STOCK_ALLOW_ADD_LIMIT_STOCK_BY_WAREHOUSE') && $fk_entrepot > 0) {
418 $sql .= ', pse.desiredstock';
419 $sql .= ', pse.seuil_stock_alerte';
420}
421$sql .= ', s.fk_product';
422
423if ($usevirtualstock) {
424 if (isModEnabled('order')) {
425 $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
426 $sqlCommandesCli .= " FROM ".MAIN_DB_PREFIX."commandedet as cd1, ".MAIN_DB_PREFIX."commande as c1";
427 $sqlCommandesCli .= " WHERE c1.rowid = cd1.fk_commande AND c1.entity IN (".getEntity(getDolGlobalString('STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE') ? 'stock' : 'commande').")";
428 $sqlCommandesCli .= " AND cd1.fk_product = p.rowid";
429 $sqlCommandesCli .= " AND c1.fk_statut IN (1,2))";
430 } else {
431 $sqlCommandesCli = '0';
432 }
433
434 if (isModEnabled("shipping")) {
435 $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
436 $sqlExpeditionsCli .= " FROM ".MAIN_DB_PREFIX."expedition as e2,";
437 $sqlExpeditionsCli .= " ".MAIN_DB_PREFIX."expeditiondet as ed2,";
438 $sqlExpeditionsCli .= " ".MAIN_DB_PREFIX."commande as c2,";
439 $sqlExpeditionsCli .= " ".MAIN_DB_PREFIX."commandedet as cd2";
440 $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').")";
441 $sqlExpeditionsCli .= " AND cd2.fk_commande = c2.rowid";
442 $sqlExpeditionsCli .= " AND c2.fk_statut IN (1,2)";
443 $sqlExpeditionsCli .= " AND cd2.fk_product = p.rowid";
444 $sqlExpeditionsCli .= " AND e2.fk_statut IN (1,2))";
445 } else {
446 $sqlExpeditionsCli = '0';
447 }
448
449 if (isModEnabled("supplier_order")) {
450 $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
451 $sqlCommandesFourn .= " FROM " . MAIN_DB_PREFIX . "commande_fournisseurdet as cd3,";
452 $sqlCommandesFourn .= " " . MAIN_DB_PREFIX . "commande_fournisseur as c3";
453 $sqlCommandesFourn .= " WHERE c3.rowid = cd3.fk_commande";
454 $sqlCommandesFourn .= " AND c3.entity IN (".getEntity(getDolGlobalString('STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE') ? 'stock' : 'supplier_order').")";
455 $sqlCommandesFourn .= " AND cd3.fk_product = p.rowid";
456 $sqlCommandesFourn .= " AND c3.fk_statut IN (3,4))";
457
458 $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
459 $sqlReceptionFourn .= " FROM ".MAIN_DB_PREFIX."commande_fournisseur as cf4,";
460 $sqlReceptionFourn .= " ".MAIN_DB_PREFIX."receptiondet_batch as fd4";
461 $sqlReceptionFourn .= " WHERE fd4.fk_element = cf4.rowid AND cf4.entity IN (".getEntity(getDolGlobalString('STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE') ? 'stock' : 'supplier_order').")";
462 $sqlReceptionFourn .= " AND fd4.fk_product = p.rowid";
463 $sqlReceptionFourn .= " AND cf4.fk_statut IN (3,4))";
464 } else {
465 $sqlCommandesFourn = '0';
466 $sqlReceptionFourn = '0';
467 }
468
469 if (isModEnabled('mrp')) {
470 $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
471 $sqlProductionToConsume .= " FROM ".MAIN_DB_PREFIX."mrp_mo as mm5,";
472 $sqlProductionToConsume .= " ".MAIN_DB_PREFIX."mrp_production as mp5";
473 $sqlProductionToConsume .= " WHERE mm5.rowid = mp5.fk_mo AND mm5.entity IN (".getEntity(getDolGlobalString('STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE') ? 'stock' : 'mo').")";
474 $sqlProductionToConsume .= " AND mp5.fk_product = p.rowid";
475 $sqlProductionToConsume .= " AND mp5.role IN ('toconsume', 'consumed')";
476 $sqlProductionToConsume .= " AND mm5.status IN (1,2))";
477
478 $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
479 $sqlProductionToProduce .= " FROM ".MAIN_DB_PREFIX."mrp_mo as mm5,";
480 $sqlProductionToProduce .= " ".MAIN_DB_PREFIX."mrp_production as mp5";
481 $sqlProductionToProduce .= " WHERE mm5.rowid = mp5.fk_mo AND mm5.entity IN (".getEntity(getDolGlobalString('STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE') ? 'stock' : 'mo').")";
482 $sqlProductionToProduce .= " AND mp5.fk_product = p.rowid";
483 $sqlProductionToProduce .= " AND mp5.role IN ('toproduce', 'produced')";
484 $sqlProductionToProduce .= " AND mm5.status IN (1,2))";
485 } else {
486 $sqlProductionToConsume = '0';
487 $sqlProductionToProduce = '0';
488 }
489
490 $sql .= ' HAVING (';
491 $sql .= " (" . $sqldesiredtock . " >= 0 AND (" . $sqldesiredtock . " > SUM(" . $db->ifsql("s.reel IS NULL", "0", "s.reel") . ')';
492 $sql .= " - (" . $sqlCommandesCli . " - " . $sqlExpeditionsCli . ") + (" . $sqlCommandesFourn . " - " . $sqlReceptionFourn . ") + (" . $sqlProductionToProduce . " - " . $sqlProductionToConsume . ")))";
493 $sql .= ' OR';
494 if ($includeproductswithoutdesiredqty == 'on') {
495 $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") . ")";
496 } else {
497 $sql .= " (" . $sqlalertstock . " >= 0 AND (" . $sqlalertstock . " > SUM(" . $db->ifsql("s.reel IS NULL", "0", "s.reel") . ')';
498 }
499 $sql .= " - (" . $sqlCommandesCli . " - " . $sqlExpeditionsCli . ") + (" . $sqlCommandesFourn . " - " . $sqlReceptionFourn . ") + (" . $sqlProductionToProduce . " - " . $sqlProductionToConsume . ")))";
500 $sql .= ")";
501 if (getDolGlobalString('STOCK_ALLOW_ADD_LIMIT_STOCK_BY_WAREHOUSE') && $fk_entrepot > 0) {
502 $sql .= " AND (";
503 $sql .= " pse.desiredstock > 0)";
504 }
505
506 if ($salert == 'on') { // Option to see when stock is lower than alert
507 $sql .= ' AND (';
508 if ($includeproductswithoutdesiredqty == 'on') {
509 $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") . ")";
510 } else {
511 $sql .= $sqlalertstock . " >= 0 AND (" . $sqlalertstock . " > SUM(" . $db->ifsql("s.reel IS NULL", "0", "s.reel") . ")";
512 }
513 $sql .= " - (" . $sqlCommandesCli . " - " . $sqlExpeditionsCli . ") + (" . $sqlCommandesFourn . " - " . $sqlReceptionFourn . ") + (" . $sqlProductionToProduce . " - " . $sqlProductionToConsume . "))";
514 $sql .= ")";
515 $alertchecked = 'checked';
516 }
517} else {
518 $sql .= ' HAVING (';
519 $sql .= "(" . $sqldesiredtock . " >= 0 AND (" . $sqldesiredtock . " > SUM(" . $db->ifsql("s.reel IS NULL", "0", "s.reel") . ")))";
520 $sql .= ' OR';
521 if ($includeproductswithoutdesiredqty == 'on') {
522 $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") . ')))';
523 } else {
524 $sql .= " (" . $sqlalertstock . " >= 0 AND (" . $sqlalertstock . " > SUM(" . $db->ifsql("s.reel IS NULL", "0", "s.reel") . ')))';
525 }
526 $sql .= ')';
527 if (getDolGlobalString('STOCK_ALLOW_ADD_LIMIT_STOCK_BY_WAREHOUSE') && $fk_entrepot > 0) {
528 $sql .= " AND (";
529 $sql .= " pse.desiredstock > 0)";
530 }
531
532 if ($salert == 'on') { // Option to see when stock is lower than alert
533 $sql .= " AND (";
534 if ($includeproductswithoutdesiredqty == 'on') {
535 $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") . "))";
536 } else {
537 $sql .= " " . $sqlalertstock . " >= 0 AND (" . $sqlalertstock . " > SUM(" . $db->ifsql("s.reel IS NULL", "0", "s.reel") . '))';
538 }
539 $sql .= ')';
540 $alertchecked = 'checked';
541 }
542}
543
544$includeproductswithoutdesiredqtychecked = '';
545if ($includeproductswithoutdesiredqty == 'on') {
546 $includeproductswithoutdesiredqtychecked = 'checked';
547}
548
549$nbtotalofrecords = '';
550if (!getDolGlobalInt('MAIN_DISABLE_FULL_SCANLIST')) {
551 $result = $db->query($sql);
552 $nbtotalofrecords = $db->num_rows($result);
553 if (($page * $limit) > $nbtotalofrecords) {
554 $page = 0;
555 $offset = 0;
556 }
557}
558
559$sql .= $db->order($sortfield, $sortorder);
560$sql .= $db->plimit($limit + 1, $offset);
561
562//print $sql;
563$resql = $db->query($sql);
564if (empty($resql)) {
565 dol_print_error($db);
566 exit;
567}
568
569$num = $db->num_rows($resql);
570$i = 0;
571
572$helpurl = 'EN:Module_Stocks_En|FR:Module_Stock|';
573$helpurl .= 'ES:M&oacute;dulo_Stocks';
574
575llxHeader('', $title, $helpurl, '', 0, 0, '', '', '', 'mod-product page-stock_replenish');
576
577$head = array();
578
579$head[0][0] = DOL_URL_ROOT . '/product/stock/replenish.php';
580$head[0][1] = $title;
581$head[0][2] = 'replenish';
582
583$head[1][0] = DOL_URL_ROOT . '/product/stock/replenishorders.php';
584$head[1][1] = $langs->trans("ReplenishmentOrders");
585$head[1][2] = 'replenishorders';
586
587
588print load_fiche_titre($langs->trans('Replenishment'), '', 'stock');
589
590print dol_get_fiche_head($head, 'replenish', '', -1, '');
591
592print '<span class="opacitymedium">' . $langs->trans("ReplenishmentStatusDesc") . '</span>' . "\n";
593
594//$link = '<a title=' .$langs->trans("MenuNewWarehouse"). ' href="'.DOL_URL_ROOT.'/product/stock/card.php?action=create">'.$langs->trans("MenuNewWarehouse").'</a>';
595
596if (empty($fk_entrepot) && getDolGlobalString('STOCK_ALLOW_ADD_LIMIT_STOCK_BY_WAREHOUSE')) {
597 print '<span class="opacitymedium">'.$langs->trans("ReplenishmentStatusDescPerWarehouse").'</span>'."\n";
598}
599print '<br><br>';
600if ($usevirtualstock == 1) {
601 print $langs->trans("CurentSelectionMode") . ': ';
602 print '<span class="a-mesure">' . $langs->trans("UseVirtualStock") . '</span>';
603 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>';
604 print '<br>';
605}
606if ($usevirtualstock == 0) {
607 print $langs->trans("CurentSelectionMode") . ': ';
608 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>';
609 print ' <span class="a-mesure">' . $langs->trans("UsePhysicalStock") . '</span>';
610 print '<br>';
611}
612print '<br>' . "\n";
613
614print '<form name="formFilterWarehouse" method="POST" action="' . $_SERVER["PHP_SELF"] . '">';
615print '<input type="hidden" name="token" value="' . newToken() . '">';
616print '<input type="hidden" name="action" value="filter">';
617print '<input type="hidden" name="search_ref" value="' . $search_ref . '">';
618print '<input type="hidden" name="search_label" value="' . $search_label . '">';
619print '<input type="hidden" name="salert" value="' . $salert . '">';
620print '<input type="hidden" name="includeproductswithoutdesiredqty" value="' . $includeproductswithoutdesiredqty . '">';
621print '<input type="hidden" name="draftorder" value="' . $draftorder . '">';
622print '<input type="hidden" name="mode" value="' . $mode . '">';
623if ($limit > 0 && $limit != $conf->liste_limit) {
624 print '<input type="hidden" name="limit" value="' . $limit . '">';
625}
626if (getDolGlobalString('STOCK_ALLOW_ADD_LIMIT_STOCK_BY_WAREHOUSE')) {
627 print '<div class="inline-block valignmiddle" style="padding-right: 20px;">';
628 print $langs->trans('Warehouse') . ' ' . $formproduct->selectWarehouses($fk_entrepot, 'fk_entrepot', '', 1);
629 print '</div>';
630}
631print '<div class="inline-block valignmiddle" style="padding-right: 20px;">';
632$filter = '(fournisseur:=:1)';
633print $langs->trans('Supplier') . ' ' . $form->select_company($fk_supplier, 'fk_supplier', $filter, 1);
634print '</div>';
635
636$parameters = array();
637$reshook = $hookmanager->executeHooks('printFieldPreListTitle', $parameters); // Note that $action and $object may have been modified by hook
638if (empty($reshook)) {
639 print $hookmanager->resPrint;
640}
641
642print '<div class="inline-block valignmiddle">';
643print '<input type="submit" class="button smallpaddingimp" name="valid" value="' . $langs->trans('ToFilter') . '">';
644print '</div>';
645
646print '</form>';
647
648print '<form action="' . $_SERVER["PHP_SELF"] . '" method="POST" name="formulaire">';
649print '<input type="hidden" name="token" value="' . newToken() . '">';
650print '<input type="hidden" name="fk_supplier" value="' . $fk_supplier . '">';
651print '<input type="hidden" name="fk_entrepot" value="' . $fk_entrepot . '">';
652print '<input type="hidden" name="sortfield" value="' . $sortfield . '">';
653print '<input type="hidden" name="sortorder" value="' . $sortorder . '">';
654print '<input type="hidden" name="type" value="' . $type . '">';
655print '<input type="hidden" name="linecount" value="' . $num . '">';
656print '<input type="hidden" name="action" value="order">';
657print '<input type="hidden" name="mode" value="' . $mode . '">';
658
659
660if ($search_ref || $search_label || $sall || $salert || $draftorder || GETPOST('search', 'alpha')) {
661 $filters = '&search_ref=' . urlencode($search_ref) . '&search_label=' . urlencode($search_label);
662 $filters .= '&sall=' . urlencode($sall);
663 $filters .= '&salert=' . urlencode($salert);
664 $filters .= '&draftorder=' . urlencode($draftorder);
665 $filters .= '&mode=' . urlencode($mode);
666 if ($fk_supplier > 0) {
667 $filters .= '&fk_supplier='.urlencode((string) ($fk_supplier));
668 }
669 if ($fk_entrepot > 0) {
670 $filters .= '&fk_entrepot='.urlencode((string) ($fk_entrepot));
671 }
672} else {
673 $filters = '&search_ref='.urlencode($search_ref).'&search_label='.urlencode($search_label);
674 $filters .= '&fourn_id='.urlencode((string) ($fourn_id));
675 $filters .= (isset($type) ? '&type='.urlencode((string) ($type)) : '');
676 $filters .= '&salert='.urlencode($salert);
677 $filters .= '&draftorder='.urlencode($draftorder);
678 $filters .= '&mode='.urlencode($mode);
679 if ($fk_supplier > 0) {
680 $filters .= '&fk_supplier='.urlencode((string) ($fk_supplier));
681 }
682 if ($fk_entrepot > 0) {
683 $filters .= '&fk_entrepot='.urlencode((string) ($fk_entrepot));
684 }
685}
686if ($limit > 0 && $limit != $conf->liste_limit) {
687 $filters .= '&limit=' . ((int) $limit);
688}
689if (!empty($includeproductswithoutdesiredqty)) {
690 $filters .= '&includeproductswithoutdesiredqty='.urlencode($includeproductswithoutdesiredqty);
691}
692if (!empty($salert)) {
693 $filters .= '&salert='.urlencode($salert);
694}
695
696$param = (isset($type) ? '&type='.urlencode((string) ($type)) : '');
697$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));
698$param .= '&search_ref='.urlencode($search_ref);
699$param .= '&mode='.urlencode($mode);
700$param .= '&fk_supplier='.urlencode((string) ($fk_supplier));
701$param .= '&fk_entrepot='.urlencode((string) ($fk_entrepot));
702if (!empty($includeproductswithoutdesiredqty)) {
703 $param .= '&includeproductswithoutdesiredqty='.urlencode($includeproductswithoutdesiredqty);
704}
705if (!empty($salert)) {
706 $param .= '&salert='.urlencode($salert);
707}
708
709$stocklabel = $langs->trans('Stock');
710$stocklabelbis = $langs->trans('Stock');
711$stocktooltip = '';
712if ($usevirtualstock == 1) {
713 $stocklabel = $langs->trans('VirtualStock');
714 $stocktooltip = $langs->trans("VirtualStockDesc");
715}
716if ($usevirtualstock == 0) {
717 $stocklabel = $langs->trans('PhysicalStock');
718}
719if (getDolGlobalString('STOCK_ALLOW_ADD_LIMIT_STOCK_BY_WAREHOUSE') && $fk_entrepot > 0) {
720 $stocklabelbis = $stocklabel.' (Selected warehouse)';
721 $stocklabel .= ' ('.$langs->trans("AllWarehouses").')';
722}
723$texte = $langs->trans('Replenishment');
724
725print '<br>';
726
727
728if (getDolGlobalString('REPLENISH_ALLOW_VARIABLESIZELIST')) {
730 $texte,
731 $page,
732 'replenish.php',
733 $filters,
734 $sortfield,
735 $sortorder,
736 '',
737 $num,
738 $nbtotalofrecords,
739 '',
740 0,
741 '',
742 '',
743 $limit
744 );
745} else {
747 $texte,
748 $page,
749 'replenish.php',
750 $filters,
751 $sortfield,
752 $sortorder,
753 '',
754 $num,
755 $nbtotalofrecords,
756 ''
757 );
758}
759
760
761print '<div class="div-table-responsive-no-min">';
762print '<table class="liste centpercent">';
763
764// Fields title search
765print '<tr class="liste_titre_filter">';
766print '<td class="liste_titre">&nbsp;</td>';
767print '<td class="liste_titre"><input class="flat" type="text" name="search_ref" size="8" value="' . dol_escape_htmltag($search_ref) . '"></td>';
768print '<td class="liste_titre"><input class="flat" type="text" name="search_label" size="8" value="' . dol_escape_htmltag($search_label) . '"></td>';
769if (isModEnabled("service") && $type == 1) {
770 print '<td class="liste_titre">&nbsp;</td>';
771}
772print '<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>';
773print '<td class="liste_titre right"></td>';
774print '<td class="liste_titre right">'.$langs->trans('AlertOnly').'&nbsp;<input type="checkbox" id="salert" name="salert" '.(!empty($alertchecked) ? $alertchecked : '').'></td>';
775if (getDolGlobalString('STOCK_ALLOW_ADD_LIMIT_STOCK_BY_WAREHOUSE') && $fk_entrepot > 0) {
776 print '<td class="liste_titre">&nbsp;</td>';
777}
778print '<td class="liste_titre right">';
779if (getDolGlobalString('STOCK_REPLENISH_ADD_CHECKBOX_INCLUDE_DRAFT_ORDER')) {
780 print $langs->trans('IncludeAlsoDraftOrders').'&nbsp;<input type="checkbox" id="draftorder" name="draftorder" '.(!empty($draftchecked) ? $draftchecked : '').'>';
781}
782print '</td>';
783print '<td class="liste_titre">&nbsp;</td>';
784// Fields from hook
785$parameters = array('param' => $param, 'sortfield' => $sortfield, 'sortorder' => $sortorder);
786$reshook = $hookmanager->executeHooks('printFieldListOption', $parameters); // Note that $action and $object may have been modified by hook
787print $hookmanager->resPrint;
788
789print '<td class="liste_titre maxwidthsearch right">';
790$searchpicto = $form->showFilterAndCheckAddButtons(0);
791print $searchpicto;
792print '</td>';
793print '</tr>';
794
795// Lines of title
796print '<tr class="liste_titre">';
797print_liste_field_titre('<input type="checkbox" onClick="toggle(this)" />', $_SERVER["PHP_SELF"], '');
798print_liste_field_titre('ProductRef', $_SERVER["PHP_SELF"], 'p.ref', $param, '', '', $sortfield, $sortorder);
799print_liste_field_titre('Label', $_SERVER["PHP_SELF"], 'p.label', $param, '', '', $sortfield, $sortorder);
800if (isModEnabled("service") && $type == 1) {
801 print_liste_field_titre('Duration', $_SERVER["PHP_SELF"], 'p.duration', $param, '', '', $sortfield, $sortorder, 'center ');
802}
803print_liste_field_titre('DesiredStock', $_SERVER["PHP_SELF"], 'p.desiredstock', $param, '', '', $sortfield, $sortorder, 'right ');
804print_liste_field_titre('StockLimitShort', $_SERVER["PHP_SELF"], 'p.seuil_stock_alerte', $param, '', '', $sortfield, $sortorder, 'right ');
805print_liste_field_titre($stocklabel, $_SERVER["PHP_SELF"], 'stock_physique', $param, '', '', $sortfield, $sortorder, 'right ', $stocktooltip);
806if (getDolGlobalString('STOCK_ALLOW_ADD_LIMIT_STOCK_BY_WAREHOUSE') && $fk_entrepot > 0) {
807 print_liste_field_titre($stocklabelbis, $_SERVER["PHP_SELF"], 'stock_real_warehouse', $param, '', '', $sortfield, $sortorder, 'right ');
808}
809print_liste_field_titre('Ordered', $_SERVER["PHP_SELF"], '', $param, '', '', $sortfield, $sortorder, 'right ');
810print_liste_field_titre('StockToBuy', $_SERVER["PHP_SELF"], '', $param, '', '', $sortfield, $sortorder, 'right ');
811print_liste_field_titre('SupplierRef', $_SERVER["PHP_SELF"], '', $param, '', '', $sortfield, $sortorder, 'right ');
812
813// Hook fields
814$parameters = array('param' => $param, 'sortfield' => $sortfield, 'sortorder' => $sortorder);
815$reshook = $hookmanager->executeHooks('printFieldListTitle', $parameters); // Note that $action and $object may have been modified by hook
816print $hookmanager->resPrint;
817
818print "</tr>\n";
819
820while ($i < ($limit ? min($num, $limit) : $num)) {
821 $objp = $db->fetch_object($resql);
822
823 if (getDolGlobalString('STOCK_SUPPORTS_SERVICES') || $objp->fk_product_type == 0) {
824 $result = $prod->fetch($objp->rowid);
825 if ($result < 0) {
826 dol_print_error($db);
827 exit;
828 }
829
830 $prod->load_stock('warehouseopen, warehouseinternal'.(!$usevirtualstock ? ', novirtual' : ''), $draftchecked);
831
832 // Multilangs
833 if (getDolGlobalInt('MAIN_MULTILANGS')) {
834 $sql = 'SELECT label,description';
835 $sql .= ' FROM ' . MAIN_DB_PREFIX . 'product_lang';
836 $sql .= ' WHERE fk_product = ' . ((int) $objp->rowid);
837 $sql .= " AND lang = '" . $db->escape($langs->getDefaultLang()) . "'";
838 $sql .= ' LIMIT 1';
839
840 $resqlm = $db->query($sql);
841 if ($resqlm) {
842 $objtp = $db->fetch_object($resqlm);
843 if (!empty($objtp->description)) {
844 $objp->description = $objtp->description;
845 }
846 if (!empty($objtp->label)) {
847 $objp->label = $objtp->label;
848 }
849 }
850 }
851
852 $stockwarehouse = 0;
853 if ($usevirtualstock) {
854 // If option to increase/decrease is not on an object validation, virtual stock may differs from physical stock.
855 $stock = $prod->stock_theorique;
856 //if conf active, stock virtual by warehouse is calculated
857 if (getDolGlobalString('STOCK_ALLOW_VIRTUAL_STOCK_PER_WAREHOUSE')) {
858 $stockwarehouse = $prod->stock_warehouse[$fk_entrepot]->virtual;
859 }
860 } else {
861 $stock = $prod->stock_reel;
862 if (getDolGlobalString('STOCK_ALLOW_ADD_LIMIT_STOCK_BY_WAREHOUSE') && $fk_entrepot > 0) {
863 $stockwarehouse = $prod->stock_warehouse[$fk_entrepot]->real;
864 }
865 }
866
867 // Force call prod->load_stats_xxx to choose status to count (otherwise it is loaded by load_stock function)
868 if (isset($draftchecked)) {
869 $result = $prod->load_stats_commande_fournisseur(0, '0,1,2,3,4');
870 } elseif (!$usevirtualstock) {
871 $result = $prod->load_stats_commande_fournisseur(0, '1,2,3,4');
872 }
873
874 if (!$usevirtualstock) {
875 $result = $prod->load_stats_reception(0, '4');
876 }
877
878 //print $prod->stats_commande_fournisseur['qty'].'<br>'."\n";
879 //print $prod->stats_reception['qty'];
880 $ordered = $prod->stats_commande_fournisseur['qty'] - $prod->stats_reception['qty'];
881
882 $desiredstock = $objp->desiredstock;
883 $alertstock = $objp->seuil_stock_alerte;
884 $desiredstockwarehouse = (!empty($objp->desiredstockpse) ? $objp->desiredstockpse : 0);
885 $alertstockwarehouse = (!empty($objp->seuil_stock_alertepse) ? $objp->seuil_stock_alertepse : 0);
886
887 $warning = '';
888 if ($alertstock && ($stock < $alertstock)) {
889 $warning = img_warning($langs->trans('StockTooLow')) . ' ';
890 }
891 $warningwarehouse = '';
892 if ($alertstockwarehouse && ($stockwarehouse < $alertstockwarehouse)) {
893 $warningwarehouse = img_warning($langs->trans('StockTooLow')) . ' ';
894 }
895
896 //depending on conf, use either physical stock or
897 //virtual stock to compute the stock to buy value
898
899 if (empty($usevirtualstock)) {
900 $stocktobuy = max(max($desiredstock, $alertstock) - $stock - $ordered, 0);
901 } else {
902 $stocktobuy = max(max($desiredstock, $alertstock) - $stock, 0); //ordered is already in $stock in virtual mode
903 }
904 if (empty($usevirtualstock)) {
905 $stocktobuywarehouse = max(max($desiredstockwarehouse, $alertstockwarehouse) - $stockwarehouse - $ordered, 0);
906 } else {
907 $stocktobuywarehouse = max(max($desiredstockwarehouse, $alertstockwarehouse) - $stockwarehouse, 0); //ordered is already in $stock in virtual mode
908 }
909
910 $picto = '';
911 if ($ordered > 0) {
912 $stockforcompare = ($usevirtualstock ? $stock : $stock + $ordered);
913 /*if ($stockforcompare >= $desiredstock)
914 {
915 $picto = img_picto('', 'help');
916 } else {
917 $picto = img_picto('', 'help');
918 }*/
919 } else {
920 $picto = img_picto($langs->trans("NoPendingReceptionOnSupplierOrder"), 'help');
921 }
922
923 print '<tr class="oddeven">';
924
925 // Select field
926 print '<td><input type="checkbox" class="check" name="choose' . $i . '"></td>';
927
928 print '<td class="nowrap">' . $prod->getNomUrl(1, 'stock') . '</td>';
929
930 print '<td class="tdoverflowmax200" title="' . dol_escape_htmltag($objp->label) . '">';
931 print dol_escape_htmltag($objp->label);
932 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
933 print '</td>';
934
935 if (isModEnabled("service") && $type == 1) {
936 $regs = array();
937 if (preg_match('/([0-9]+)y/i', $objp->duration, $regs)) {
938 $duration = $regs[1] . ' ' . $langs->trans('DurationYear');
939 } elseif (preg_match('/([0-9]+)m/i', $objp->duration, $regs)) {
940 $duration = $regs[1] . ' ' . $langs->trans('DurationMonth');
941 } elseif (preg_match('/([0-9]+)d/i', $objp->duration, $regs)) {
942 $duration = $regs[1] . ' ' . $langs->trans('DurationDay');
943 } else {
944 $duration = $objp->duration;
945 }
946 print '<td class="center">' . $duration . '</td>';
947 }
948
949 // Desired stock
950 print '<td class="right">'.((getDolGlobalString('STOCK_ALLOW_ADD_LIMIT_STOCK_BY_WAREHOUSE') && $fk_entrepot > 0) > 0 ? $desiredstockwarehouse : $desiredstock).'</td>';
951
952 // Limit stock for alert
953 print '<td class="right">'.((getDolGlobalString('STOCK_ALLOW_ADD_LIMIT_STOCK_BY_WAREHOUSE') && $fk_entrepot > 0) > 0 ? $alertstockwarehouse : $alertstock).'</td>';
954
955 // Current stock (all warehouses)
956 print '<td class="right">' . $warning . $stock;
957 print '<!-- stock returned by main sql is ' . $objp->stock_physique . ' -->';
958 print '</td>';
959
960 // Current stock (warehouse selected only)
961 if (getDolGlobalString('STOCK_ALLOW_ADD_LIMIT_STOCK_BY_WAREHOUSE') && $fk_entrepot > 0) {
962 print '<td class="right">'.$warningwarehouse.$stockwarehouse.'</td>';
963 }
964
965 // Already ordered
966 print '<td class="right"><a href="replenishorders.php?search_product=' . $prod->id . '">' . $ordered . '</a> ' . $picto . '</td>';
967
968 // To order
969 $tobuy = ((getDolGlobalString('STOCK_ALLOW_ADD_LIMIT_STOCK_BY_WAREHOUSE') && $fk_entrepot > 0) > 0 ? $stocktobuywarehouse : $stocktobuy);
970 print '<td class="right"><input type="text" size="4" name="tobuy'.$i.'" value="'.$tobuy.'"></td>';
971
972 // Supplier
973 print '<td class="right">';
974 print $form->select_product_fourn_price($prod->id, 'fourn' . $i, $fk_supplier);
975 print '</td>';
976
977 // Fields from hook
978 $parameters = array('objp' => $objp, 'i' => $i, 'tobuy' => $tobuy);
979 $reshook = $hookmanager->executeHooks('printFieldListValue', $parameters); // Note that $action and $object may have been modified by hook
980 print $hookmanager->resPrint;
981
982 print '</tr>';
983 }
984 $i++;
985}
986
987if ($num == 0) {
988 $colspan = 9;
989 if (isModEnabled("service") && $type == 1) {
990 $colspan++;
991 }
992 if (getDolGlobalString('STOCK_ALLOW_ADD_LIMIT_STOCK_BY_WAREHOUSE') && $fk_entrepot > 0) {
993 $colspan++;
994 }
995 print '<tr><td colspan="' . $colspan . '">';
996 print '<span class="opacitymedium">';
997 print $langs->trans("None");
998 print '</span>';
999 print '</td></tr>';
1000}
1001
1002$parameters = array('sql' => $sql);
1003$reshook = $hookmanager->executeHooks('printFieldListFooter', $parameters); // Note that $action and $object may have been modified by hook
1004print $hookmanager->resPrint;
1005
1006print '</table>';
1007print '</div>';
1008
1009$db->free($resql);
1010
1011print dol_get_fiche_end();
1012
1013
1014$value = $langs->trans("CreateOrders");
1015print '<div class="center"><input type="submit" class="button" name="valid" value="' . $value . '"></div>';
1016
1017
1018print '</form>';
1019
1020
1021// TODO Replace this with jquery
1022print '
1023<script type="text/javascript">
1024function toggle(source)
1025{
1026 checkboxes = document.getElementsByClassName("check");
1027 for (var i=0; i < checkboxes.length;i++) {
1028 if (!checkboxes[i].disabled) {
1029 checkboxes[i].checked = source.checked;
1030 }
1031 }
1032}
1033</script>';
1034
1035
1036llxFooter();
1037
1038$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.