dolibarr 19.0.3
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 = GETPOST('type', 'int');
59$tobuy = GETPOST('tobuy', 'int');
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 = GETPOST('fourn_id', 'int');
67$fk_supplier = GETPOST('fk_supplier', 'int');
68$fk_entrepot = GETPOST('fk_entrepot', 'int');
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') ? (GETPOST('pageplusone') - 1) : GETPOST("page", 'int');
93if (empty($page) || $page == -1) {
94 $page = 0;
95} // If $page is not defined, or '' or -1
96$limit = GETPOST('limit', 'int') ? GETPOST('limit', 'int') : $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 = GETPOST('linecount', 'int');
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, 'alpha') === 'on' && GETPOST('fourn' . $i, 'int') > 0) {
168 //one line
169 $box = $i;
170 $supplierpriceid = GETPOST('fourn' . $i, 'int');
171 //get all the parameters needed to create a line
172 $qty = GETPOST('tobuy' . $i, 'int');
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 $tva = $line->tva_tx / 100;
201
202 // If we use multicurrency
203 if (isModEnabled('multicurrency') && !empty($productsupplier->fourn_multicurrency_code) && $productsupplier->fourn_multicurrency_code != $conf->currency) {
204 $line->multicurrency_code = $productsupplier->fourn_multicurrency_code;
205 $line->fk_multicurrency = $productsupplier->fourn_multicurrency_id;
206 $line->multicurrency_subprice = $productsupplier->fourn_multicurrency_unitprice;
207 $line->multicurrency_total_ht = $line->multicurrency_subprice * $qty;
208 $line->multicurrency_total_tva = $line->multicurrency_total_ht * $tva;
209 $line->multicurrency_total_ttc = $line->multicurrency_total_ht + $line->multicurrency_total_tva;
210 }
211 $line->subprice = $productsupplier->fourn_pu;
212 $line->total_ht = $productsupplier->fourn_pu * $qty;
213 $line->total_tva = $line->total_ht * $tva;
214 $line->total_ttc = $line->total_ht + $line->total_tva;
215 $line->remise_percent = $productsupplier->remise_percent;
216 $line->ref_fourn = $productsupplier->ref_supplier;
217 $line->type = $productsupplier->type;
218 $line->fk_unit = $productsupplier->fk_unit;
219 $suppliers[$productsupplier->fourn_socid]['lines'][] = $line;
220 }
221 } elseif ($idprod == -1) {
222 $errorQty++;
223 } else {
224 $error = $db->lasterror();
225 dol_print_error($db);
226 }
227
228 unset($_POST['fourn' . $i]);
229 }
230 unset($_POST[$i]);
231 }
232
233 //we now know how many orders we need and what lines they have
234 $i = 0;
235 $fail = 0;
236 $orders = array();
237 $suppliersid = array_keys($suppliers);
238 foreach ($suppliers as $supplier) {
239 $order = new CommandeFournisseur($db);
240
241 // Check if an order for the supplier exists
242 $sql = "SELECT rowid FROM " . MAIN_DB_PREFIX . "commande_fournisseur";
243 $sql .= " WHERE fk_soc = " . ((int) $suppliersid[$i]);
244 $sql .= " AND source = " . ((int) $order::SOURCE_ID_REPLENISHMENT) . " AND fk_statut = " . ((int) $order::STATUS_DRAFT);
245 $sql .= " AND entity IN (" . getEntity('commande_fournisseur') . ")";
246 $sql .= " ORDER BY date_creation DESC";
247 $resql = $db->query($sql);
248 if ($resql && $db->num_rows($resql) > 0) {
249 $obj = $db->fetch_object($resql);
250
251 $order->fetch($obj->rowid);
252 $order->fetch_thirdparty();
253
254 foreach ($supplier['lines'] as $line) {
255 if (empty($line->remise_percent)) {
256 $line->remise_percent = $order->thirdparty->remise_supplier_percent;
257 }
258 $result = $order->addline(
259 $line->desc,
260 $line->subprice,
261 $line->qty,
262 $line->tva_tx,
263 $line->localtax1_tx,
264 $line->localtax2_tx,
265 $line->fk_product,
266 0,
267 $line->ref_fourn,
268 $line->remise_percent,
269 'HT',
270 0,
271 $line->type,
272 0,
273 false,
274 null,
275 null,
276 0,
277 $line->fk_unit,
278 $line->multicurrency_subprice ?? 0
279 );
280 }
281 if ($result < 0) {
282 $fail++;
283 $msg = $langs->trans('OrderFail') . "&nbsp;:&nbsp;";
284 $msg .= $order->error;
285 setEventMessages($msg, null, 'errors');
286 } else {
287 $id = $result;
288 }
289 $i++;
290 } else {
291 $order->socid = $suppliersid[$i];
292 $order->fetch_thirdparty();
293 $order->multicurrency_code = $order->thirdparty->multicurrency_code;
294
295 // Trick to know which orders have been generated using the replenishment feature
296 $order->source = $order::SOURCE_ID_REPLENISHMENT;
297
298 foreach ($supplier['lines'] as $line) {
299 if (empty($line->remise_percent)) {
300 $line->remise_percent = $order->thirdparty->remise_supplier_percent;
301 }
302 $order->lines[] = $line;
303 }
304 $order->cond_reglement_id = $order->thirdparty->cond_reglement_supplier_id;
305 $order->mode_reglement_id = $order->thirdparty->mode_reglement_supplier_id;
306
307 $id = $order->create($user);
308 if ($id < 0) {
309 $fail++;
310 $msg = $langs->trans('OrderFail') . "&nbsp;:&nbsp;";
311 $msg .= $order->error;
312 setEventMessages($msg, null, 'errors');
313 }
314 $i++;
315 }
316 }
317
318 if ($errorQty) {
319 setEventMessages($langs->trans('ErrorOrdersNotCreatedQtyTooLow'), null, 'warnings');
320 }
321
322 if (!$fail && $id) {
323 $db->commit();
324
325 setEventMessages($langs->trans('OrderCreated'), null, 'mesgs');
326 header('Location: replenishorders.php');
327 exit;
328 } else {
329 $db->rollback();
330 }
331 }
332 if ($box == 0) {
333 setEventMessages($langs->trans('SelectProductWithNotNullQty'), null, 'warnings');
334 }
335}
336
337
338/*
339 * View
340 */
341
342$form = new Form($db);
343$formproduct = new FormProduct($db);
344$prod = new Product($db);
345
346$title = $langs->trans('MissingStocks');
347
348if (getDolGlobalString('STOCK_ALLOW_ADD_LIMIT_STOCK_BY_WAREHOUSE') && $fk_entrepot > 0) {
349 $sqldesiredtock = $db->ifsql("pse.desiredstock IS NULL", "p.desiredstock", "pse.desiredstock");
350 $sqlalertstock = $db->ifsql("pse.seuil_stock_alerte IS NULL", "p.seuil_stock_alerte", "pse.seuil_stock_alerte");
351} else {
352 $sqldesiredtock = 'p.desiredstock';
353 $sqlalertstock = 'p.seuil_stock_alerte';
354}
355
356$sql = 'SELECT p.rowid, p.ref, p.label, p.description, p.price,';
357$sql .= ' p.price_ttc, p.price_base_type, p.fk_product_type,';
358$sql .= ' p.tms as datem, p.duration, p.tobuy,';
359$sql .= ' p.desiredstock, p.seuil_stock_alerte,';
360if (getDolGlobalString('STOCK_ALLOW_ADD_LIMIT_STOCK_BY_WAREHOUSE') && $fk_entrepot > 0) {
361 $sql .= ' pse.desiredstock as desiredstockpse, pse.seuil_stock_alerte as seuil_stock_alertepse,';
362}
363$sql .= " " . $sqldesiredtock . " as desiredstockcombined, " . $sqlalertstock . " as seuil_stock_alertecombined,";
364$sql .= ' s.fk_product,';
365$sql .= " SUM(".$db->ifsql("s.reel IS NULL", "0", "s.reel").') as stock_physique';
366if (getDolGlobalString('STOCK_ALLOW_ADD_LIMIT_STOCK_BY_WAREHOUSE') && $fk_entrepot > 0) {
367 $sql .= ", SUM(".$db->ifsql("s.reel IS NULL OR s.fk_entrepot <> ".((int) $fk_entrepot), "0", "s.reel").') as stock_real_warehouse';
368}
369
370// Add fields from hooks
371$parameters = array();
372$reshook = $hookmanager->executeHooks('printFieldListSelect', $parameters); // Note that $action and $object may have been modified by hook
373$sql .= $hookmanager->resPrint;
374
375$list_warehouse = (empty($listofqualifiedwarehousesid) ? '0' : $listofqualifiedwarehousesid);
376
377$sql .= ' FROM ' . MAIN_DB_PREFIX . 'product as p';
378$sql .= ' LEFT JOIN ' . MAIN_DB_PREFIX . 'product_stock as s ON p.rowid = s.fk_product';
379$sql .= ' AND s.fk_entrepot IN (' . $db->sanitize($list_warehouse) . ')';
380
381$list_warehouse_selected = ($fk_entrepot < 0 || empty($fk_entrepot)) ? $list_warehouse : $fk_entrepot;
382$sql .= ' AND s.fk_entrepot IN (' . $db->sanitize($list_warehouse_selected) . ')';
383
384
385//$sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'entrepot AS ent ON s.fk_entrepot = ent.rowid AND ent.entity IN('.getEntity('stock').')';
386if (getDolGlobalString('STOCK_ALLOW_ADD_LIMIT_STOCK_BY_WAREHOUSE') && $fk_entrepot > 0) {
387 $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'product_warehouse_properties AS pse ON (p.rowid = pse.fk_product AND pse.fk_entrepot = '.((int) $fk_entrepot).')';
388}
389// Add fields from hooks
390$parameters = array();
391$reshook = $hookmanager->executeHooks('printFieldListJoin', $parameters); // Note that $action and $object may have been modified by hook
392$sql .= $hookmanager->resPrint;
393
394$sql .= ' WHERE p.entity IN (' . getEntity('product') . ')';
395if ($sall) {
396 $sql .= natural_search(array('p.ref', 'p.label', 'p.description', 'p.note'), $sall);
397}
398// if the type is not 1, we show all products (type = 0,2,3)
399if (dol_strlen($type)) {
400 if ($type == 1) {
401 $sql .= ' AND p.fk_product_type = 1';
402 } else {
403 $sql .= ' AND p.fk_product_type <> 1';
404 }
405}
406if ($search_ref) {
407 $sql .= natural_search('p.ref', $search_ref);
408}
409if ($search_label) {
410 $sql .= natural_search('p.label', $search_label);
411}
412$sql .= ' AND p.tobuy = 1';
413if (isModEnabled('variants') && !getDolGlobalString('VARIANT_ALLOW_STOCK_MOVEMENT_ON_VARIANT_PARENT')) { // Add test to exclude products that has variants
414 $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').'))';
415}
416if ($fk_supplier > 0) {
417 $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') . '))';
418}
419// Add where from hooks
420$parameters = array();
421$reshook = $hookmanager->executeHooks('printFieldListWhere', $parameters); // Note that $action and $object may have been modified by hook
422$sql .= $hookmanager->resPrint;
423
424$sql .= ' GROUP BY p.rowid, p.ref, p.label, p.description, p.price';
425$sql .= ', p.price_ttc, p.price_base_type,p.fk_product_type, p.tms';
426$sql .= ', p.duration, p.tobuy';
427$sql .= ', p.desiredstock';
428$sql .= ', p.seuil_stock_alerte';
429if (getDolGlobalString('STOCK_ALLOW_ADD_LIMIT_STOCK_BY_WAREHOUSE') && $fk_entrepot > 0) {
430 $sql .= ', pse.desiredstock';
431 $sql .= ', pse.seuil_stock_alerte';
432}
433$sql .= ', s.fk_product';
434
435if ($usevirtualstock) {
436 if (isModEnabled('commande')) {
437 $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
438 $sqlCommandesCli .= " FROM ".MAIN_DB_PREFIX."commandedet as cd1, ".MAIN_DB_PREFIX."commande as c1";
439 $sqlCommandesCli .= " WHERE c1.rowid = cd1.fk_commande AND c1.entity IN (".getEntity(getDolGlobalString('STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE') ? 'stock' : 'commande').")";
440 $sqlCommandesCli .= " AND cd1.fk_product = p.rowid";
441 $sqlCommandesCli .= " AND c1.fk_statut IN (1,2))";
442 } else {
443 $sqlCommandesCli = '0';
444 }
445
446 if (isModEnabled("expedition")) {
447 $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
448 $sqlExpeditionsCli .= " FROM ".MAIN_DB_PREFIX."expedition as e2,";
449 $sqlExpeditionsCli .= " ".MAIN_DB_PREFIX."expeditiondet as ed2,";
450 $sqlExpeditionsCli .= " ".MAIN_DB_PREFIX."commande as c2,";
451 $sqlExpeditionsCli .= " ".MAIN_DB_PREFIX."commandedet as cd2";
452 $sqlExpeditionsCli .= " WHERE ed2.fk_expedition = e2.rowid AND cd2.rowid = ed2.fk_origin_line AND e2.entity IN (".getEntity(getDolGlobalString('STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE') ? 'stock' : 'expedition').")";
453 $sqlExpeditionsCli .= " AND cd2.fk_commande = c2.rowid";
454 $sqlExpeditionsCli .= " AND c2.fk_statut IN (1,2)";
455 $sqlExpeditionsCli .= " AND cd2.fk_product = p.rowid";
456 $sqlExpeditionsCli .= " AND e2.fk_statut IN (1,2))";
457 } else {
458 $sqlExpeditionsCli = '0';
459 }
460
461 if (isModEnabled("supplier_order")) {
462 $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
463 $sqlCommandesFourn .= " FROM " . MAIN_DB_PREFIX . "commande_fournisseurdet as cd3,";
464 $sqlCommandesFourn .= " " . MAIN_DB_PREFIX . "commande_fournisseur as c3";
465 $sqlCommandesFourn .= " WHERE c3.rowid = cd3.fk_commande";
466 $sqlCommandesFourn .= " AND c3.entity IN (".getEntity(getDolGlobalString('STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE') ? 'stock' : 'supplier_order').")";
467 $sqlCommandesFourn .= " AND cd3.fk_product = p.rowid";
468 $sqlCommandesFourn .= " AND c3.fk_statut IN (3,4))";
469
470 $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
471 $sqlReceptionFourn .= " FROM ".MAIN_DB_PREFIX."commande_fournisseur as cf4,";
472 $sqlReceptionFourn .= " ".MAIN_DB_PREFIX."commande_fournisseur_dispatch as fd4";
473 $sqlReceptionFourn .= " WHERE fd4.fk_commande = cf4.rowid AND cf4.entity IN (".getEntity(getDolGlobalString('STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE') ? 'stock' : 'supplier_order').")";
474 $sqlReceptionFourn .= " AND fd4.fk_product = p.rowid";
475 $sqlReceptionFourn .= " AND cf4.fk_statut IN (3,4))";
476 } else {
477 $sqlCommandesFourn = '0';
478 $sqlReceptionFourn = '0';
479 }
480
481 if (isModEnabled('mrp')) {
482 $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
483 $sqlProductionToConsume .= " FROM ".MAIN_DB_PREFIX."mrp_mo as mm5,";
484 $sqlProductionToConsume .= " ".MAIN_DB_PREFIX."mrp_production as mp5";
485 $sqlProductionToConsume .= " WHERE mm5.rowid = mp5.fk_mo AND mm5.entity IN (".getEntity(getDolGlobalString('STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE') ? 'stock' : 'mo').")";
486 $sqlProductionToConsume .= " AND mp5.fk_product = p.rowid";
487 $sqlProductionToConsume .= " AND mp5.role IN ('toconsume', 'consumed')";
488 $sqlProductionToConsume .= " AND mm5.status IN (1,2))";
489
490 $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
491 $sqlProductionToProduce .= " FROM ".MAIN_DB_PREFIX."mrp_mo as mm5,";
492 $sqlProductionToProduce .= " ".MAIN_DB_PREFIX."mrp_production as mp5";
493 $sqlProductionToProduce .= " WHERE mm5.rowid = mp5.fk_mo AND mm5.entity IN (".getEntity(getDolGlobalString('STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE') ? 'stock' : 'mo').")";
494 $sqlProductionToProduce .= " AND mp5.fk_product = p.rowid";
495 $sqlProductionToProduce .= " AND mp5.role IN ('toproduce', 'produced')";
496 $sqlProductionToProduce .= " AND mm5.status IN (1,2))";
497 } else {
498 $sqlProductionToConsume = '0';
499 $sqlProductionToProduce = '0';
500 }
501
502 $sql .= ' HAVING (';
503 $sql .= " (" . $sqldesiredtock . " >= 0 AND (" . $sqldesiredtock . " > SUM(" . $db->ifsql("s.reel IS NULL", "0", "s.reel") . ')';
504 $sql .= " - (" . $sqlCommandesCli . " - " . $sqlExpeditionsCli . ") + (" . $sqlCommandesFourn . " - " . $sqlReceptionFourn . ") + (" . $sqlProductionToProduce . " - " . $sqlProductionToConsume . ")))";
505 $sql .= ' OR';
506 if ($includeproductswithoutdesiredqty == 'on') {
507 $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") . ")";
508 } else {
509 $sql .= " (" . $sqlalertstock . " >= 0 AND (" . $sqlalertstock . " > SUM(" . $db->ifsql("s.reel IS NULL", "0", "s.reel") . ')';
510 }
511 $sql .= " - (" . $sqlCommandesCli . " - " . $sqlExpeditionsCli . ") + (" . $sqlCommandesFourn . " - " . $sqlReceptionFourn . ") + (" . $sqlProductionToProduce . " - " . $sqlProductionToConsume . ")))";
512 $sql .= ")";
513 if (!empty($conf->global->STOCK_ALLOW_ADD_LIMIT_STOCK_BY_WAREHOUSE) && $fk_entrepot > 0) {
514 $sql .= " AND (";
515 $sql .= " pse.desiredstock > 0)";
516 }
517
518 if ($salert == 'on') { // Option to see when stock is lower than alert
519 $sql .= ' AND (';
520 if ($includeproductswithoutdesiredqty == 'on') {
521 $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") . ")";
522 } else {
523 $sql .= $sqlalertstock . " >= 0 AND (" . $sqlalertstock . " > SUM(" . $db->ifsql("s.reel IS NULL", "0", "s.reel") . ")";
524 }
525 $sql .= " - (" . $sqlCommandesCli . " - " . $sqlExpeditionsCli . ") + (" . $sqlCommandesFourn . " - " . $sqlReceptionFourn . ") + (" . $sqlProductionToProduce . " - " . $sqlProductionToConsume . "))";
526 $sql .= ")";
527 $alertchecked = 'checked';
528 }
529} else {
530 $sql .= ' HAVING (';
531 $sql .= "(" . $sqldesiredtock . " >= 0 AND (" . $sqldesiredtock . " > SUM(" . $db->ifsql("s.reel IS NULL", "0", "s.reel") . ")))";
532 $sql .= ' OR';
533 if ($includeproductswithoutdesiredqty == 'on') {
534 $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") . ')))';
535 } else {
536 $sql .= " (" . $sqlalertstock . " >= 0 AND (" . $sqlalertstock . " > SUM(" . $db->ifsql("s.reel IS NULL", "0", "s.reel") . ')))';
537 }
538 $sql .= ')';
539 if (!empty($conf->global->STOCK_ALLOW_ADD_LIMIT_STOCK_BY_WAREHOUSE) && $fk_entrepot > 0) {
540 $sql .= " AND (";
541 $sql .= " pse.desiredstock > 0)";
542 }
543
544 if ($salert == 'on') { // Option to see when stock is lower than alert
545 $sql .= " AND (";
546 if ($includeproductswithoutdesiredqty == 'on') {
547 $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") . "))";
548 } else {
549 $sql .= " " . $sqlalertstock . " >= 0 AND (" . $sqlalertstock . " > SUM(" . $db->ifsql("s.reel IS NULL", "0", "s.reel") . '))';
550 }
551 $sql .= ')';
552 $alertchecked = 'checked';
553 }
554}
555
556$includeproductswithoutdesiredqtychecked = '';
557if ($includeproductswithoutdesiredqty == 'on') {
558 $includeproductswithoutdesiredqtychecked = 'checked';
559}
560
561$nbtotalofrecords = '';
562if (!getDolGlobalInt('MAIN_DISABLE_FULL_SCANLIST')) {
563 $result = $db->query($sql);
564 $nbtotalofrecords = $db->num_rows($result);
565 if (($page * $limit) > $nbtotalofrecords) {
566 $page = 0;
567 $offset = 0;
568 }
569}
570
571$sql .= $db->order($sortfield, $sortorder);
572$sql .= $db->plimit($limit + 1, $offset);
573
574//print $sql;
575$resql = $db->query($sql);
576if (empty($resql)) {
577 dol_print_error($db);
578 exit;
579}
580
581$num = $db->num_rows($resql);
582$i = 0;
583
584$helpurl = 'EN:Module_Stocks_En|FR:Module_Stock|';
585$helpurl .= 'ES:M&oacute;dulo_Stocks';
586
587llxHeader('', $title, $helpurl, '');
588
589$head = array();
590
591$head[0][0] = DOL_URL_ROOT . '/product/stock/replenish.php';
592$head[0][1] = $title;
593$head[0][2] = 'replenish';
594
595$head[1][0] = DOL_URL_ROOT . '/product/stock/replenishorders.php';
596$head[1][1] = $langs->trans("ReplenishmentOrders");
597$head[1][2] = 'replenishorders';
598
599
600print load_fiche_titre($langs->trans('Replenishment'), '', 'stock');
601
602print dol_get_fiche_head($head, 'replenish', '', -1, '');
603
604print '<span class="opacitymedium">' . $langs->trans("ReplenishmentStatusDesc") . '</span>' . "\n";
605
606//$link = '<a title=' .$langs->trans("MenuNewWarehouse"). ' href="'.DOL_URL_ROOT.'/product/stock/card.php?action=create">'.$langs->trans("MenuNewWarehouse").'</a>';
607
608if (empty($fk_entrepot) && getDolGlobalString('STOCK_ALLOW_ADD_LIMIT_STOCK_BY_WAREHOUSE')) {
609 print '<span class="opacitymedium">'.$langs->trans("ReplenishmentStatusDescPerWarehouse").'</span>'."\n";
610}
611print '<br><br>';
612if ($usevirtualstock == 1) {
613 print $langs->trans("CurentSelectionMode") . ': ';
614 print '<span class="a-mesure">' . $langs->trans("UseVirtualStock") . '</span>';
615 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>';
616 print '<br>';
617}
618if ($usevirtualstock == 0) {
619 print $langs->trans("CurentSelectionMode") . ': ';
620 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>';
621 print ' <span class="a-mesure">' . $langs->trans("UsePhysicalStock") . '</span>';
622 print '<br>';
623}
624print '<br>' . "\n";
625
626print '<form name="formFilterWarehouse" method="POST" action="' . $_SERVER["PHP_SELF"] . '">';
627print '<input type="hidden" name="token" value="' . newToken() . '">';
628print '<input type="hidden" name="action" value="filter">';
629print '<input type="hidden" name="search_ref" value="' . $search_ref . '">';
630print '<input type="hidden" name="search_label" value="' . $search_label . '">';
631print '<input type="hidden" name="salert" value="' . $salert . '">';
632print '<input type="hidden" name="includeproductswithoutdesiredqty" value="' . $includeproductswithoutdesiredqty . '">';
633print '<input type="hidden" name="draftorder" value="' . $draftorder . '">';
634print '<input type="hidden" name="mode" value="' . $mode . '">';
635if ($limit > 0 && $limit != $conf->liste_limit) {
636 print '<input type="hidden" name="limit" value="' . $limit . '">';
637}
638if (getDolGlobalString('STOCK_ALLOW_ADD_LIMIT_STOCK_BY_WAREHOUSE')) {
639 print '<div class="inline-block valignmiddle" style="padding-right: 20px;">';
640 print $langs->trans('Warehouse') . ' ' . $formproduct->selectWarehouses($fk_entrepot, 'fk_entrepot', '', 1);
641 print '</div>';
642}
643print '<div class="inline-block valignmiddle" style="padding-right: 20px;">';
644$filter = '(fournisseur:=:1)';
645print $langs->trans('Supplier') . ' ' . $form->select_company($fk_supplier, 'fk_supplier', $filter, 1);
646print '</div>';
647
648$parameters = array();
649$reshook = $hookmanager->executeHooks('printFieldPreListTitle', $parameters); // Note that $action and $object may have been modified by hook
650if (empty($reshook)) {
651 print $hookmanager->resPrint;
652}
653
654print '<div class="inline-block valignmiddle">';
655print '<input type="submit" class="button smallpaddingimp" name="valid" value="' . $langs->trans('ToFilter') . '">';
656print '</div>';
657
658print '</form>';
659
660print '<form action="' . $_SERVER["PHP_SELF"] . '" method="POST" name="formulaire">';
661print '<input type="hidden" name="token" value="' . newToken() . '">';
662print '<input type="hidden" name="fk_supplier" value="' . $fk_supplier . '">';
663print '<input type="hidden" name="fk_entrepot" value="' . $fk_entrepot . '">';
664print '<input type="hidden" name="sortfield" value="' . $sortfield . '">';
665print '<input type="hidden" name="sortorder" value="' . $sortorder . '">';
666print '<input type="hidden" name="type" value="' . $type . '">';
667print '<input type="hidden" name="linecount" value="' . $num . '">';
668print '<input type="hidden" name="action" value="order">';
669print '<input type="hidden" name="mode" value="' . $mode . '">';
670
671
672if ($search_ref || $search_label || $sall || $salert || $draftorder || GETPOST('search', 'alpha')) {
673 $filters = '&search_ref=' . urlencode($search_ref) . '&search_label=' . urlencode($search_label);
674 $filters .= '&sall=' . urlencode($sall);
675 $filters .= '&salert=' . urlencode($salert);
676 $filters .= '&draftorder=' . urlencode($draftorder);
677 $filters .= '&mode=' . urlencode($mode);
678 if ($fk_supplier > 0) {
679 $filters .= '&fk_supplier=' . urlencode($fk_supplier);
680 }
681 if ($fk_entrepot > 0) {
682 $filters .= '&fk_entrepot=' . urlencode($fk_entrepot);
683 }
684} else {
685 $filters = '&search_ref=' . urlencode($search_ref) . '&search_label=' . urlencode($search_label);
686 $filters .= '&fourn_id=' . urlencode($fourn_id);
687 $filters .= (isset($type) ? '&type=' . urlencode($type) : '');
688 $filters .= '&=' . urlencode($salert);
689 $filters .= '&draftorder=' . urlencode($draftorder);
690 $filters .= '&mode=' . urlencode($mode);
691 if ($fk_supplier > 0) {
692 $filters .= '&fk_supplier=' . urlencode($fk_supplier);
693 }
694 if ($fk_entrepot > 0) {
695 $filters .= '&fk_entrepot=' . urlencode($fk_entrepot);
696 }
697}
698if ($limit > 0 && $limit != $conf->liste_limit) {
699 $filters .= '&limit=' . ((int) $limit);
700}
701if (!empty($includeproductswithoutdesiredqty)) {
702 $filters .= '&includeproductswithoutdesiredqty='.urlencode($includeproductswithoutdesiredqty);
703}
704if (!empty($salert)) {
705 $filters .= '&salert='.urlencode($salert);
706}
707
708$param = (isset($type) ? '&type='.urlencode($type) : '');
709$param .= '&fourn_id='.urlencode($fourn_id).'&search_label='.urlencode($search_label).'&includeproductswithoutdesiredqty='.urlencode($includeproductswithoutdesiredqty).'&salert='.urlencode($salert).'&draftorder='.urlencode($draftorder);
710$param .= '&search_ref='.urlencode($search_ref);
711$param .= '&mode='.urlencode($mode);
712$param .= '&fk_supplier='.urlencode($fk_supplier);
713$param .= '&fk_entrepot='.urlencode($fk_entrepot);
714if (!empty($includeproductswithoutdesiredqty)) {
715 $param .= '&includeproductswithoutdesiredqty='.urlencode($includeproductswithoutdesiredqty);
716}
717if (!empty($salert)) {
718 $param .= '&salert='.urlencode($salert);
719}
720
721$stocklabel = $langs->trans('Stock');
722$stocklabelbis = $langs->trans('Stock');
723$stocktooltip = '';
724if ($usevirtualstock == 1) {
725 $stocklabel = $langs->trans('VirtualStock');
726 $stocktooltip = $langs->trans("VirtualStockDesc");
727}
728if ($usevirtualstock == 0) {
729 $stocklabel = $langs->trans('PhysicalStock');
730}
731if (getDolGlobalString('STOCK_ALLOW_ADD_LIMIT_STOCK_BY_WAREHOUSE') && $fk_entrepot > 0) {
732 $stocklabelbis = $stocklabel.' (Selected warehouse)';
733 $stocklabel .= ' ('.$langs->trans("AllWarehouses").')';
734}
735$texte = $langs->trans('Replenishment');
736
737print '<br>';
738
739
740if (getDolGlobalString('REPLENISH_ALLOW_VARIABLESIZELIST')) {
742 $texte,
743 $page,
744 'replenish.php',
745 $filters,
746 $sortfield,
747 $sortorder,
748 '',
749 $num,
750 $nbtotalofrecords,
751 '',
752 0,
753 '',
754 '',
755 $limit
756 );
757} else {
759 $texte,
760 $page,
761 'replenish.php',
762 $filters,
763 $sortfield,
764 $sortorder,
765 '',
766 $num,
767 $nbtotalofrecords,
768 ''
769 );
770}
771
772
773print '<div class="div-table-responsive-no-min">';
774print '<table class="liste centpercent">';
775
776// Fields title search
777print '<tr class="liste_titre_filter">';
778print '<td class="liste_titre">&nbsp;</td>';
779print '<td class="liste_titre"><input class="flat" type="text" name="search_ref" size="8" value="' . dol_escape_htmltag($search_ref) . '"></td>';
780print '<td class="liste_titre"><input class="flat" type="text" name="search_label" size="8" value="' . dol_escape_htmltag($search_label) . '"></td>';
781if (isModEnabled("service") && $type == 1) {
782 print '<td class="liste_titre">&nbsp;</td>';
783}
784print '<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>';
785print '<td class="liste_titre right"></td>';
786print '<td class="liste_titre right">'.$langs->trans('AlertOnly').'&nbsp;<input type="checkbox" id="salert" name="salert" '.(!empty($alertchecked) ? $alertchecked : '').'></td>';
787if (getDolGlobalString('STOCK_ALLOW_ADD_LIMIT_STOCK_BY_WAREHOUSE') && $fk_entrepot > 0) {
788 print '<td class="liste_titre">&nbsp;</td>';
789}
790print '<td class="liste_titre right">';
791if (getDolGlobalString('STOCK_REPLENISH_ADD_CHECKBOX_INCLUDE_DRAFT_ORDER')) {
792 print $langs->trans('IncludeAlsoDraftOrders').'&nbsp;<input type="checkbox" id="draftorder" name="draftorder" '.(!empty($draftchecked) ? $draftchecked : '').'>';
793}
794print '</td>';
795print '<td class="liste_titre">&nbsp;</td>';
796// Fields from hook
797$parameters = array('param' => $param, 'sortfield' => $sortfield, 'sortorder' => $sortorder);
798$reshook = $hookmanager->executeHooks('printFieldListOption', $parameters); // Note that $action and $object may have been modified by hook
799print $hookmanager->resPrint;
800
801print '<td class="liste_titre maxwidthsearch right">';
802$searchpicto = $form->showFilterAndCheckAddButtons(0);
803print $searchpicto;
804print '</td>';
805print '</tr>';
806
807// Lines of title
808print '<tr class="liste_titre">';
809print_liste_field_titre('<input type="checkbox" onClick="toggle(this)" />', $_SERVER["PHP_SELF"], '');
810print_liste_field_titre('ProductRef', $_SERVER["PHP_SELF"], 'p.ref', $param, '', '', $sortfield, $sortorder);
811print_liste_field_titre('Label', $_SERVER["PHP_SELF"], 'p.label', $param, '', '', $sortfield, $sortorder);
812if (isModEnabled("service") && $type == 1) {
813 print_liste_field_titre('Duration', $_SERVER["PHP_SELF"], 'p.duration', $param, '', '', $sortfield, $sortorder, 'center ');
814}
815print_liste_field_titre('DesiredStock', $_SERVER["PHP_SELF"], 'p.desiredstock', $param, '', '', $sortfield, $sortorder, 'right ');
816print_liste_field_titre('StockLimitShort', $_SERVER["PHP_SELF"], 'p.seuil_stock_alerte', $param, '', '', $sortfield, $sortorder, 'right ');
817print_liste_field_titre($stocklabel, $_SERVER["PHP_SELF"], 'stock_physique', $param, '', '', $sortfield, $sortorder, 'right ', $stocktooltip);
818if (getDolGlobalString('STOCK_ALLOW_ADD_LIMIT_STOCK_BY_WAREHOUSE') && $fk_entrepot > 0) {
819 print_liste_field_titre($stocklabelbis, $_SERVER["PHP_SELF"], 'stock_real_warehouse', $param, '', '', $sortfield, $sortorder, 'right ');
820}
821print_liste_field_titre('Ordered', $_SERVER["PHP_SELF"], '', $param, '', '', $sortfield, $sortorder, 'right ');
822print_liste_field_titre('StockToBuy', $_SERVER["PHP_SELF"], '', $param, '', '', $sortfield, $sortorder, 'right ');
823print_liste_field_titre('SupplierRef', $_SERVER["PHP_SELF"], '', $param, '', '', $sortfield, $sortorder, 'right ');
824
825// Hook fields
826$parameters = array('param' => $param, 'sortfield' => $sortfield, 'sortorder' => $sortorder);
827$reshook = $hookmanager->executeHooks('printFieldListTitle', $parameters); // Note that $action and $object may have been modified by hook
828print $hookmanager->resPrint;
829
830print "</tr>\n";
831
832while ($i < ($limit ? min($num, $limit) : $num)) {
833 $objp = $db->fetch_object($resql);
834
835 if (getDolGlobalString('STOCK_SUPPORTS_SERVICES') || $objp->fk_product_type == 0) {
836 $result = $prod->fetch($objp->rowid);
837 if ($result < 0) {
838 dol_print_error($db);
839 exit;
840 }
841
842 $prod->load_stock('warehouseopen, warehouseinternal'.(!$usevirtualstock ? ', novirtual' : ''), $draftchecked);
843
844 // Multilangs
845 if (getDolGlobalInt('MAIN_MULTILANGS')) {
846 $sql = 'SELECT label,description';
847 $sql .= ' FROM ' . MAIN_DB_PREFIX . 'product_lang';
848 $sql .= ' WHERE fk_product = ' . ((int) $objp->rowid);
849 $sql .= " AND lang = '" . $db->escape($langs->getDefaultLang()) . "'";
850 $sql .= ' LIMIT 1';
851
852 $resqlm = $db->query($sql);
853 if ($resqlm) {
854 $objtp = $db->fetch_object($resqlm);
855 if (!empty($objtp->description)) {
856 $objp->description = $objtp->description;
857 }
858 if (!empty($objtp->label)) {
859 $objp->label = $objtp->label;
860 }
861 }
862 }
863
864 $stockwarehouse = 0;
865 if ($usevirtualstock) {
866 // If option to increase/decrease is not on an object validation, virtual stock may differs from physical stock.
867 $stock = $prod->stock_theorique;
868 //TODO $stockwarehouse = $prod->stock_warehouse[$fk_entrepot]->;
869 } else {
870 $stock = $prod->stock_reel;
871 if (!empty($prod->stock_warehouse[$fk_entrepot])) {
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(!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($titre, $morehtmlright='', $picto='generic', $pictoisfullpath=0, $id='', $morecssontable='', $morehtmlcenter='')
Load a title with picto.
img_warning($titlealt='default', $moreatt='', $morecss='pictowarning')
Show warning logo.
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_print_error($db='', $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
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.
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2)
Show picto whatever it's its name (generic function)
print_liste_field_titre($name, $file="", $field="", $begin="", $moreparam="", $moreattrib="", $sortfield="", $sortorder="", $prefix="", $tooltip="", $forcenowrapcolumntitle=0)
Show title line of an array.
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.
print_barre_liste($titre, $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.
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.