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