dolibarr 20.0.2
movement_card.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2001-2006 Rodolphe Quiedeville <rodolphe@quiedeville.org>
3 * Copyright (C) 2004-2020 Laurent Destailleur <eldy@users.sourceforge.net>
4 * Copyright (C) 2005-2014 Regis Houssin <regis.houssin@inodbox.com>
5 * Copyright (C) 2015 Juanjo Menent <jmenent@2byte.es>
6 * Copyright (C) 2018 Ferran Marcet <fmarcet@2byte.es>
7 * Copyright (C) 2019-2024 Frédéric France <frederic.france@free.fr>
8 * Copyright (C) 2024 MDW <mdeweerd@users.noreply.github.com>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 3 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program. If not, see <https://www.gnu.org/licenses/>.
22 */
23
30// Load Dolibarr environment
31require '../../main.inc.php';
32require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php';
33require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
34require_once DOL_DOCUMENT_ROOT.'/product/stock/class/entrepot.class.php';
35require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
36require_once DOL_DOCUMENT_ROOT.'/product/stock/class/productlot.class.php';
37require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php';
38require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php';
39require_once DOL_DOCUMENT_ROOT.'/core/lib/stock.lib.php';
40require_once DOL_DOCUMENT_ROOT.'/core/lib/product.lib.php';
41require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
42if (isModEnabled('project')) {
43 require_once DOL_DOCUMENT_ROOT.'/core/class/html.formprojet.class.php';
44 require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
45}
46
47// Load translation files required by the page
48$langs->loadLangs(array('products', 'stocks', 'orders'));
49if (isModEnabled('productbatch')) {
50 $langs->load("productbatch");
51}
52
53// Security check
54$result = restrictedArea($user, 'stock');
55
56$id = GETPOSTINT('id');
57$ref = GETPOST('ref', 'alpha');
58$msid = GETPOSTINT('msid');
59$product_id = GETPOSTINT("product_id");
60$action = GETPOST('action', 'aZ09');
61$cancel = GETPOST('cancel', 'alpha');
62$contextpage = GETPOST('contextpage', 'aZ') ? GETPOST('contextpage', 'aZ') : 'movementlist';
63
64$idproduct = GETPOSTINT('idproduct');
65$year = GETPOSTINT("year");
66$month = GETPOSTINT("month");
67$search_ref = GETPOST('search_ref', 'alpha');
68$search_movement = GETPOST("search_movement", 'alpha');
69$search_product_ref = trim(GETPOST("search_product_ref", 'alpha'));
70$search_product = trim(GETPOST("search_product", 'alpha'));
71$search_warehouse = trim(GETPOST("search_warehouse", 'alpha'));
72$search_inventorycode = trim(GETPOST("search_inventorycode", 'alpha'));
73$search_user = trim(GETPOST("search_user", 'alpha'));
74$search_batch = trim(GETPOST("search_batch", 'alpha'));
75$search_qty = trim(GETPOST("search_qty", 'alpha'));
76$search_type_mouvement = GETPOST('search_type_mouvement', "intcomma");
77
78$limit = GETPOSTINT('limit') ? GETPOSTINT('limit') : $conf->liste_limit;
79$page = GETPOSTISSET('pageplusone') ? (GETPOSTINT('pageplusone') - 1) : GETPOSTINT("page");
80$sortfield = GETPOST('sortfield', 'aZ09comma');
81$sortorder = GETPOST('sortorder', 'aZ09comma');
82if (empty($page) || $page == -1) {
83 $page = 0;
84} // If $page is not defined, or '' or -1
85$offset = $limit * $page;
86if (!$sortfield) {
87 $sortfield = "m.datem";
88}
89if (!$sortorder) {
90 $sortorder = "DESC";
91}
92
93$pdluoid = GETPOSTINT('pdluoid');
94
95// Initialize technical object to manage hooks of page. Note that conf->hooks_modules contains array of hook context
96$object = new MouvementStock($db);
97$hookmanager->initHooks(array('movementlist'));
98$extrafields = new ExtraFields($db);
99$formfile = new FormFile($db);
100
101// fetch optionals attributes and labels
102$extrafields->fetch_name_optionals_label($object->table_element);
103
104$search_array_options = $extrafields->getOptionalsFromPost($object->table_element, '', 'search_');
105
106$arrayfields = array(
107 'm.rowid' => array('label' => $langs->trans("Ref"), 'checked' => 1),
108 'm.datem' => array('label' => $langs->trans("Date"), 'checked' => 1),
109 'p.ref' => array('label' => $langs->trans("ProductRef"), 'checked' => 1, 'css' => 'maxwidth100'),
110 'p.label' => array('label' => $langs->trans("ProductLabel"), 'checked' => 1),
111 'm.batch' => array('label' => $langs->trans("BatchNumberShort"), 'checked' => 1, 'enabled' => (isModEnabled('productbatch'))),
112 'pl.eatby' => array('label' => $langs->trans("EatByDate"), 'checked' => 0, 'position' => 10, 'enabled' => (isModEnabled('productbatch'))),
113 'pl.sellby' => array('label' => $langs->trans("SellByDate"), 'checked' => 0, 'position' => 10, 'enabled' => (isModEnabled('productbatch'))),
114 'e.ref' => array('label' => $langs->trans("Warehouse"), 'checked' => 1, 'enabled' => (!($id > 0))), // If we are on specific warehouse, we hide it
115 'm.fk_user_author' => array('label' => $langs->trans("Author"), 'checked' => 0),
116 'm.inventorycode' => array('label' => $langs->trans("InventoryCodeShort"), 'checked' => 1),
117 'm.label' => array('label' => $langs->trans("MovementLabel"), 'checked' => 1),
118 'm.type_mouvement' => array('label' => $langs->trans("TypeMovement"), 'checked' => 1),
119 'origin' => array('label' => $langs->trans("Origin"), 'checked' => 1),
120 'm.value' => array('label' => $langs->trans("Qty"), 'checked' => 1),
121 'm.price' => array('label' => $langs->trans("UnitPurchaseValue"), 'checked' => 0),
122 //'m.datec'=>array('label'=>$langs->trans("DateCreation"), 'checked'=>0, 'position'=>500),
123 //'m.tms'=>array('label'=>$langs->trans("DateModificationShort"), 'checked'=>0, 'position'=>500)
124);
125
126$usercanread = (($user->hasRight('stock', 'mouvement', 'lire')));
127$usercancreate = (($user->hasRight('stock', 'mouvement', 'creer')));
128$usercandelete = (($user->hasRight('stock', 'mouvement', 'supprimer')));
129
130
131
132/*
133 * Actions
134 */
135
136if (GETPOST('cancel', 'alpha')) {
137 $action = 'list';
138 $massaction = '';
139}
140if (!GETPOST('confirmmassaction', 'alpha') && $massaction != 'presend' && $massaction != 'confirm_presend') {
141 $massaction = '';
142}
143
144$parameters = array();
145$reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
146if ($reshook < 0) {
147 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
148}
149
150include DOL_DOCUMENT_ROOT.'/core/actions_changeselectedfields.inc.php';
151
152// Do we click on purge search criteria ?
153if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x', 'alpha') || GETPOST('button_removefilter', 'alpha')) { // Both test are required to be compatible with all browsers
154 $year = '';
155 $month = '';
156 $search_ref = '';
157 $search_movement = "";
158 $search_type_mouvement = "";
159 $search_inventorycode = "";
160 $search_product_ref = "";
161 $search_product = "";
162 $search_warehouse = "";
163 $search_user = "";
164 $search_batch = "";
165 $search_qty = '';
166 $sall = "";
167 $toselect = array();
168 $search_array_options = array();
169}
170
171// Correct stock
172if ($action == "correct_stock" && !$cancel && $usercancreate) {
173 $product = new Product($db);
174 if (!empty($product_id)) {
175 $result = $product->fetch($product_id);
176 }
177
178 $error = 0;
179
180 if (empty($product_id)) {
181 $error++;
182 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Product")), null, 'errors');
183 $action = 'correction';
184 }
185 if (!is_numeric(GETPOST("nbpiece"))) {
186 $error++;
187 setEventMessages($langs->trans("ErrorFieldMustBeANumeric", $langs->transnoentitiesnoconv("NumberOfUnit")), null, 'errors');
188 $action = 'correction';
189 }
190
191 if (!$error) {
192 $origin_element = '';
193 $origin_id = null;
194
195 if (GETPOSTINT('projectid')) {
196 $origin_element = 'project';
197 $origin_id = GETPOSTINT('projectid');
198 }
199
200 if ($product->hasbatch()) {
201 $batch = GETPOST('batch_number', 'alpha');
202
203 //$eatby=GETPOST('eatby');
204 //$sellby=GETPOST('sellby');
205 $eatby = dol_mktime(0, 0, 0, GETPOSTINT('eatbymonth'), GETPOSTINT('eatbyday'), GETPOSTINT('eatbyyear'));
206 $sellby = dol_mktime(0, 0, 0, GETPOSTINT('sellbymonth'), GETPOSTINT('sellbyday'), GETPOSTINT('sellbyyear'));
207
208 $result = $product->correct_stock_batch(
209 $user,
210 $id,
211 GETPOSTINT("nbpiece"),
212 GETPOSTINT("mouvement"),
213 GETPOST("label", 'san_alpha'),
214 GETPOST('unitprice', 'alpha'),
215 $eatby,
216 $sellby,
217 $batch,
218 GETPOST('inventorycode', 'alpha'),
219 $origin_element,
220 $origin_id
221 ); // We do not change value of stock for a correction
222 } else {
223 $result = $product->correct_stock(
224 $user,
225 $id,
226 GETPOSTINT("nbpiece"),
227 GETPOST("mouvement", 'alpha'),
228 GETPOST("label", 'san_alpha'),
229 GETPOST('unitprice', 'alpha'),
230 GETPOST('inventorycode', 'alpha'),
231 $origin_element,
232 $origin_id
233 ); // We do not change value of stock for a correction
234 }
235
236 if ($result > 0) {
237 header("Location: ".$_SERVER["PHP_SELF"]."?id=".$id);
238 exit;
239 } else {
240 $error++;
241 setEventMessages($product->error, $product->errors, 'errors');
242 $action = 'correction';
243 }
244 }
245
246 if (!$error) {
247 $action = '';
248 }
249}
250
251// Transfer stock from a warehouse to another warehouse
252if ($action == "transfert_stock" && !$cancel && $usercancreate) {
253 $error = 0;
254 $product = new Product($db);
255 if (!empty($product_id)) {
256 $result = $product->fetch($product_id);
257 }
258
259 if (!(GETPOSTINT("id_entrepot_destination") > 0)) {
260 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Warehouse")), null, 'errors');
261 $error++;
262 $action = 'transfert';
263 }
264 if (empty($product_id)) {
265 $error++;
266 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Product")), null, 'errors');
267 $action = 'transfert';
268 }
269 if (!GETPOSTINT("nbpiece")) {
270 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("NumberOfUnit")), null, 'errors');
271 $error++;
272 $action = 'transfert';
273 }
274 if ($id == GETPOSTINT("id_entrepot_destination")) {
275 setEventMessages($langs->trans("ErrorSrcAndTargetWarehouseMustDiffers"), null, 'errors');
276 $error++;
277 $action = 'transfert';
278 }
279
280 if (isModEnabled('productbatch')) {
281 $product = new Product($db);
282 $result = $product->fetch($product_id);
283
284 if ($product->hasbatch() && !GETPOST("batch_number", 'alpha')) {
285 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("batch_number")), null, 'errors');
286 $error++;
287 $action = 'transfert';
288 }
289 }
290
291 if (!$error) {
292 if ($id) {
293 $object = new Entrepot($db);
294 $result = $object->fetch($id);
295
296 $db->begin();
297
298 $product->load_stock('novirtual'); // Load array product->stock_warehouse
299
300 // Define value of products moved
301 $pricesrc = 0;
302 if (isset($product->pmp)) {
303 $pricesrc = $product->pmp;
304 }
305 $pricedest = $pricesrc;
306
307 if ($product->hasbatch()) {
308 $pdluo = new Productbatch($db);
309
310 if ($pdluoid > 0) {
311 $result = $pdluo->fetch($pdluoid);
312 if ($result) {
313 $srcwarehouseid = $pdluo->warehouseid;
314 $batch = $pdluo->batch;
315 $eatby = $pdluo->eatby;
316 $sellby = $pdluo->sellby;
317 } else {
318 setEventMessages($pdluo->error, $pdluo->errors, 'errors');
319 $error++;
320 }
321 } else {
322 $srcwarehouseid = $id;
323 $batch = GETPOST('batch_number', 'alpha');
324 $eatby = $d_eatby;
325 $sellby = $d_sellby;
326 }
327
328 if (!$error) {
329 // Remove stock
330 $result1 = $product->correct_stock_batch(
331 $user,
332 $srcwarehouseid,
333 GETPOSTINT("nbpiece"),
334 1,
335 GETPOST("label", 'san_alpha'),
336 $pricesrc,
337 $eatby,
338 $sellby,
339 $batch,
340 GETPOST('inventorycode', 'alpha')
341 );
342 // Add stock
343 $result2 = $product->correct_stock_batch(
344 $user,
345 GETPOSTINT("id_entrepot_destination"),
346 GETPOSTINT("nbpiece"),
347 0,
348 GETPOST("label", 'san_alpha'),
349 $pricedest,
350 $eatby,
351 $sellby,
352 $batch,
353 GETPOST('inventorycode', 'alpha')
354 );
355 }
356 } else {
357 // Remove stock
358 $result1 = $product->correct_stock(
359 $user,
360 $id,
361 GETPOSTINT("nbpiece"),
362 1,
363 GETPOST("label", 'alpha'),
364 $pricesrc,
365 GETPOST('inventorycode', 'alpha')
366 );
367
368 // Add stock
369 $result2 = $product->correct_stock(
370 $user,
371 GETPOST("id_entrepot_destination"),
372 GETPOSTINT("nbpiece"),
373 0,
374 GETPOST("label", 'alpha'),
375 $pricedest,
376 GETPOST('inventorycode', 'alpha')
377 );
378 }
379 if (!$error && $result1 >= 0 && $result2 >= 0) {
380 $db->commit();
381
382 if ($backtopage) {
383 header("Location: ".$backtopage);
384 exit;
385 } else {
386 header("Location: movement_list.php?id=".$object->id);
387 exit;
388 }
389 } else {
390 setEventMessages($product->error, $product->errors, 'errors');
391 $db->rollback();
392 $action = 'transfert';
393 }
394 }
395 }
396}
397
398
399/*
400 * Build document
401 */
402// The builddoc action for object of a movement must be on the movement card
403// Actions to build doc
404$upload_dir = $conf->stock->dir_output."movement/";
405$permissiontoadd = $user->hasRight('stock', 'creer');
406include DOL_DOCUMENT_ROOT.'/core/actions_builddoc.inc.php';
407
408
409if (empty($reshook) && $action != 'remove_file') {
410 $objectclass = 'MouvementStock';
411 $objectlabel = 'Movements';
412 $permissiontoread = $user->hasRight('stock', 'lire');
413 $permissiontodelete = $user->hasRight('stock', 'supprimer');
414 $uploaddir = $conf->stock->dir_output."/movement/";
415 include DOL_DOCUMENT_ROOT.'/core/actions_massactions.inc.php';
416}
417
418
419
420/*
421 * View
422 */
423
424$productlot = new Productlot($db);
425$productstatic = new Product($db);
426$warehousestatic = new Entrepot($db);
427$movement = new MouvementStock($db);
428$userstatic = new User($db);
429$form = new Form($db);
430$formother = new FormOther($db);
431$formproduct = new FormProduct($db);
432if (isModEnabled('project')) {
433 $formproject = new FormProjets($db);
434}
435
436$sql = "SELECT p.rowid, p.ref as product_ref, p.label as produit, p.tobatch, p.fk_product_type as type, p.entity,";
437$sql .= " e.ref as warehouse_ref, e.rowid as entrepot_id, e.lieu,";
438$sql .= " m.rowid as mid, m.value as qty, m.datem, m.fk_user_author, m.label, m.inventorycode, m.fk_origin, m.origintype,";
439$sql .= " m.batch, m.price,";
440$sql .= " m.type_mouvement,";
441$sql .= " pl.rowid as lotid, pl.eatby, pl.sellby,";
442$sql .= " u.login, u.photo, u.lastname, u.firstname";
443// Add fields from extrafields
444if (!empty($extrafields->attributes[$object->table_element]['label'])) {
445 foreach ($extrafields->attributes[$object->table_element]['label'] as $key => $val) {
446 $sql .= ($extrafields->attributes[$object->table_element]['type'][$key] != 'separate' ? ", ef.".$key." as options_".$key : '');
447 }
448}
449// Add fields from hooks
450$parameters = array();
451$reshook = $hookmanager->executeHooks('printFieldListSelect', $parameters); // Note that $action and $object may have been modified by hook
452$sql .= $hookmanager->resPrint;
453$sql .= " FROM ".MAIN_DB_PREFIX."entrepot as e,";
454$sql .= " ".MAIN_DB_PREFIX."product as p,";
455$sql .= " ".MAIN_DB_PREFIX."stock_mouvement as m";
456if (isset($extrafields->attributes[$object->table_element]['label']) && is_array($extrafields->attributes[$object->table_element]['label']) && count($extrafields->attributes[$object->table_element]['label'])) {
457 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX.$object->table_element."_extrafields as ef on (m.rowid = ef.fk_object)";
458}
459$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."user as u ON m.fk_user_author = u.rowid";
460$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product_lot as pl ON m.batch = pl.batch AND m.fk_product = pl.fk_product";
461$sql .= " WHERE m.fk_product = p.rowid";
462if ($msid > 0) {
463 $sql .= " AND m.rowid = ".((int) $msid);
464}
465$sql .= " AND m.fk_entrepot = e.rowid";
466$sql .= " AND e.entity IN (".getEntity('stock').")";
467if (!getDolGlobalString('STOCK_SUPPORTS_SERVICES')) {
468 $sql .= " AND p.fk_product_type = 0";
469}
470if ($id > 0) {
471 $sql .= " AND e.rowid = ".((int) $id);
472}
473$sql .= dolSqlDateFilter('m.datem', 0, $month, $year);
474if ($idproduct > 0) {
475 $sql .= " AND p.rowid = ".((int) $idproduct);
476}
477if (!empty($search_ref)) {
478 $sql .= natural_search('m.rowid', $search_ref, 1);
479}
480if (!empty($search_movement)) {
481 $sql .= natural_search('m.label', $search_movement);
482}
483if (!empty($search_inventorycode)) {
484 $sql .= natural_search('m.inventorycode', $search_inventorycode);
485}
486if (!empty($search_product_ref)) {
487 $sql .= natural_search('p.ref', $search_product_ref);
488}
489if (!empty($search_product)) {
490 $sql .= natural_search('p.label', $search_product);
491}
492if ($search_warehouse != '' && $search_warehouse != '-1') {
493 $sql .= natural_search('e.rowid', $search_warehouse, 2);
494}
495if (!empty($search_user)) {
496 $sql .= natural_search(array('u.lastname', 'u.firstname', 'u.login'), $search_user);
497}
498if (!empty($search_batch)) {
499 $sql .= natural_search('m.batch', $search_batch);
500}
501if ($search_qty != '') {
502 $sql .= natural_search('m.value', $search_qty, 1);
503}
504if ($search_type_mouvement != '' && $search_type_mouvement != '-1') {
505 $sql .= natural_search('m.type_mouvement', $search_type_mouvement, 2);
506}
507// Add where from extra fields
508include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_sql.tpl.php';
509// Add where from hooks
510$parameters = array();
511$reshook = $hookmanager->executeHooks('printFieldListWhere', $parameters); // Note that $action and $object may have been modified by hook
512$sql .= $hookmanager->resPrint;
513$sql .= $db->order($sortfield, $sortorder);
514
515$nbtotalofrecords = '';
516if (!getDolGlobalInt('MAIN_DISABLE_FULL_SCANLIST')) {
517 $result = $db->query($sql);
518 $nbtotalofrecords = $db->num_rows($result);
519 if (($page * $limit) > $nbtotalofrecords) { // if total resultset is smaller then paging size (filtering), goto and load page 0
520 $page = 0;
521 $offset = 0;
522 }
523}
524
525//print $sql;
526
527$resql = $db->query($sql);
528
529if ($resql) {
530 $product = new Product($db);
531 $object = new Entrepot($db);
532
533 if ($idproduct > 0) {
534 $product->fetch($idproduct);
535 }
536 if ($id > 0 || $ref) {
537 $result = $object->fetch($id, $ref);
538 if ($result < 0) {
539 dol_print_error($db);
540 }
541 }
542
543 $num = $db->num_rows($resql);
544
545 $arrayofselected = is_array($toselect) ? $toselect : array();
546
547
548 $i = 0;
549 $help_url = 'EN:Module_Stocks_En|FR:Module_Stock|ES:M&oacute;dulo_Stocks';
550 if ($msid) {
551 $texte = $langs->trans('StockMovementForId', $msid);
552 } else {
553 $texte = $langs->trans("ListOfStockMovements");
554 if ($id) {
555 $texte .= ' ('.$langs->trans("ForThisWarehouse").')';
556 }
557 }
558 llxHeader("", $texte, $help_url, '', 0, 0, '', '', '', 'mod-product page-stock_movement_card');
559
560 /*
561 * Show tab only if we ask a particular warehouse
562 */
563 if ($object->id > 0) {
564 $head = stock_prepare_head($object);
565
566 print dol_get_fiche_head($head, 'movements', $langs->trans("Warehouse"), -1, 'stock');
567
568
569 $linkback = '<a href="'.DOL_URL_ROOT.'/product/stock/list.php?restore_lastsearch_values=1">'.$langs->trans("BackToList").'</a>';
570
571 $morehtmlref = '<div class="refidno">';
572 $morehtmlref .= $langs->trans("LocationSummary").' : '.$object->lieu;
573 $morehtmlref .= '</div>';
574
575 $shownav = 1;
576 if ($user->socid && !in_array('stock', explode(',', getDolGlobalString('MAIN_MODULES_FOR_EXTERNAL')))) {
577 $shownav = 0;
578 }
579
580 dol_banner_tab($object, 'ref', $linkback, $shownav, 'ref', 'ref', $morehtmlref);
581
582
583 print '<div class="fichecenter">';
584 print '<div class="fichehalfleft">';
585 print '<div class="underbanner clearboth"></div>';
586
587 print '<table class="border centpercent">';
588
589 print '<tr>';
590
591 // Description
592 print '<td class="titlefield tdtop">'.$langs->trans("Description").'</td><td>'.dol_htmlentitiesbr($object->description).'</td></tr>';
593
594 $calcproductsunique = $object->nb_different_products();
595 $calcproducts = $object->nb_products();
596
597 // Total nb of different products
598 print '<tr><td>'.$langs->trans("NumberOfDifferentProducts").'</td><td>';
599 print empty($calcproductsunique['nb']) ? '0' : $calcproductsunique['nb'];
600 print "</td></tr>";
601
602 // Nb of products
603 print '<tr><td>'.$langs->trans("NumberOfProducts").'</td><td>';
604 $valtoshow = price2num($calcproducts['nb'], 'MS');
605 print empty($valtoshow) ? '0' : $valtoshow;
606 print "</td></tr>";
607
608 print '</table>';
609
610 print '</div>';
611 print '<div class="fichehalfright">';
612 print '<div class="underbanner clearboth"></div>';
613
614 print '<table class="border centpercent">';
615
616 // Value
617 print '<tr><td class="titlefield">'.$langs->trans("EstimatedStockValueShort").'</td><td>';
618 print price((empty($calcproducts['value']) ? '0' : price2num($calcproducts['value'], 'MT')), 0, $langs, 0, -1, -1, $conf->currency);
619 print "</td></tr>";
620
621 // Last movement
622 $sql = "SELECT MAX(m.datem) as datem";
623 $sql .= " FROM ".MAIN_DB_PREFIX."stock_mouvement as m";
624 $sql .= " WHERE m.fk_entrepot = ".(int) $object->id;
625 $resqlbis = $db->query($sql);
626 if ($resqlbis) {
627 $obj = $db->fetch_object($resqlbis);
628 $lastmovementdate = $db->jdate($obj->datem);
629 } else {
630 dol_print_error($db);
631 }
632
633 print '<tr><td>'.$langs->trans("LastMovement").'</td><td>';
634 if ($lastmovementdate) {
635 print dol_print_date($lastmovementdate, 'dayhour');
636 } else {
637 print $langs->trans("None");
638 }
639 print "</td></tr>";
640
641 print "</table>";
642
643 print '</div>';
644 print '</div>';
645
646 print '<div class="clearboth"></div>';
647
648 print dol_get_fiche_end();
649 }
650
651
652 /*
653 * Correct stock
654 */
655 if ($action == "correction") {
656 include DOL_DOCUMENT_ROOT.'/product/stock/tpl/stockcorrection.tpl.php';
657 print '<br>';
658 }
659
660 /*
661 * Transfer of units
662 */
663 if ($action == "transfert") {
664 include DOL_DOCUMENT_ROOT.'/product/stock/tpl/stocktransfer.tpl.php';
665 print '<br>';
666 }
667
668
669 /*
670 * Action bar
671 */
672 if ((empty($action) || $action == 'list') && $id > 0) {
673 print "<div class=\"tabsAction\">\n";
674
675 if ($user->hasRight('stock', 'mouvement', 'creer')) {
676 print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?id='.$id.'&action=correction&token='.newToken().'">'.$langs->trans("CorrectStock").'</a>';
677 }
678
679 if ($user->hasRight('stock', 'mouvement', 'creer')) {
680 print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?id='.$id.'&action=transfert&token='.newToken().'">'.$langs->trans("TransferStock").'</a>';
681 }
682
683 print '</div><br>';
684 }
685
686 $param = '';
687 if (!empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) {
688 $param .= '&contextpage='.urlencode($contextpage);
689 }
690 if ($limit > 0 && $limit != $conf->liste_limit) {
691 $param .= '&limit='.((int) $limit);
692 }
693 if ($id > 0) {
694 $param .= '&id='.urlencode((string) ($id));
695 }
696 if ($search_movement) {
697 $param .= '&search_movement='.urlencode($search_movement);
698 }
699 if ($search_inventorycode) {
700 $param .= '&search_inventorycode='.urlencode($search_inventorycode);
701 }
702 if ($search_type_mouvement) {
703 $param .= '&search_type_mouvement='.urlencode($search_type_mouvement);
704 }
705 if ($search_product_ref) {
706 $param .= '&search_product_ref='.urlencode($search_product_ref);
707 }
708 if ($search_product) {
709 $param .= '&search_product='.urlencode($search_product);
710 }
711 if ($search_batch) {
712 $param .= '&search_batch='.urlencode($search_batch);
713 }
714 if ($search_warehouse > 0) {
715 $param .= '&search_warehouse='.urlencode($search_warehouse);
716 }
717 if ($search_user) {
718 $param .= '&search_user='.urlencode($search_user);
719 }
720 if ($idproduct > 0) {
721 $param .= '&idproduct='.urlencode((string) ($idproduct));
722 }
723 // Add $param from extra fields
724 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_param.tpl.php';
725
726 // List of mass actions available
727 $arrayofmassactions = array(
728 // 'presend'=>$langs->trans("SendByMail"),
729 // 'builddoc'=>$langs->trans("PDFMerge"),
730 );
731 //if ($user->rights->stock->supprimer) $arrayofmassactions['predelete']='<span class="fa fa-trash paddingrightonly"></span>'.$langs->trans("Delete");
732 if (in_array($massaction, array('presend', 'predelete'))) {
733 $arrayofmassactions = array();
734 }
735 $massactionbutton = $form->selectMassAction('', $arrayofmassactions);
736
737 print '<form method="POST" action="'.$_SERVER["PHP_SELF"].'">';
738 if ($optioncss != '') {
739 print '<input type="hidden" name="optioncss" value="'.$optioncss.'">';
740 }
741 print '<input type="hidden" name="token" value="'.newToken().'">';
742 print '<input type="hidden" name="formfilteraction" id="formfilteraction" value="list">';
743 print '<input type="hidden" name="action" value="list">';
744 print '<input type="hidden" name="sortfield" value="'.$sortfield.'">';
745 print '<input type="hidden" name="sortorder" value="'.$sortorder.'">';
746 print '<input type="hidden" name="page" value="'.$page.'">';
747 print '<input type="hidden" name="contextpage" value="'.$contextpage.'">';
748 if ($id > 0) {
749 print '<input type="hidden" name="id" value="'.$id.'">';
750 }
751
752 if ($id > 0) {
753 print_barre_liste($texte, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $massactionbutton, $num, $nbtotalofrecords, '', 0, '', '', $limit);
754 } else {
755 print_barre_liste($texte, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $massactionbutton, $num, $nbtotalofrecords, 'generic', 0, '', '', $limit);
756 }
757
758 if ($sall) {
759 if (!isset($fieldstosearchall) || !is_array($fieldstosearchall)) {
760 // Ensure $fieldstosearchall is array
761 $fieldstosearchall = array();
762 }
763 foreach ($fieldstosearchall as $key => $val) {
764 $fieldstosearchall[$key] = $langs->trans($val);
765 }
766 print '<div class="divsearchfieldfilter">'.$langs->trans("FilterOnInto", $sall).implode(', ', $fieldstosearchall).'</div>';
767 }
768
769 $moreforfilter = '';
770
771 $parameters = array();
772 $reshook = $hookmanager->executeHooks('printFieldPreListTitle', $parameters); // Note that $action and $object may have been modified by hook
773 if (empty($reshook)) {
774 $moreforfilter .= $hookmanager->resPrint;
775 } else {
776 $moreforfilter = $hookmanager->resPrint;
777 }
778
779 if (!empty($moreforfilter)) {
780 print '<div class="liste_titre liste_titre_bydiv centpercent">';
781 print $moreforfilter;
782 print '</div>';
783 }
784
785 $varpage = empty($contextpage) ? $_SERVER["PHP_SELF"] : $contextpage;
786 $selectedfields = $form->multiSelectArrayWithCheckbox('selectedfields', $arrayfields, $varpage); // This also change content of $arrayfields
787
788 print '<div class="div-table-responsive">';
789 print '<table class="tagtable liste'.($moreforfilter ? " listwithfilterbefore" : "").'">'."\n";
790
791 // Fields title search
792 print '<tr class="liste_titre_filter">';
793 if (!empty($arrayfields['m.rowid']['checked'])) {
794 // Ref
795 print '<td class="liste_titre left">';
796 print '<input class="flat maxwidth25" type="text" name="search_ref" value="'.dol_escape_htmltag($search_ref).'">';
797 print '</td>';
798 }
799 if (!empty($arrayfields['m.datem']['checked'])) {
800 print '<td class="liste_titre nowraponall">';
801 print '<input class="flat" type="text" size="2" maxlength="2" placeholder="'.dol_escape_htmltag($langs->trans("Month")).'" name="month" value="'.$month.'">';
802 if (empty($conf->productbatch->enabled)) {
803 print '&nbsp;';
804 }
805 //else print '<br>';
806 $syear = $year ? $year : -1;
807 print '<input class="flat maxwidth50" type="text" maxlength="4" placeholder="'.dol_escape_htmltag($langs->trans("Year")).'" name="year" value="'.($syear > 0 ? $syear : '').'">';
808 //print $formother->selectyear($syear,'year',1, 20, 5);
809 print '</td>';
810 }
811 if (!empty($arrayfields['p.ref']['checked'])) {
812 // Product Ref
813 print '<td class="liste_titre left">';
814 print '<input class="flat maxwidth75" type="text" name="search_product_ref" value="'.dol_escape_htmltag($idproduct ? $product->ref : $search_product_ref).'">';
815 print '</td>';
816 }
817 if (!empty($arrayfields['p.label']['checked'])) {
818 // Product label
819 print '<td class="liste_titre left">';
820 print '<input class="flat maxwidth100" type="text" name="search_product" value="'.dol_escape_htmltag($idproduct ? $product->label : $search_product).'">';
821 print '</td>';
822 }
823 // Batch
824 if (!empty($arrayfields['m.batch']['checked'])) {
825 print '<td class="liste_titre center"><input class="flat maxwidth75" type="text" name="search_batch" value="'.dol_escape_htmltag($search_batch).'"></td>';
826 }
827 if (!empty($arrayfields['pl.eatby']['checked'])) {
828 print '<td class="liste_titre left">';
829 print '</td>';
830 }
831 if (!empty($arrayfields['pl.sellby']['checked'])) {
832 print '<td class="liste_titre left">';
833 print '</td>';
834 }
835 // Warehouse
836 if (!empty($arrayfields['e.ref']['checked'])) {
837 print '<td class="liste_titre maxwidthonsmartphone left">';
838 //print '<input class="flat" type="text" size="8" name="search_warehouse" value="'.($search_warehouse).'">';
839 print $formproduct->selectWarehouses($search_warehouse, 'search_warehouse', 'warehouseopen,warehouseinternal', 1, 0, 0, '', 0, 0, null, 'maxwidth200');
840 print '</td>';
841 }
842 if (!empty($arrayfields['m.fk_user_author']['checked'])) {
843 // Author
844 print '<td class="liste_titre left">';
845 print '<input class="flat" type="text" size="6" name="search_user" value="'.dol_escape_htmltag($search_user).'">';
846 print '</td>';
847 }
848 if (!empty($arrayfields['m.inventorycode']['checked'])) {
849 // Inventory code
850 print '<td class="liste_titre left">';
851 print '<input class="flat" type="text" size="4" name="search_inventorycode" value="'.dol_escape_htmltag($search_inventorycode).'">';
852 print '</td>';
853 }
854 if (!empty($arrayfields['m.label']['checked'])) {
855 // Label of movement
856 print '<td class="liste_titre left">';
857 print '<input class="flat" type="text" size="8" name="search_movement" value="'.dol_escape_htmltag($search_movement).'">';
858 print '</td>';
859 }
860 if (!empty($arrayfields['m.type_mouvement']['checked'])) {
861 // Type of movement
862 print '<td class="liste_titre center">';
863 //print '<input class="flat" type="text" size="3" name="search_type_mouvement" value="'.dol_escape_htmltag($search_type_mouvement).'">';
864 print '<select id="search_type_mouvement" name="search_type_mouvement" class="maxwidth150">';
865 print '<option value="" '.(($search_type_mouvement == "") ? 'selected="selected"' : '').'></option>';
866 print '<option value="0" '.(($search_type_mouvement == "0") ? 'selected="selected"' : '').'>'.$langs->trans('StockIncreaseAfterCorrectTransfer').'</option>';
867 print '<option value="1" '.(($search_type_mouvement == "1") ? 'selected="selected"' : '').'>'.$langs->trans('StockDecreaseAfterCorrectTransfer').'</option>';
868 print '<option value="2" '.(($search_type_mouvement == "2") ? 'selected="selected"' : '').'>'.$langs->trans('StockDecrease').'</option>';
869 print '<option value="3" '.(($search_type_mouvement == "3") ? 'selected="selected"' : '').'>'.$langs->trans('StockIncrease').'</option>';
870 print '</select>';
871 print ajax_combobox('search_type_mouvement');
872 // TODO: add new function $formentrepot->selectTypeOfMovement(...) like
873 // print $formproduct->selectWarehouses($search_warehouse, 'search_warehouse', 'warehouseopen,warehouseinternal', 1, 0, 0, '', 0, 0, null, 'maxwidth200');
874 print '</td>';
875 }
876 if (!empty($arrayfields['origin']['checked'])) {
877 // Origin of movement
878 print '<td class="liste_titre left">';
879 print '&nbsp; ';
880 print '</td>';
881 }
882 if (!empty($arrayfields['m.value']['checked'])) {
883 // Qty
884 print '<td class="liste_titre right">';
885 print '<input class="flat" type="text" size="4" name="search_qty" value="'.dol_escape_htmltag($search_qty).'">';
886 print '</td>';
887 }
888 if (!empty($arrayfields['m.price']['checked'])) {
889 // Price
890 print '<td class="liste_titre left">';
891 print '&nbsp; ';
892 print '</td>';
893 }
894
895
896 // Extra fields
897 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_input.tpl.php';
898
899 // Fields from hook
900 $parameters = array('arrayfields' => $arrayfields);
901 $reshook = $hookmanager->executeHooks('printFieldListOption', $parameters); // Note that $action and $object may have been modified by hook
902 print $hookmanager->resPrint;
903 // Date creation
904 if (!empty($arrayfields['m.datec']['checked'])) {
905 print '<td class="liste_titre">';
906 print '</td>';
907 }
908 // Date modification
909 if (!empty($arrayfields['m.tms']['checked'])) {
910 print '<td class="liste_titre">';
911 print '</td>';
912 }
913 // Actions
914 print '<td class="liste_titre maxwidthsearch">';
915 $searchpicto = $form->showFilterAndCheckAddButtons(0);
916 print $searchpicto;
917 print '</td>';
918 print "</tr>\n";
919
920 print '<tr class="liste_titre">';
921 if (!empty($arrayfields['m.rowid']['checked'])) {
922 print_liste_field_titre($arrayfields['m.rowid']['label'], $_SERVER["PHP_SELF"], 'm.rowid', '', $param, '', $sortfield, $sortorder);
923 }
924 if (!empty($arrayfields['m.datem']['checked'])) {
925 print_liste_field_titre($arrayfields['m.datem']['label'], $_SERVER["PHP_SELF"], 'm.datem', '', $param, '', $sortfield, $sortorder);
926 }
927 if (!empty($arrayfields['p.ref']['checked'])) {
928 print_liste_field_titre($arrayfields['p.ref']['label'], $_SERVER["PHP_SELF"], 'p.ref', '', $param, '', $sortfield, $sortorder);
929 }
930 if (!empty($arrayfields['p.label']['checked'])) {
931 print_liste_field_titre($arrayfields['p.label']['label'], $_SERVER["PHP_SELF"], 'p.label', '', $param, '', $sortfield, $sortorder);
932 }
933 if (!empty($arrayfields['m.batch']['checked'])) {
934 print_liste_field_titre($arrayfields['m.batch']['label'], $_SERVER["PHP_SELF"], 'm.batch', '', $param, '', $sortfield, $sortorder, 'center ');
935 }
936 if (!empty($arrayfields['pl.eatby']['checked'])) {
937 print_liste_field_titre($arrayfields['pl.eatby']['label'], $_SERVER["PHP_SELF"], 'pl.eatby', '', $param, '', $sortfield, $sortorder, 'center ');
938 }
939 if (!empty($arrayfields['pl.sellby']['checked'])) {
940 print_liste_field_titre($arrayfields['pl.sellby']['label'], $_SERVER["PHP_SELF"], 'pl.sellby', '', $param, '', $sortfield, $sortorder, 'center ');
941 }
942 if (!empty($arrayfields['e.ref']['checked'])) {
943 // We are on a specific warehouse card, no filter on other should be possible
944 print_liste_field_titre($arrayfields['e.ref']['label'], $_SERVER["PHP_SELF"], "e.ref", "", $param, "", $sortfield, $sortorder);
945 }
946 if (!empty($arrayfields['m.fk_user_author']['checked'])) {
947 print_liste_field_titre($arrayfields['m.fk_user_author']['label'], $_SERVER["PHP_SELF"], "m.fk_user_author", "", $param, "", $sortfield, $sortorder);
948 }
949 if (!empty($arrayfields['m.inventorycode']['checked'])) {
950 print_liste_field_titre($arrayfields['m.inventorycode']['label'], $_SERVER["PHP_SELF"], "m.inventorycode", "", $param, "", $sortfield, $sortorder);
951 }
952 if (!empty($arrayfields['m.label']['checked'])) {
953 print_liste_field_titre($arrayfields['m.label']['label'], $_SERVER["PHP_SELF"], "m.label", "", $param, "", $sortfield, $sortorder);
954 }
955 if (!empty($arrayfields['m.type_mouvement']['checked'])) {
956 print_liste_field_titre($arrayfields['m.type_mouvement']['label'], $_SERVER["PHP_SELF"], "m.type_mouvement", "", $param, '', $sortfield, $sortorder, 'center ');
957 }
958 if (!empty($arrayfields['origin']['checked'])) {
959 print_liste_field_titre($arrayfields['origin']['label'], $_SERVER["PHP_SELF"], "", "", $param, "", $sortfield, $sortorder);
960 }
961 if (!empty($arrayfields['m.value']['checked'])) {
962 print_liste_field_titre($arrayfields['m.value']['label'], $_SERVER["PHP_SELF"], "m.value", "", $param, '', $sortfield, $sortorder, 'right ');
963 }
964 if (!empty($arrayfields['m.price']['checked'])) {
965 print_liste_field_titre($arrayfields['m.price']['label'], $_SERVER["PHP_SELF"], "m.price", "", $param, '', $sortfield, $sortorder, 'right ');
966 }
967
968 // Extra fields
969 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_title.tpl.php';
970
971 // Hook fields
972 $parameters = array('arrayfields' => $arrayfields, 'param' => $param, 'sortfield' => $sortfield, 'sortorder' => $sortorder);
973 $reshook = $hookmanager->executeHooks('printFieldListTitle', $parameters); // Note that $action and $object may have been modified by hook
974 print $hookmanager->resPrint;
975 if (!empty($arrayfields['m.datec']['checked'])) {
976 print_liste_field_titre($arrayfields['m.datec']['label'], $_SERVER["PHP_SELF"], "m.datec", "", $param, '', $sortfield, $sortorder, 'center nowrap ');
977 }
978 if (!empty($arrayfields['m.tms']['checked'])) {
979 print_liste_field_titre($arrayfields['m.tms']['label'], $_SERVER["PHP_SELF"], "m.tms", "", $param, '', $sortfield, $sortorder, 'center nowrap ');
980 }
981 print_liste_field_titre($selectedfields, $_SERVER["PHP_SELF"], "", '', '', '', $sortfield, $sortorder, 'center maxwidthsearch ');
982 print "</tr>\n";
983
984
985 $arrayofuniqueproduct = array();
986 while ($i < ($limit ? min($num, $limit) : $num)) {
987 $objp = $db->fetch_object($resql);
988
989 $userstatic->id = $objp->fk_user_author;
990 $userstatic->login = $objp->login;
991 $userstatic->lastname = $objp->lastname;
992 $userstatic->firstname = $objp->firstname;
993 $userstatic->photo = $objp->photo;
994
995 $productstatic->id = $objp->rowid;
996 $productstatic->ref = $objp->product_ref;
997 $productstatic->label = $objp->produit;
998 $productstatic->type = $objp->type;
999 $productstatic->entity = $objp->entity;
1000 $productstatic->status_batch = $objp->tobatch;
1001
1002 $productlot->id = $objp->lotid;
1003 $productlot->batch = $objp->batch;
1004 $productlot->eatby = $objp->eatby;
1005 $productlot->sellby = $objp->sellby;
1006
1007 $warehousestatic->id = $objp->entrepot_id;
1008 $warehousestatic->label = $objp->warehouse_ref;
1009 $warehousestatic->lieu = $objp->lieu;
1010
1011 $arrayofuniqueproduct[$objp->rowid] = $objp->produit;
1012 if (!empty($objp->fk_origin)) {
1013 $origin = $movement->get_origin($objp->fk_origin, $objp->origintype);
1014 } else {
1015 $origin = '';
1016 }
1017
1018 print '<tr class="oddeven">';
1019 // Id movement
1020 if (!empty($arrayfields['m.rowid']['checked'])) {
1021 // This is primary not movement id
1022 print '<td>'.$objp->mid.'</td>';
1023 }
1024 if (!empty($arrayfields['m.datem']['checked'])) {
1025 // Date
1026 print '<td>'.dol_print_date($db->jdate($objp->datem), 'dayhour').'</td>';
1027 }
1028 if (!empty($arrayfields['p.ref']['checked'])) {
1029 // Product ref
1030 print '<td class="nowraponall">';
1031 print $productstatic->getNomUrl(1, 'stock', 16);
1032 print "</td>\n";
1033 }
1034 if (!empty($arrayfields['p.label']['checked'])) {
1035 // Product label
1036 print '<td>';
1037 /*$productstatic->id=$objp->rowid;
1038 $productstatic->ref=$objp->produit;
1039 $productstatic->type=$objp->type;
1040 print $productstatic->getNomUrl(1,'',16);*/
1041 print $productstatic->label;
1042 print "</td>\n";
1043 }
1044 if (!empty($arrayfields['m.batch']['checked'])) {
1045 print '<td class="center nowraponall">';
1046 if ($productlot->id > 0) {
1047 print $productlot->getNomUrl(1);
1048 } else {
1049 print $productlot->batch; // the id may not be defined if movement was entered when lot was not saved or if lot was removed after movement.
1050 }
1051 print '</td>';
1052 }
1053 if (!empty($arrayfields['pl.eatby']['checked'])) {
1054 print '<td class="center">'.dol_print_date($objp->eatby, 'day').'</td>';
1055 }
1056 if (!empty($arrayfields['pl.sellby']['checked'])) {
1057 print '<td class="center">'.dol_print_date($objp->sellby, 'day').'</td>';
1058 }
1059 // Warehouse
1060 if (!empty($arrayfields['e.ref']['checked'])) {
1061 print '<td>';
1062 print $warehousestatic->getNomUrl(1);
1063 print "</td>\n";
1064 }
1065 // Author
1066 if (!empty($arrayfields['m.fk_user_author']['checked'])) {
1067 print '<td class="tdoverflowmax100">';
1068 print $userstatic->getNomUrl(-1);
1069 print "</td>\n";
1070 }
1071 if (!empty($arrayfields['m.inventorycode']['checked'])) {
1072 // Inventory code
1073 print '<td><a href="'
1074 .DOL_URL_ROOT.'/product/stock/movement_card.php?id='.urlencode($objp->entrepot_id)
1075 .'&search_inventorycode='.urlencode($objp->inventorycode)
1076 .'&search_type_mouvement='.urlencode($objp->type_mouvement)
1077 .'">'
1078 .$objp->inventorycode
1079 .'</a></td>';
1080 }
1081 if (!empty($arrayfields['m.label']['checked'])) {
1082 // Label of movement
1083 print '<td class="tdoverflowmax100aaa">'.$objp->label.'</td>';
1084 }
1085 if (!empty($arrayfields['m.type_mouvement']['checked'])) {
1086 // Type of movement
1087 switch ($objp->type_mouvement) {
1088 case "0":
1089 print '<td class="center">'.$langs->trans('StockIncreaseAfterCorrectTransfer').'</td>';
1090 break;
1091 case "1":
1092 print '<td class="center">'.$langs->trans('StockDecreaseAfterCorrectTransfer').'</td>';
1093 break;
1094 case "2":
1095 print '<td class="center">'.$langs->trans('StockDecrease').'</td>';
1096 break;
1097 case "3":
1098 print '<td class="center">'.$langs->trans('StockIncrease').'</td>';
1099 break;
1100 }
1101 }
1102 if (!empty($arrayfields['origin']['checked'])) {
1103 // Origin of movement
1104 print '<td class="nowraponall">'.$origin.'</td>';
1105 }
1106 if (!empty($arrayfields['m.value']['checked'])) {
1107 // Qty
1108 print '<td class="right">';
1109 if ($objp->qt > 0) {
1110 print '+';
1111 }
1112 print $objp->qty;
1113 print '</td>';
1114 }
1115 if (!empty($arrayfields['m.price']['checked'])) {
1116 // Price
1117 print '<td class="right">';
1118 if ($objp->price != 0) {
1119 print price($objp->price);
1120 }
1121 print '</td>';
1122 }
1123 // Action column
1124 print '<td class="nowrap center">';
1125 if ($massactionbutton || $massaction) { // If we are in select mode (massactionbutton defined) or if we have already selected and sent an action ($massaction) defined
1126 $selected = 0;
1127 if (in_array($obj->rowid, $arrayofselected)) {
1128 $selected = 1;
1129 }
1130 print '<input id="cb'.$obj->rowid.'" class="flat checkforselect" type="checkbox" name="toselect[]" value="'.$obj->rowid.'"'.($selected ? ' checked="checked"' : '').'>';
1131 }
1132 print '</td>';
1133 if (!$i) {
1134 $totalarray['nbfield']++;
1135 }
1136
1137 print "</tr>\n";
1138 $i++;
1139 }
1140 $db->free($resql);
1141
1142 print "</table>";
1143 print '</div>';
1144 print "</form>";
1145
1146 // Add number of product when there is a filter on period
1147 if (count($arrayofuniqueproduct) == 1 && is_numeric($year)) {
1148 print "<br>";
1149
1150 $productidselected = 0;
1151 foreach ($arrayofuniqueproduct as $key => $val) {
1152 $productidselected = $key;
1153 $productlabelselected = $val;
1154 }
1155 $datebefore = dol_get_first_day($year ? $year : dol_print_date(time(), "%Y"), $month ? $month : 1, true);
1156 $dateafter = dol_get_last_day($year ? $year : dol_print_date(time(), "%Y"), $month ? $month : 12, true);
1157 $balancebefore = $movement->calculateBalanceForProductBefore($productidselected, $datebefore);
1158 $balanceafter = $movement->calculateBalanceForProductBefore($productidselected, $dateafter);
1159
1160 //print '<tr class="total"><td class="liste_total">';
1161 print $langs->trans("NbOfProductBeforePeriod", $productlabelselected, dol_print_date($datebefore, 'day', 'gmt'));
1162 //print '</td>';
1163 //print '<td class="liste_total right" colspan="6">';
1164 print ': '.$balancebefore;
1165 print "<br>\n";
1166 //print '</td></tr>';
1167 //print '<tr class="total"><td class="liste_total">';
1168 print $langs->trans("NbOfProductAfterPeriod", $productlabelselected, dol_print_date($dateafter, 'day', 'gmt'));
1169 //print '</td>';
1170 //print '<td class="liste_total right" colspan="6">';
1171 print ': '.$balanceafter;
1172 print "<br>\n";
1173 //print '</td></tr>';
1174 }
1175} else {
1176 dol_print_error($db);
1177}
1178
1179
1180
1181/*
1182 * Generated documents
1183 */
1184//Area for doc and last events of warehouse are stored on the main card of warehouse
1185$modulepart = 'movement';
1186
1187if ($action != 'create' && $action != 'edit' && $action != 'delete' && $id > 0) {
1188 print '<br>';
1189 print '<div class="fichecenter"><div class="fichehalfleft">';
1190 print '<a name="builddoc"></a>'; // ancre
1191
1192 // Documents
1193 $objectref = dol_sanitizeFileName($object->ref);
1194 // Add inventorycode & type_mouvement to filename of the pdf
1195 if (!empty($search_inventorycode)) {
1196 $objectref .= "_".$id."_".$search_inventorycode;
1197 }
1198 if ($search_type_mouvement) {
1199 $objectref .= "_".$search_type_mouvement;
1200 }
1201 $relativepath = $comref.'/'.$objectref.'.pdf';
1202 $filedir = $conf->stock->dir_output.'/movement/'.$objectref;
1203
1204 $urlsource = $_SERVER["PHP_SELF"]."?id=".$object->id."&search_inventorycode=".$search_inventorycode."&search_type_mouvement=$search_type_mouvement";
1205 $genallowed = $usercanread;
1206 $delallowed = $usercancreate;
1207
1208 $genallowed = $user->hasRight('stock', 'lire');
1209 $delallowed = $user->hasRight('stock', 'creer');
1210
1211 print $formfile->showdocuments($modulepart, $objectref, $filedir, $urlsource, $genallowed, $delallowed, '', 0, 0, 0, 28, 0, '', 0, '', $object->default_lang, '', $object);
1212 $somethingshown = $formfile->numoffiles;
1213
1214 print '</div><div class="fichehalfright">';
1215
1216 $MAXEVENT = 10;
1217
1218 $morehtmlcenter = dolGetButtonTitle($langs->trans('SeeAll'), '', 'fa fa-bars imgforviewmode', DOL_URL_ROOT.'/product/agenda.php?id='.$object->id);
1219
1220 // List of actions on element
1221 include_once DOL_DOCUMENT_ROOT.'/core/class/html.formactions.class.php';
1222 $formactions = new FormActions($db);
1223 $somethingshown = $formactions->showactions($object, 'mouvement', 0, 1, '', $MAXEVENT, '', $morehtmlcenter); // Show all action for product
1224
1225 print '</div></div>';
1226}
1227
1228
1229// End of page
1230llxFooter();
1231$db->close();
if( $user->socid > 0) if(! $user->hasRight('accounting', 'chartofaccount')) $object
Definition card.php:58
ajax_combobox($htmlname, $events=array(), $minLengthToAutocomplete=0, $forcefocus=0, $widthTypeOfAutocomplete='resolve', $idforemptyvalue='-1', $morecss='')
Convert a html select field into an ajax combobox.
Definition ajax.lib.php:456
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 warehouses.
Class to manage standard extra fields.
Class to manage building of HTML components.
Class to offer components to list and upload files.
Class to manage generation of HTML components Only common components must be here.
Class permettant la generation de composants html autre Only common components are here.
Class with static methods for building HTML components related to products Only components common to ...
Class to manage building of HTML components.
Class to manage stock movements.
Class to manage products or services.
Manage record for batch number management.
Class with list of lots and properties.
Class to manage Dolibarr users.
dolSqlDateFilter($datefield, $day_date, $month_date, $year_date, $excludefirstand=0, $gm=false)
Generate a SQL string to make a filter into a range (for second of date until last second of date).
Definition date.lib.php:378
dol_get_first_day($year, $month=1, $gm=false)
Return GMT time for first day of a month or year.
Definition date.lib.php:595
dol_get_last_day($year, $month=12, $gm=false)
Return GMT time for last day of a month or year.
Definition date.lib.php:614
dol_mktime($hour, $minute, $second, $month, $day, $year, $gm='auto', $check=1)
Return a timestamp date built from detailed information (by default a local PHP server timestamp) Rep...
GETPOSTINT($paramname, $method=0)
Return the value of a $_GET or $_POST supervariable, converted into integer.
dol_get_fiche_head($links=array(), $active='', $title='', $notab=0, $picto='', $pictoisfullpath=0, $morehtmlright='', $morecss='', $limittoshow=0, $moretabssuffix='', $dragdropfile=0)
Show tabs of a record.
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
dolGetButtonTitle($label, $helpText='', $iconClass='fa fa-file', $url='', $id='', $status=1, $params=array())
Function dolGetButtonTitle : this kind of buttons are used in title in list.
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...
price($amount, $form=0, $outlangs='', $trunc=1, $rounding=-1, $forcerounding=-1, $currency_code='')
Function to format a value into an amount for visual output Function used into PDF and HTML pages.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs=null, $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
newToken()
Return the value of token currently saved into session with name 'newtoken'.
print_liste_field_titre($name, $file="", $field="", $begin="", $moreparam="", $moreattrib="", $sortfield="", $sortorder="", $prefix="", $tooltip="", $forcenowrapcolumntitle=0)
Show title line of an array.
print_barre_liste($title, $page, $file, $options='', $sortfield='', $sortorder='', $morehtmlcenter='', $num=-1, $totalnboflines='', $picto='generic', $pictoisfullpath=0, $morehtmlright='', $morecss='', $limit=-1, $hideselectlimit=0, $hidenavigation=0, $pagenavastextinput=0, $morehtmlrightbeforearrow='')
Print a title with navigation controls for pagination.
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='', $noduplicate=0)
Set event messages in dol_events session object.
dol_sanitizeFileName($str, $newstr='_', $unaccent=1)
Clean a string to use it as a file name.
dol_print_error($db=null, $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
dol_htmlentitiesbr($stringtoencode, $nl2brmode=0, $pagecodefrom='UTF-8', $removelasteolbr=1)
This function is called to encode a string into a HTML string but differs from htmlentities because a...
getDolGlobalString($key, $default='')
Return dolibarr global constant string value.
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.
stock_prepare_head($object)
Prepare array with list of tabs.
Definition stock.lib.php:30