dolibarr 22.0.5
movement_list.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2001-2006 Rodolphe Quiedeville <rodolphe@quiedeville.org>
3 * Copyright (C) 2004-2017 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-2022 Ferran Marcet <fmarcet@2byte.es>
7 * Copyright (C) 2019-2025 Frédéric France <frederic.france@free.fr>
8 * Copyright (C) 2024-2025 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';
42require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
43if (isModEnabled('project')) {
44 require_once DOL_DOCUMENT_ROOT.'/core/class/html.formprojet.class.php';
45 require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
46}
47
56// Load translation files required by the page
57$langs->loadLangs(array('products', 'stocks', 'orders'));
58if (isModEnabled('productbatch')) {
59 $langs->load("productbatch");
60}
61
62$action = GETPOST('action', 'aZ09');
63$massaction = GETPOST('massaction', 'alpha'); // The bulk action (combo box choice into lists)
64$confirm = GETPOST('confirm', 'alpha'); // Result of a confirmation
65$cancel = GETPOST('cancel', 'alpha');
66$contextpage = GETPOST('contextpage', 'aZ') ? GETPOST('contextpage', 'aZ') : str_replace('_', '', basename(dirname(__FILE__)).basename(__FILE__, '.php')); // To manage different context of search
67$toselect = GETPOST('toselect', 'array'); // Array of ids of elements selected into a list
68$backtopage = GETPOST("backtopage", "alpha");
69$optioncss = GETPOST('optioncss', 'aZ'); // Option for the css output (always '' except when 'print')
70$show_files = GETPOST('show_files', 'aZ');
71$mode = GETPOST('mode', 'aZ'); // The output mode ('list', 'kanban', 'hierarchy', 'calendar', ...)
72
73$id = GETPOSTINT('id');
74$ref = GETPOST('ref', 'alpha');
75$msid = GETPOSTINT('msid');
76$idproduct = GETPOSTINT('idproduct');
77$product_id = GETPOSTINT('product_id');
78$show_files = GETPOSTINT('show_files');
79
80$search_all = trim(GETPOST('search_all', 'alphanohtml'));
81$search_date_startday = GETPOSTINT('search_date_startday');
82$search_date_startmonth = GETPOSTINT('search_date_startmonth');
83$search_date_startyear = GETPOSTINT('search_date_startyear');
84$search_date_endday = GETPOSTINT('search_date_endday');
85$search_date_endmonth = GETPOSTINT('search_date_endmonth');
86$search_date_endyear = GETPOSTINT('search_date_endyear');
87$search_date_start = dol_mktime(0, 0, 0, GETPOSTINT('search_date_startmonth'), GETPOSTINT('search_date_startday'), GETPOSTINT('search_date_startyear'), 'tzuserrel');
88$search_date_end = dol_mktime(23, 59, 59, GETPOSTINT('search_date_endmonth'), GETPOSTINT('search_date_endday'), GETPOSTINT('search_date_endyear'), 'tzuserrel');
89$search_ref = GETPOST('search_ref', 'alpha');
90$search_movement = GETPOST("search_movement");
91$search_product_ref = trim(GETPOST("search_product_ref"));
92$search_product = trim(GETPOST("search_product"));
93$search_warehouse = trim(GETPOST("search_warehouse"));
94$search_inventorycode = trim(GETPOST("search_inventorycode"));
95$search_user = trim(GETPOST("search_user"));
96$search_batch = trim(GETPOST("search_batch"));
97$search_qty = trim(GETPOST("search_qty"));
98$search_type_mouvement = GETPOST('search_type_mouvement');
99$search_fk_project = GETPOST("search_fk_project");
100
101$type = GETPOSTINT("type");
102
103// Load variable for pagination
104$limit = GETPOSTINT('limit') ? GETPOSTINT('limit') : $conf->liste_limit;
105$sortfield = GETPOST('sortfield', 'aZ09comma');
106$sortorder = GETPOST('sortorder', 'aZ09comma');
107$page = GETPOSTISSET('pageplusone') ? (GETPOSTINT('pageplusone') - 1) : GETPOSTINT("page");
108if (empty($page) || $page < 0 || GETPOST('button_search', 'alpha') || GETPOST('button_removefilter', 'alpha')) {
109 // If $page is not defined, or '' or -1 or if we click on clear filters
110 $page = 0;
111}
112$offset = $limit * $page;
113$pageprev = $page - 1;
114$pagenext = $page + 1;
115
116if (!$sortfield) {
117 $sortfield = "m.datem";
118}
119if (!$sortorder) {
120 $sortorder = "DESC";
121}
122
123$pdluoid = GETPOSTINT('pdluoid');
124
125// Initialize a technical objects
126$object = new MouvementStock($db);
127$extrafields = new ExtraFields($db);
128$diroutputmassaction = $conf->stock->dir_output.'/temp/massgeneration/'.$user->id;
129$hookmanager->initHooks(array($contextpage)); // Note that conf->hooks_modules contains array of activated contexes
130
131$formfile = new FormFile($db);
132
133// Fetch optionals attributes and labels
134$extrafields->fetch_name_optionals_label($object->table_element);
135
136$search_array_options = $extrafields->getOptionalsFromPost($object->table_element, '', 'search_');
137
138$arrayfields = array(
139 'm.rowid' => array('label' => "Ref", 'checked' => '1', 'position' => 1),
140 'm.datem' => array('label' => "Date", 'checked' => '1', 'position' => 2),
141 'p.ref' => array('label' => "ProductRef", 'checked' => '1', 'css' => 'maxwidth100', 'position' => 3),
142 'p.label' => array('label' => "ProductLabel", 'checked' => '0', 'position' => 5),
143 'm.batch' => array('label' => "BatchNumberShort", 'checked' => '1', 'position' => 8, 'enabled' => (string) (int) (isModEnabled('productbatch'))),
144 'pl.eatby' => array('label' => "EatByDate", 'checked' => '0', 'position' => 9, 'enabled' => (string) (int) (isModEnabled('productbatch'))),
145 'pl.sellby' => array('label' => "SellByDate", 'checked' => '0', 'position' => 10, 'enabled' => (string) (int) (isModEnabled('productbatch'))),
146 'e.ref' => array('label' => "Warehouse", 'checked' => '1', 'position' => 100, 'enabled' => (string) (int) (!($id > 0))), // If we are on specific warehouse, we hide it
147 'm.fk_user_author' => array('label' => "Author", 'checked' => '0', 'position' => 120),
148 'm.inventorycode' => array('label' => "InventoryCodeShort", 'checked' => '1', 'position' => 130),
149 'm.label' => array('label' => "MovementLabel", 'checked' => '1', 'position' => 140),
150 'm.type_mouvement' => array('label' => "TypeMovement", 'checked' => '0', 'position' => 150),
151 'origin' => array('label' => "Origin", 'checked' => '1', 'position' => 155),
152 'm.fk_projet' => array('label' => 'Project', 'checked' => '0', 'position' => 180),
153 'm.value' => array('label' => "Qty", 'checked' => '1', 'position' => 200),
154 'm.price' => array('label' => "UnitPurchaseValue", 'checked' => '0', 'position' => 210, 'enabled' => (string) (int) (!getDolGlobalInt('STOCK_MOVEMENT_LIST_HIDE_UNIT_PRICE')))
155 //'m.datec'=>array('label'=>"DateCreation", 'checked' => '0', 'position'=>500),
156 //'m.tms'=>array('label'=>"DateModificationShort", 'checked' => '0', 'position'=>500)
157);
158
159include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_array_fields.tpl.php';
160
161if (getDolGlobalString('PRODUCT_DISABLE_SELLBY')) {
162 unset($arrayfields['pl.sellby']);
163}
164if (getDolGlobalString('PRODUCT_DISABLE_EATBY')) {
165 unset($arrayfields['pl.eatby']);
166}
167
168
169$tmpwarehouse = new Entrepot($db);
170if ($id > 0 || !empty($ref)) {
171 $tmpwarehouse->fetch($id, $ref);
172 $id = $tmpwarehouse->id;
173}
174
175
176// Security check
177//$result=restrictedArea($user, 'stock', $id, 'entrepot&stock');
178$result = restrictedArea($user, 'stock');
179
180// Security check
181if (!$user->hasRight('stock', 'mouvement', 'lire')) {
183}
184
185$uploaddir = $conf->stock->dir_output.'/movements';
186
187$permissiontoread = $user->hasRight('stock', 'mouvement', 'lire');
188$permissiontoadd = $user->hasRight('stock', 'mouvement', 'creer');
189$permissiontodelete = $user->hasRight('stock', 'mouvement', 'creer'); // There is no deletion permission for stock movement as we should never delete
190$permissiontoeditextra = $permissiontoadd;
191if (GETPOST('attribute', 'aZ09') && isset($extrafields->attributes[$object->table_element]['perms'][GETPOST('attribute', 'aZ09')])) {
192 // For action 'update_extras', is there a specific permission set for the attribute to update
193 $permissiontoeditextra = dol_eval((string) $extrafields->attributes[$object->table_element]['perms'][GETPOST('attribute', 'aZ09')]);
194}
195
196$usercanread = $user->hasRight('stock', 'mouvement', 'lire');
197$usercancreate = $user->hasRight('stock', 'mouvement', 'creer');
198$usercandelete = $user->hasRight('stock', 'mouvement', 'creer');
199
200$error = 0;
201
202
203/*
204 * Actions
205 */
206
207if (GETPOST('cancel', 'alpha')) {
208 $action = 'list';
209 $massaction = '';
210}
211if (!GETPOST('confirmmassaction', 'alpha') && $massaction != 'presend' && $massaction != 'confirm_presend') {
212 $massaction = '';
213}
214
215$parameters = array();
216$reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
217if ($reshook < 0) {
218 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
219}
220
221if (empty($reshook)) {
222 // Selection of new fields
223 include DOL_DOCUMENT_ROOT.'/core/actions_changeselectedfields.inc.php';
224
225 // Purge search criteria
226 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
227 $search_date_startday = '';
228 $search_date_startmonth = '';
229 $search_date_startyear = '';
230 $search_date_endday = '';
231 $search_date_endmonth = '';
232 $search_date_endyear = '';
233 $search_date_start = '';
234 $search_date_end = '';
235 $search_ref = '';
236 $search_movement = "";
237 $search_type_mouvement = "";
238 $search_inventorycode = "";
239 $search_product_ref = "";
240 $search_product = "";
241 $search_warehouse = "";
242 $search_user = "";
243 $search_batch = "";
244 $search_qty = '';
245 $search_fk_project = "";
246 $search_all = "";
247 $toselect = array();
248 $search_array_options = array();
249 }
250 if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x', 'alpha') || GETPOST('button_removefilter', 'alpha')
251 || GETPOST('button_search_x', 'alpha') || GETPOST('button_search.x', 'alpha') || GETPOST('button_search', 'alpha')) {
252 $massaction = ''; // Protection to avoid mass action if we force a new search during a mass action confirmation
253 }
254
255 // Mass actions
256 $objectclass = 'MouvementStock';
257 $objectlabel = 'MouvementStock';
258
259 if (!$error && $massaction == "builddoc" && $permissiontoread && !GETPOST('button_search')) {
260 if (empty($diroutputmassaction)) {
261 dol_print_error(null, 'include of actions_massactions.inc.php is done but var $diroutputmassaction was not defined');
262 exit;
263 }
264
265 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
266 require_once DOL_DOCUMENT_ROOT.'/core/lib/pdf.lib.php';
267 require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
268
269 $objecttmp = new MouvementStock($db);
270 $listofobjectid = array();
271 foreach ($toselect as $toselectid) {
272 $objecttmp = new MouvementStock($db); // must create new instance because instance is saved into $listofobjectref array for future use
273 $result = $objecttmp->fetch($toselectid);
274 if ($result > 0) {
275 $listofobjectid[$toselectid] = $toselectid;
276 }
277 }
278
279 $arrayofinclusion = array();
280 foreach ($listofobjectref as $tmppdf) {
281 $arrayofinclusion[] = '^'.preg_quote(dol_sanitizeFileName($tmppdf), '/').'\.pdf$';
282 }
283 foreach ($listofobjectref as $tmppdf) {
284 $arrayofinclusion[] = '^'.preg_quote(dol_sanitizeFileName($tmppdf), '/').'_[a-zA-Z0-9-_]+\.pdf$'; // To include PDF generated from ODX files
285 }
286 $listoffiles = dol_dir_list($uploaddir, 'all', 1, implode('|', $arrayofinclusion), '\.meta$|\.png', 'date', SORT_DESC, 0, 1);
287
288 // Define output language (Here it is not used because we do only merging existing PDF)
289 $outputlangs = $langs;
290 $newlang = '';
291 if (getDolGlobalInt('MAIN_MULTILANGS') /* && empty($newlang) */ && GETPOST('lang_id', 'aZ09')) {
292 $newlang = GETPOST('lang_id', 'aZ09');
293 }
294 //elseif (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && is_object($objecttmp->thirdparty)) { // On massaction, we can have several values for $objecttmp->thirdparty
295 // $newlang = $objecttmp->thirdparty->default_lang;
296 //}
297 if (!empty($newlang)) {
298 $outputlangs = new Translate("", $conf);
299 $outputlangs->setDefaultLang($newlang);
300 }
301
302 // Create output dir if not exists
303 dol_mkdir($diroutputmassaction);
304
305 // Defined name of merged file
306 $filename = strtolower(dol_sanitizeFileName($langs->transnoentities($objectlabel)));
307 $filename = preg_replace('/\s/', '_', $filename);
308
309 // Save merged file
310 /*
311 if ($year) {
312 $filename .= '_'.$year;
313 }
314 if ($month) {
315 $filename .= '_'.$month;
316 }
317 */
318 $now = dol_now();
319 $file = $diroutputmassaction.'/'.$filename.'_'.dol_print_date($now, 'dayhourlog').'.pdf';
320
321
322 // Create PDF
323 // TODO Create the pdf including list of movement ids found into $listofobjectid
324 // ...
325
326
327 if (!$error) {
328 $langs->load("exports");
329 setEventMessage($langs->trans('FeatureNotYetAvailable'));
330 //setEventMessages($langs->trans('FileSuccessfullyBuilt', $filename.'_'.dol_print_date($now, 'dayhourlog')), null, 'mesgs');
331 }
332
333 $massaction = '';
334 $action = '';
335 }
336
337 include DOL_DOCUMENT_ROOT.'/core/actions_massactions.inc.php';
338}
339
340if ($action == 'update_extras' && $permissiontoeditextra) {
341 $tmpwarehouse->oldcopy = dol_clone($tmpwarehouse, 2); // @phan-suppress-current-line PhanTypeMismatchProperty
342
343 $attribute_name = GETPOST('attribute', 'aZ09');
344
345 // Fill array 'array_options' with data from update form
346 $ret = $extrafields->setOptionalsFromPost(null, $tmpwarehouse, $attribute_name);
347 if ($ret < 0) {
348 $error++;
349 }
350
351 if (!$error) {
352 $result = $tmpwarehouse->updateExtraField($attribute_name, 'CONTRACT_MODIFY');
353 if ($result < 0) {
354 setEventMessages($tmpwarehouse->error, $tmpwarehouse->errors, 'errors');
355 $error++;
356 }
357 }
358
359 if ($error) {
360 $action = 'edit_extras';
361 }
362}
363
364$batch = '';
365$eatby = null;
366$sellby = 0;
367$qty = 0;
368$price = '0';
369$entrepot = 0;
370
371// Correct stock
372if ($action == "correct_stock" && $permissiontoadd) {
373 $product = new Product($db);
374 if (!empty($product_id)) {
375 $result = $product->fetch($product_id);
376 }
377
378 $error = 0;
379
380 if (empty($product_id)) {
381 $error++;
382 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Product")), null, 'errors');
383 $action = 'correction';
384 }
385 if (!GETPOSTFLOAT("nbpiece")) {
386 $error++;
387 setEventMessages($langs->trans("ErrorFieldMustBeANumeric", $langs->transnoentitiesnoconv("NumberOfUnit")), null, 'errors');
388 $action = 'correction';
389 }
390
391 if (!$error) {
392 $origin_element = '';
393 $origin_id = null;
394
395 if (GETPOSTINT('projectid')) {
396 $origin_element = 'project';
397 $origin_id = GETPOSTINT('projectid');
398 }
399
400 if ($product->hasbatch()) {
401 $batch = GETPOST('batch_number', 'alphanohtml');
402
403 $eatby = dol_mktime(0, 0, 0, GETPOSTINT('eatbymonth'), GETPOSTINT('eatbyday'), GETPOSTINT('eatbyyear'));
404 $sellby = dol_mktime(0, 0, 0, GETPOSTINT('sellbymonth'), GETPOSTINT('sellbyday'), GETPOSTINT('sellbyyear'));
405
406 $result = $product->correct_stock_batch(
407 $user,
408 $id,
409 GETPOSTFLOAT("nbpiece"),
410 GETPOSTINT("mouvement"),
411 GETPOST("label", 'alphanohtml'),
412 (float) price2num(GETPOST('unitprice'), 'MT'),
413 $eatby,
414 $sellby,
415 $batch,
416 GETPOST('inventorycode', 'alphanohtml'),
417 $origin_element,
418 $origin_id,
419 0,
420 $extrafields
421 ); // We do not change value of stock for a correction
422 } else {
423 $result = $product->correct_stock(
424 $user,
425 $id,
426 GETPOSTFLOAT("nbpiece"),
427 GETPOSTINT("mouvement"),
428 GETPOST("label", 'alphanohtml'),
429 (float) price2num(GETPOST('unitprice'), 'MT'),
430 GETPOST('inventorycode', 'alphanohtml'),
431 $origin_element,
432 $origin_id,
433 0,
434 $extrafields
435 ); // We do not change value of stock for a correction
436 }
437
438 if ($result > 0) {
439 header("Location: ".$_SERVER["PHP_SELF"]."?id=".$id);
440 exit;
441 } else {
442 $error++;
443 setEventMessages($product->error, $product->errors, 'errors');
444 $action = 'correction';
445 }
446 }
447
448 if (!$error) {
449 $action = '';
450 }
451}
452
453// Transfer stock from a warehouse to another warehouse
454if ($action == "transfert_stock" && $permissiontoadd && !$cancel) {
455 $error = 0;
456 $product = new Product($db);
457 if (!empty($product_id)) {
458 $result = $product->fetch($product_id);
459 }
460
461 if (!(GETPOSTINT("id_entrepot_destination") > 0)) {
462 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Warehouse")), null, 'errors');
463 $error++;
464 $action = 'transfert';
465 }
466 if (empty($product_id)) {
467 $error++;
468 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Product")), null, 'errors');
469 $action = 'transfert';
470 }
471 if (!GETPOSTFLOAT("nbpiece")) {
472 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("NumberOfUnit")), null, 'errors');
473 $error++;
474 $action = 'transfert';
475 }
476 if ($id == GETPOSTINT("id_entrepot_destination")) {
477 setEventMessages($langs->trans("ErrorSrcAndTargetWarehouseMustDiffers"), null, 'errors');
478 $error++;
479 $action = 'transfert';
480 }
481
482 if (isModEnabled('productbatch')) {
483 $product = new Product($db);
484 $result = $product->fetch($product_id);
485
486 if ($product->hasbatch() && !GETPOST("batch_number")) {
487 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("batch_number")), null, 'errors');
488 $error++;
489 $action = 'transfert';
490 }
491 }
492
493 if (!$error) {
494 if ($id) {
495 $warehouse = new Entrepot($db);
496 $result = $warehouse->fetch($id);
497
498 $db->begin();
499
500 $product->load_stock('novirtual'); // Load array product->stock_warehouse
501
502 // Define value of products moved
503 $pricesrc = 0;
504 if (isset($product->pmp)) {
505 $pricesrc = $product->pmp;
506 }
507 $pricedest = $pricesrc;
508
509 if ($product->hasbatch()) {
510 $pdluo = new Productbatch($db);
511 $srcwarehouseid = 0;
512
513 $eatby = dol_mktime(0, 0, 0, GETPOSTINT('eatbymonth'), GETPOSTINT('eatbyday'), GETPOSTINT('eatbyyear'));
514 $sellby = dol_mktime(0, 0, 0, GETPOSTINT('sellbymonth'), GETPOSTINT('sellbyday'), GETPOSTINT('sellbyyear'));
515
516 if ($pdluoid > 0) {
517 $result = $pdluo->fetch($pdluoid);
518 if ($result) {
519 $srcwarehouseid = $pdluo->warehouseid;
520 $batch = $pdluo->batch;
521 } else {
522 setEventMessages($pdluo->error, $pdluo->errors, 'errors');
523 $error++;
524 }
525 } else {
526 $srcwarehouseid = $id;
527 $batch = GETPOST('batch_number', 'alphanohtml');
528 }
529
530 $result1 = -1;
531 $result2 = -1;
532 if (!$error) {
533 // Remove stock
534 $result1 = $product->correct_stock_batch(
535 $user,
536 $srcwarehouseid,
537 GETPOSTFLOAT("nbpiece"),
538 1,
539 GETPOST("label", 'san_alpha'),
540 (float) $pricesrc,
541 $eatby,
542 $sellby,
543 $batch,
544 GETPOST('inventorycode'),
545 '',
546 null,
547 0,
548 $extrafields
549 );
550 // Add stock
551 $result2 = $product->correct_stock_batch(
552 $user,
553 GETPOSTINT("id_entrepot_destination"),
554 GETPOSTFLOAT("nbpiece"),
555 0,
556 GETPOST("label", 'san_alpha'),
557 (float) $pricedest,
558 $eatby,
559 $sellby,
560 $batch,
561 GETPOST('inventorycode', 'alphanohtml'),
562 '',
563 null,
564 0,
565 $extrafields
566 );
567 }
568 } else {
569 // Remove stock
570 $result1 = $product->correct_stock(
571 $user,
572 $id,
573 GETPOSTFLOAT("nbpiece"),
574 1,
575 GETPOST("label", 'alphanohtml'),
576 (float) $pricesrc,
577 GETPOST('inventorycode', 'alphanohtml'),
578 '',
579 null,
580 0,
581 $extrafields
582 );
583
584 // Add stock
585 $result2 = $product->correct_stock(
586 $user,
587 GETPOSTINT("id_entrepot_destination"),
588 GETPOSTFLOAT("nbpiece"),
589 0,
590 GETPOST("label", 'alphanohtml'),
591 (float) $pricedest,
592 GETPOST('inventorycode', 'alphanohtml'),
593 '',
594 null,
595 0,
596 $extrafields
597 );
598 }
599 if (!$error && $result1 >= 0 && $result2 >= 0) {
600 $db->commit();
601
602 if ($backtopage) {
603 header("Location: ".$backtopage);
604 exit;
605 } else {
606 header("Location: movement_list.php?id=".$warehouse->id);
607 exit;
608 }
609 } else {
610 setEventMessages($product->error, $product->errors, 'errors');
611 $db->rollback();
612 $action = 'transfert';
613 }
614 }
615 }
616}
617
618// reverse movement of stock
619if ($action == 'confirm_reverse' && $confirm == "yes" && $permissiontoadd) {
620 $toselect = array_map('intval', $toselect);
621
622 $db->begin();
623
624 $sql = "SELECT rowid, label, inventorycode, datem";
625 $sql .= " FROM ".MAIN_DB_PREFIX."stock_mouvement";
626 $sql .= " WHERE rowid IN (".$db->sanitize(implode(',', $toselect)).")";
627
628 $resql = $db->query($sql);
629 if ($resql) {
630 $num = $db->num_rows($resql);
631 $i = 0;
632 $error =0;
633 while ($i < $num) {
634 $obj = $db->fetch_object($resql);
635
636 $object->id = 0;
637 $object->fetch($obj->rowid); // $object is MouvementStock
638
639 // TODO Add a protection to disallow reversion if type of movement is not the same value for all selected lines
640
641 // Create the reverse movement
642 $reverse = $object->reverseMovement();
643 if ($reverse < 0) {
644 setEventMessages($object->error, $object->errors, 'errors');
645 $error++;
646 break;
647 }
648 $i++;
649 }
650 } else {
651 setEventMessages($db->lasterror(), null, 'errors');
652 $error++;
653 }
654
655 if (!$error) {
656 setEventMessages($langs->trans("ReverseConfirmed"), null);
657 $db->commit();
658 } else {
659 $db->rollback();
660 }
661
662 header("Location: ".$_SERVER["PHP_SELF"]);
663 exit;
664}
665
666/*
667 * View
668 */
669
670$form = new Form($db);
671$formproduct = new FormProduct($db);
672if (isModEnabled('project')) {
673 $formproject = new FormProjets($db);
674} else {
675 $formproject = null;
676}
677$productlot = new Productlot($db);
678$productstatic = new Product($db);
679$warehousestatic = new Entrepot($db);
680
681$userstatic = new User($db);
682
683$now = dol_now();
684
685// Build and execute select
686// --------------------------------------------------------------------
687$sql = "SELECT p.rowid, p.ref as product_ref, p.label as produit, p.tosell, p.tobuy, p.tobatch, p.fk_product_type as type, p.entity,";
688$sql .= " e.ref as warehouse_ref, e.rowid as entrepot_id, e.lieu, e.fk_parent, e.statut,";
689$sql .= " m.rowid as mid, m.value as qty, m.datem, m.fk_user_author, m.label, m.inventorycode, m.fk_origin, m.origintype,";
690$sql .= " m.batch, m.price,";
691$sql .= " m.type_mouvement,";
692$sql .= " m.fk_projet as fk_project,";
693$sql .= " pl.rowid as lotid, pl.eatby, pl.sellby,";
694$sql .= " u.login, u.photo, u.lastname, u.firstname, u.email as user_email, u.statut as user_status";
695// Add fields from extrafields
696if (!empty($extrafields->attributes[$object->table_element]['label'])) {
697 foreach ($extrafields->attributes[$object->table_element]['label'] as $key => $val) {
698 $sql .= ($extrafields->attributes[$object->table_element]['type'][$key] != 'separate' ? ", ef.".$key." as options_".$key : '');
699 }
700}
701// Add fields from hooks
702$parameters = array();
703$reshook = $hookmanager->executeHooks('printFieldListSelect', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
704$sql .= $hookmanager->resPrint;
705$sql = preg_replace('/,\s*$/', '', $sql);
706
707$sqlfields = $sql; // $sql fields to remove for count total
708
709$sql .= " FROM ".MAIN_DB_PREFIX."entrepot as e,";
710$sql .= " ".MAIN_DB_PREFIX."product as p,";
711$sql .= " ".MAIN_DB_PREFIX."stock_mouvement as m";
712if (!empty($extrafields->attributes[$object->table_element]['label']) && is_array($extrafields->attributes[$object->table_element]['label']) && count($extrafields->attributes[$object->table_element]['label'])) {
713 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX.$object->table_element."_extrafields as ef on (m.rowid = ef.fk_object)";
714}
715$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."user as u ON m.fk_user_author = u.rowid";
716$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product_lot as pl ON m.batch = pl.batch AND m.fk_product = pl.fk_product";
717
718// Add table from hooks
719$parameters = array();
720$reshook = $hookmanager->executeHooks('printFieldListFrom', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
721$sql .= $hookmanager->resPrint;
722
723$sql .= " WHERE m.fk_product = p.rowid";
724if ($msid > 0) {
725 $sql .= " AND m.rowid = ".((int) $msid);
726}
727$sql .= " AND m.fk_entrepot = e.rowid";
728$sql .= " AND e.entity IN (".getEntity('stock').")";
729if (!getDolGlobalString('STOCK_SUPPORTS_SERVICES')) {
730 $sql .= " AND p.fk_product_type = 0";
731}
732if ($id > 0) {
733 $sql .= " AND e.rowid = ".((int) $id);
734}
735if (!empty($search_date_start)) {
736 $sql .= " AND m.datem >= '" . $db->idate($search_date_start) . "'";
737}
738if (!empty($search_date_end)) {
739 $sql .= " AND m.datem <= '" . $db->idate($search_date_end) . "'";
740}
741if ($idproduct > 0) {
742 $sql .= " AND p.rowid = ".((int) $idproduct);
743}
744if (!empty($search_ref)) {
745 $sql .= natural_search('m.rowid', $search_ref, 1);
746}
747if (!empty($search_movement)) {
748 $sql .= natural_search('m.label', $search_movement);
749}
750if (!empty($search_inventorycode)) {
751 $sql .= natural_search('m.inventorycode', $search_inventorycode);
752}
753if (!empty($search_product_ref)) {
754 $sql .= natural_search('p.ref', $search_product_ref);
755}
756if (!empty($search_product)) {
757 $sql .= natural_search('p.label', $search_product);
758}
759if ($search_warehouse != '' && $search_warehouse != '-1') {
760 $sql .= natural_search('e.rowid', $search_warehouse, 2);
761}
762if (!empty($search_user)) {
763 $sql .= natural_search(array('u.lastname', 'u.firstname', 'u.login'), $search_user);
764}
765if (!empty($search_batch)) {
766 $sql .= natural_search('m.batch', $search_batch);
767}
768if (!empty($product_id) && $product_id != '-1') {
769 $sql .= natural_search('p.rowid', (string) $product_id);
770}
771if (!empty($search_fk_project) && $search_fk_project != '-1') {
772 $sql .= natural_search('m.fk_projet', $search_fk_project);
773}
774if ($search_qty != '') {
775 $sql .= natural_search('m.value', $search_qty, 1);
776}
777if ($search_type_mouvement != '' && $search_type_mouvement != '-1') {
778 $sql .= natural_search('m.type_mouvement', $search_type_mouvement, 2);
779}
780// Add where from extra fields
781include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_sql.tpl.php';
782// Add where from hooks
783$parameters = array();
784$reshook = $hookmanager->executeHooks('printFieldListWhere', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
785$sql .= $hookmanager->resPrint;
786
787// Count total nb of records
788$nbtotalofrecords = '';
789if (!getDolGlobalInt('MAIN_DISABLE_FULL_SCANLIST')) {
790 /* The fast and low memory method to get and count full list converts the sql into a sql count */
791 $sqlforcount = preg_replace('/^'.preg_quote($sqlfields, '/').'/', 'SELECT COUNT(*) as nbtotalofrecords', $sql);
792 $sqlforcount = preg_replace('/GROUP BY .*$/', '', $sqlforcount);
793 $resql = $db->query($sqlforcount);
794 if ($resql) {
795 $objforcount = $db->fetch_object($resql);
796 $nbtotalofrecords = $objforcount->nbtotalofrecords;
797 } else {
798 dol_print_error($db);
799 }
800
801 if (($page * $limit) > $nbtotalofrecords) { // if total resultset is smaller than the paging size (filtering), goto and load page 0
802 $page = 0;
803 $offset = 0;
804 }
805 $db->free($resql);
806}
807
808// Complete request and execute it with limit
809$sql .= $db->order($sortfield, $sortorder);
810if ($limit) {
811 $sql .= $db->plimit($limit + 1, $offset);
812}
813
814$resql = $db->query($sql);
815if (!$resql) {
816 dol_print_error($db);
817 exit;
818}
819
820$num = $db->num_rows($resql);
821
822
823$product = new Product($db);
824$warehouse = new Entrepot($db);
825
826if ($idproduct > 0) {
827 $product->fetch($idproduct);
828}
829if ($id > 0 || $ref) {
830 $result = $warehouse->fetch($id, $ref);
831 if ($result < 0) {
832 dol_print_error($db);
833 }
834}
835
836$i = 0;
837$help_url = 'EN:Module_Stocks_En|FR:Module_Stock|ES:M&oacute;dulo_Stocks';
838if ($msid) {
839 $title = $langs->trans('StockMovementForId', $msid);
840} else {
841 $title = $langs->trans("StockMovements");
842 if ($id) {
843 if (!empty($warehouse->ref)) {
844 $title .= ' ('.$warehouse->ref.')';
845 } else {
846 $title .= ' ('.$langs->trans("ForThisWarehouse").')';
847 }
848 }
849}
850
851
852// Output page
853// --------------------------------------------------------------------
854
855llxHeader('', $title, $help_url, '', 0, 0, '', '', '', 'bodyforlist mod-product page-stock_movement_list');
856
857/*
858 * Show tab only if we ask a particular warehouse
859 */
860if ($warehouse->id > 0) {
861 $head = stock_prepare_head($warehouse);
862
863 print dol_get_fiche_head($head, 'movements', $langs->trans("Warehouse"), -1, 'stock');
864
865
866 $linkback = '<a href="'.DOL_URL_ROOT.'/product/stock/list.php?restore_lastsearch_values=1">'.$langs->trans("BackToList").'</a>';
867
868 $morehtmlref = '<div class="refidno">';
869 $morehtmlref .= $langs->trans("LocationSummary").' : '.$warehouse->lieu;
870
871 // Project
872 if (isModEnabled('project') && $formproject !== null) {
873 $langs->load("projects");
874 $morehtmlref .= '<br>'.img_picto('', 'project').' '.$langs->trans('Project').' ';
875 if ($usercancreate && 1 == 2) { // @phan-suppress-current-line PhanPluginBothLiteralsBinaryOp
876 if ($action != 'classify') {
877 $morehtmlref .= '<a class="editfielda" href="'.$_SERVER['PHP_SELF'].'?action=classify&token='.newToken().'&id='.$warehouse->id.'">'.img_edit($langs->transnoentitiesnoconv('SetProject')).'</a> : ';
878 }
879 if ($action == 'classify') {
880 $projectid = $warehouse->fk_project;
881 $morehtmlref .= '<form method="post" action="'.$_SERVER['PHP_SELF'].'?id='.$warehouse->id.'">';
882 $morehtmlref .= '<input type="hidden" name="action" value="classin">';
883 $morehtmlref .= '<input type="hidden" name="token" value="'.newToken().'">';
884 $morehtmlref .= $formproject->select_projects(($socid > 0 ? $socid : -1), (string) $projectid, 'projectid', 0, 0, 1, 1, 0, 0, 0, '', 1, 0, 'maxwidth500');
885 $morehtmlref .= '<input type="submit" class="button valignmiddle" value="'.$langs->trans("Modify").'">';
886 $morehtmlref .= '</form>';
887 } else {
888 $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'].'?id='.$warehouse->id, $warehouse->socid, (string) $warehouse->fk_project, 'none', 0, 0, 0, 1, '', 'maxwidth300');
889 }
890 } else {
891 if (!empty($warehouse->fk_project)) {
892 $proj = new Project($db);
893 $proj->fetch($warehouse->fk_project);
894 $morehtmlref .= ' : '.$proj->getNomUrl(1);
895 if ($proj->title) {
896 $morehtmlref .= ' - '.$proj->title;
897 }
898 } else {
899 $morehtmlref .= '';
900 }
901 }
902 }
903 $morehtmlref .= '</div>';
904
905 $shownav = 1;
906 if ($user->socid && !in_array('stock', explode(',', getDolGlobalString('MAIN_MODULES_FOR_EXTERNAL')))) {
907 $shownav = 0;
908 }
909
910 dol_banner_tab($warehouse, 'ref', $linkback, $shownav, 'ref', 'ref', $morehtmlref);
911
912
913 print '<div class="fichecenter">';
914 print '<div class="fichehalfleft">';
915 print '<div class="underbanner clearboth"></div>';
916
917 print '<table class="border centpercent tableforfield">';
918
919 print '<tr>';
920
921 // Description
922 print '<td class="titlefield tdtop">'.$langs->trans("Description").'</td><td>'.dol_htmlentitiesbr($warehouse->description).'</td></tr>';
923
924 $calcproductsunique = $warehouse->nb_different_products();
925 $calcproducts = $warehouse->nb_products();
926
927 // Total nb of different products
928 print '<tr><td>'.$langs->trans("NumberOfDifferentProducts").'</td><td>';
929 print empty($calcproductsunique['nb']) ? '0' : $calcproductsunique['nb'];
930 print "</td></tr>";
931
932 // Nb of products
933 print '<tr><td>'.$langs->trans("NumberOfProducts").'</td><td>';
934 $valtoshow = price2num($calcproducts['nb'], 'MS');
935 print empty($valtoshow) ? '0' : $valtoshow;
936 print "</td></tr>";
937
938 print '</table>';
939
940 print '</div>';
941 print '<div class="fichehalfright">';
942 print '<div class="underbanner clearboth"></div>';
943
944 print '<table class="border centpercent tableforfield">';
945
946 // Value
947 print '<tr><td class="titlefield">'.$langs->trans("EstimatedStockValueShort").'</td><td>';
948 print price((empty($calcproducts['value']) ? '0' : price2num($calcproducts['value'], 'MT')), 0, $langs, 0, -1, -1, $conf->currency);
949 print "</td></tr>";
950
951 // Last movement
952 $sql = "SELECT MAX(m.datem) as datem";
953 $sql .= " FROM ".MAIN_DB_PREFIX."stock_mouvement as m";
954 $sql .= " WHERE m.fk_entrepot = ".((int) $warehouse->id);
955 $resqlbis = $db->query($sql);
956
957 $lastmovementdate = 0;
958 if ($resqlbis) {
959 $objbis = $db->fetch_object($resqlbis);
960 $lastmovementdate = $db->jdate($objbis->datem);
961 } else {
962 dol_print_error($db);
963 }
964
965 print '<tr><td>'.$langs->trans("LastMovement").'</td><td>';
966 if ($lastmovementdate) {
967 print dol_print_date($lastmovementdate, 'dayhour');
968 } else {
969 print $langs->trans("None");
970 }
971 print "</td></tr>";
972
973 // Other attributes
974 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_view.tpl.php';
975
976 // Categories
977 if (isModEnabled('category')) {
978 print '<tr><td valign="middle">'.$langs->trans("Categories").'</td><td colspan="3">';
979 print $form->showCategories($warehouse->id, Categorie::TYPE_WAREHOUSE, 1);
980 print "</td></tr>";
981 }
982
983 print "</table>";
984
985 print '</div>';
986 print '</div>';
987
988 print '<div class="clearboth"></div>';
989
990 print dol_get_fiche_end();
991}
992
993
994// Correct stock
995if ($action == "correction") {
996 include DOL_DOCUMENT_ROOT.'/product/stock/tpl/stockcorrection.tpl.php';
997 print '<br>';
998}
999
1000// Transfer of units
1001if ($action == "transfert") {
1002 $d_eatby = GETPOSTDATE('eatby'); // used by the tpl
1003 $d_sellby = GETPOSTDATE('sellby'); // used by the tpl
1004 include DOL_DOCUMENT_ROOT.'/product/stock/tpl/stocktransfer.tpl.php';
1005 print '<br>';
1006}
1007
1008
1009// Action bar
1010if ((empty($action) || $action == 'list') && $id > 0) {
1011 print "<div class=\"tabsAction\">\n";
1012
1013 $parameters = array();
1014 $reshook = $hookmanager->executeHooks('addMoreActionsButtons', $parameters, $warehouse, $action); // Note that $action and $warehouse may have been
1015 // modified by hook
1016 if (empty($reshook)) {
1017 if ($user->hasRight('stock', 'mouvement', 'creer')) {
1018 print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?id='.$id.'&action=transfert&token='.newToken().'">'.$langs->trans("TransferStock").'</a>';
1019 }
1020
1021 if ($user->hasRight('stock', 'mouvement', 'creer')) {
1022 print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?id='.$id.'&action=correction&token='.newToken().'">'.$langs->trans("CorrectStock").'</a>';
1023 }
1024 }
1025
1026 print '</div><br>';
1027}
1028
1029$arrayofselected = is_array($toselect) ? $toselect : array();
1030
1031$param = '';
1032if (!empty($mode)) {
1033 $param .= '&mode='.urlencode($mode);
1034}
1035if (!empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) {
1036 $param .= '&contextpage='.urlencode($contextpage);
1037}
1038if ($limit > 0 && $limit != $conf->liste_limit) {
1039 $param .= '&limit='.((int) $limit);
1040}
1041if ($id > 0) {
1042 $param .= '&id='.urlencode((string) ($id));
1043}
1044if ($show_files) {
1045 $param .= '&show_files='.urlencode((string) ($show_files));
1046}
1047if ($search_date_startday) {
1048 $param .= '&search_date_startday='.urlencode((string) ($search_date_startday));
1049}
1050if ($search_date_startmonth) {
1051 $param .= '&search_date_startmonth='.urlencode((string) ($search_date_startmonth));
1052}
1053if ($search_date_startyear) {
1054 $param .= '&search_date_startyear='.urlencode((string) ($search_date_startyear));
1055}
1056if ($search_date_endday) {
1057 $param .= '&search_date_endday='.urlencode((string) ($search_date_endday));
1058}
1059if ($search_date_endmonth) {
1060 $param .= '&search_date_endmonth='.urlencode((string) ($search_date_endmonth));
1061}
1062if ($search_date_endyear) {
1063 $param .= '&search_date_endyear='.urlencode((string) ($search_date_endyear));
1064}
1065if ($search_movement) {
1066 $param .= '&search_movement='.urlencode($search_movement);
1067}
1068if ($search_inventorycode) {
1069 $param .= '&search_inventorycode='.urlencode($search_inventorycode);
1070}
1071if ($search_type_mouvement) {
1072 $param .= '&search_type_mouvement='.urlencode($search_type_mouvement);
1073}
1074if ($search_product_ref) {
1075 $param .= '&search_product_ref='.urlencode($search_product_ref);
1076}
1077if ($search_product) {
1078 $param .= '&search_product='.urlencode($search_product);
1079}
1080if ($search_batch) {
1081 $param .= '&search_batch='.urlencode($search_batch);
1082}
1083if ($search_warehouse > 0) {
1084 $param .= '&search_warehouse='.urlencode($search_warehouse);
1085}
1086if ($search_user) {
1087 $param .= '&search_user='.urlencode($search_user);
1088}
1089if ($idproduct > 0) {
1090 $param .= '&idproduct='.urlencode((string) ($idproduct));
1091}
1092if ($search_fk_project != '' && $search_fk_project != '-1') {
1093 $param .= '&search_fk_project='.urlencode((string) ($search_fk_project));
1094}
1095// Add $param from extra fields
1096include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_param.tpl.php';
1097// Add $param from hooks
1098$parameters = array('param' => &$param);
1099$reshook = $hookmanager->executeHooks('printFieldListSearchParam', $parameters, $warehouse, $action); // Note that $action and $warehouse may have been modified by hook
1100$param .= $hookmanager->resPrint;
1101
1102// List of mass actions available
1103$arrayofmassactions = array();
1104if (getDolGlobalInt('MAIN_FEATURES_LEVEL') >= 2) {
1105 $arrayofmassactions['builddoc'] = img_picto('', 'pdf', 'class="pictofixedwidth"').$langs->trans("GeneratePDF");
1106}
1107// By default, we should never accept deletion of stock movement
1108if (getDolGlobalString('STOCK_ALLOW_DELETE_OF_MOVEMENT') && $permissiontodelete) {
1109 $arrayofmassactions['predelete'] = img_picto('', 'delete', 'class="pictofixedwidth"').$langs->trans("Delete");
1110}
1111if (!empty($permissiontoadd)) {
1112 $arrayofmassactions['prereverse'] = img_picto('', 'add', 'class="pictofixedwidth"').$langs->trans("Reverse");
1113}
1114if (GETPOSTINT('nomassaction') || in_array($massaction, array('presend', 'predelete', 'prereverse'))) {
1115 $arrayofmassactions = array();
1116}
1117
1118$massactionbutton = $form->selectMassAction('', $arrayofmassactions);
1119
1120print '<form method="POST" id="searchFormList" action="'.$_SERVER["PHP_SELF"].'">'."\n";
1121if ($optioncss != '') {
1122 print '<input type="hidden" name="optioncss" value="'.$optioncss.'">';
1123}
1124print '<input type="hidden" name="token" value="'.newToken().'">';
1125print '<input type="hidden" name="formfilteraction" id="formfilteraction" value="list">';
1126print '<input type="hidden" name="action" value="list">';
1127print '<input type="hidden" name="sortfield" value="'.$sortfield.'">';
1128print '<input type="hidden" name="sortorder" value="'.$sortorder.'">';
1129print '<input type="hidden" name="type" value="'.$type.'">';
1130print '<input type="hidden" name="page" value="'.$page.'">';
1131print '<input type="hidden" name="contextpage" value="'.$contextpage.'">';
1132print '<input type="hidden" name="page_y" value="">';
1133print '<input type="hidden" name="mode" value="'.$mode.'">';
1134if ($id > 0) {
1135 print '<input type="hidden" name="id" value="'.$id.'">';
1136}
1137
1138
1139$newcardbutton = '';
1140
1141print_barre_liste($title, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $massactionbutton, $num, $nbtotalofrecords, 'movement', 0, '', '', $limit, 0, 0, 1);
1142
1143// Add code for pre mass action (confirmation or email presend form)
1144$topicmail = "SendStockMovement";
1145$modelmail = "movementstock";
1146$objecttmp = new MouvementStock($db);
1147$trackid = 'mov'.$warehouse->id;
1148include DOL_DOCUMENT_ROOT.'/core/tpl/massactions_pre.tpl.php';
1149if ($massaction == 'prereverse') {
1150 print $form->formconfirm($_SERVER["PHP_SELF"], $langs->trans("ConfirmMassReverse"), $langs->trans("ConfirmMassReverseQuestion", count($toselect)), "confirm_reverse", null, '', 0, 200, 500, 1, 'Yes');
1151}
1152
1153
1154if ($search_all) {
1155 $setupstring = '';
1156 if (!isset($fieldstosearchall) || !is_array($fieldstosearchall)) {
1157 // Ensure $fieldstosearchall is array
1158 $fieldstosearchall = array();
1159 }
1160 foreach ($fieldstosearchall as $key => $val) {
1161 $fieldstosearchall[$key] = $langs->trans($val);
1162 $setupstring .= $key."=".$val.";";
1163 }
1164 print '<!-- Search done like if STOCK_QUICKSEARCH_ON_FIELDS = '.$setupstring.' -->'."\n";
1165 print '<div class="divsearchfieldfilter">'.$langs->trans("FilterOnInto", $search_all).implode(', ', $fieldstosearchall).'</div>'."\n";
1166}
1167
1168$moreforfilter = '';
1169
1170$parameters = array('arrayfields' => &$arrayfields);
1171$reshook = $hookmanager->executeHooks('printFieldPreListTitle', $parameters, $warehouse, $action); // Note that $action and $warehouse may have been modified by hook
1172if (empty($reshook)) {
1173 $moreforfilter .= $hookmanager->resPrint;
1174} else {
1175 $moreforfilter = $hookmanager->resPrint;
1176}
1177
1178if (!empty($moreforfilter)) {
1179 print '<div class="liste_titre liste_titre_bydiv centpercent">';
1180 print $moreforfilter;
1181 print '</div>';
1182}
1183
1184$varpage = empty($contextpage) ? $_SERVER["PHP_SELF"] : $contextpage;
1185$htmlofselectarray = $form->multiSelectArrayWithCheckbox('selectedfields', $arrayfields, $varpage, getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')); // This also change content of $arrayfields with user setup
1186$selectedfields = ($mode != 'kanban' ? $htmlofselectarray : '');
1187$selectedfields .= (count($arrayofmassactions) ? $form->showCheckAddButtons('checkforselect', 1) : '');
1188
1189print '<div class="div-table-responsive">'; // You can use div-table-responsive-no-min if you don't need reserved height for your table
1190print '<table class="tagtable nobottomiftotal liste'.($moreforfilter ? " listwithfilterbefore" : "").'">'."\n";
1191
1192// Fields title search
1193// --------------------------------------------------------------------
1194print '<tr class="liste_titre_filter">';
1195// Action column
1196if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
1197 print '<td class="liste_titre center maxwidthsearch">';
1198 $searchpicto = $form->showFilterButtons('left');
1199 print $searchpicto;
1200 print '</td>';
1201}
1202if (!empty($arrayfields['m.rowid']['checked'])) {
1203 // Ref
1204 print '<td class="liste_titre left">';
1205 print '<input class="flat maxwidth40" type="text" name="search_ref" value="'.dol_escape_htmltag($search_ref).'">';
1206 print '</td>';
1207}
1208if (!empty($arrayfields['m.datem']['checked'])) {
1209 // Date
1210 print '<td class="liste_titre center">';
1211 print '<div class="nowrapfordate">';
1212 print $form->selectDate($search_date_start ? $search_date_start : -1, 'search_date_start', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans('From'), 'tzuserrel');
1213 print '</div>';
1214 print '<div class="nowrapfordate">';
1215 print $form->selectDate($search_date_end ? $search_date_end : -1, 'search_date_end', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans('to'), 'tzuserrel');
1216 print '</div>';
1217 print '</td>';
1218}
1219if (!empty($arrayfields['p.ref']['checked'])) {
1220 // Product Ref
1221 print '<td class="liste_titre left">';
1222 print '<input class="flat maxwidth75" type="text" name="search_product_ref" value="'.dol_escape_htmltag($idproduct ? $product->ref : $search_product_ref).'">';
1223 print '</td>';
1224}
1225if (!empty($arrayfields['p.label']['checked'])) {
1226 // Product label
1227 print '<td class="liste_titre left">';
1228 print '<input class="flat maxwidth100" type="text" name="search_product" value="'.dol_escape_htmltag($idproduct ? $product->label : $search_product).'">';
1229 print '</td>';
1230}
1231// Batch
1232if (!empty($arrayfields['m.batch']['checked'])) {
1233 print '<td class="liste_titre center"><input class="flat maxwidth75" type="text" name="search_batch" value="'.dol_escape_htmltag($search_batch).'"></td>';
1234}
1235if (!empty($arrayfields['pl.eatby']['checked'])) {
1236 print '<td class="liste_titre left">';
1237 print '</td>';
1238}
1239if (!empty($arrayfields['pl.sellby']['checked'])) {
1240 print '<td class="liste_titre left">';
1241 print '</td>';
1242}
1243// Warehouse
1244if (!empty($arrayfields['e.ref']['checked'])) {
1245 print '<td class="liste_titre maxwidthonsmartphone left">';
1246 //print '<input class="flat" type="text" size="8" name="search_warehouse" value="'.($search_warehouse).'">';
1247 print $formproduct->selectWarehouses($search_warehouse, 'search_warehouse', 'warehouseopen,warehouseinternal', 1, 0, 0, '', 0, 0, array(), 'maxwidth150');
1248 print '</td>';
1249}
1250if (!empty($arrayfields['m.fk_user_author']['checked'])) {
1251 // Author
1252 print '<td class="liste_titre left">';
1253 print '<input class="flat" type="text" size="6" name="search_user" value="'.dol_escape_htmltag($search_user).'">';
1254 print '</td>';
1255}
1256if (!empty($arrayfields['m.inventorycode']['checked'])) {
1257 // Inventory code
1258 print '<td class="liste_titre left">';
1259 print '<input class="flat" type="text" size="4" name="search_inventorycode" value="'.dol_escape_htmltag($search_inventorycode).'">';
1260 print '</td>';
1261}
1262if (!empty($arrayfields['m.label']['checked'])) {
1263 // Label of movement
1264 print '<td class="liste_titre left">';
1265 print '<input class="flat" type="text" size="8" name="search_movement" value="'.dol_escape_htmltag($search_movement).'">';
1266 print '</td>';
1267}
1268if (!empty($arrayfields['origin']['checked'])) {
1269 // Origin of movement
1270 print '<td class="liste_titre left">';
1271 print '&nbsp; ';
1272 print '</td>';
1273}
1274if (!empty($arrayfields['m.fk_projet']['checked'])) {
1275 // fk_project
1276 print '<td class="liste_titre" align="left">';
1277 print $warehouse->showInputField($warehouse->fields['fk_project'], 'fk_project', $search_fk_project, '', '', 'search_', 'maxwidth125', 1);
1278 print '</td>';
1279}
1280if (!empty($arrayfields['m.type_mouvement']['checked'])) {
1281 // Type of movement
1282 print '<td class="liste_titre center">';
1283 //print '<input class="flat" type="text" size="3" name="search_type_mouvement" value="'.dol_escape_htmltag($search_type_mouvement).'">';
1284 print '<select id="search_type_mouvement" name="search_type_mouvement" class="maxwidth150">';
1285 print '<option value="" '.(($search_type_mouvement == "") ? 'selected="selected"' : '').'>&nbsp;</option>';
1286 print '<option value="0" '.(($search_type_mouvement == "0") ? 'selected="selected"' : '').'>'.$langs->trans('StockIncreaseAfterCorrectTransfer').'</option>';
1287 print '<option value="1" '.(($search_type_mouvement == "1") ? 'selected="selected"' : '').'>'.$langs->trans('StockDecreaseAfterCorrectTransfer').'</option>';
1288 print '<option value="2" '.(($search_type_mouvement == "2") ? 'selected="selected"' : '').'>'.$langs->trans('StockDecrease').'</option>';
1289 print '<option value="3" '.(($search_type_mouvement == "3") ? 'selected="selected"' : '').'>'.$langs->trans('StockIncrease').'</option>';
1290 print '</select>';
1291 print ajax_combobox('search_type_mouvement');
1292 // TODO: add new function $formentrepot->selectTypeOfMovement(...) like
1293 // print $formproduct->selectWarehouses($search_warehouse, 'search_warehouse', 'warehouseopen,warehouseinternal', 1, 0, 0, '', 0, 0, null, 'maxwidth200');
1294 print '</td>';
1295}
1296if (!empty($arrayfields['m.value']['checked'])) {
1297 // Qty
1298 print '<td class="liste_titre right">';
1299 print '<input class="flat width50 right" type="text" name="search_qty" value="'.dol_escape_htmltag($search_qty).'">';
1300 print '</td>';
1301}
1302if (!empty($arrayfields['m.price']['checked'])) {
1303 // Price
1304 print '<td class="liste_titre" align="left">';
1305 print '&nbsp; ';
1306 print '</td>';
1307}
1308
1309// Extra fields
1310include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_input.tpl.php';
1311
1312// Fields from hook
1313$parameters = array('arrayfields' => $arrayfields);
1314$reshook = $hookmanager->executeHooks('printFieldListOption', $parameters, $warehouse, $action); // Note that $action and $warehouse may have been modified by hook
1315print $hookmanager->resPrint;
1316// Date creation
1317if (!empty($arrayfields['m.datec']['checked'])) {
1318 print '<td class="liste_titre">';
1319 print '</td>';
1320}
1321// Date modification
1322if (!empty($arrayfields['m.tms']['checked'])) {
1323 print '<td class="liste_titre">';
1324 print '</td>';
1325}
1326// Action column
1327if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
1328 print '<td class="liste_titre center maxwidthsearch">';
1329 $searchpicto = $form->showFilterButtons();
1330 print $searchpicto;
1331 print '</td>';
1332}
1333print '</tr>'."\n";
1334
1335$totalarray = array();
1336$totalarray['nbfield'] = 0;
1337
1338// Fields title label
1339// --------------------------------------------------------------------
1340print '<tr class="liste_titre">';
1341// Action column
1342if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
1343 print getTitleFieldOfList($selectedfields, 0, $_SERVER["PHP_SELF"], '', '', '', '', $sortfield, $sortorder, 'center maxwidthsearch ')."\n";
1344 $totalarray['nbfield']++;
1345}
1346if (!empty($arrayfields['m.rowid']['checked'])) {
1347 print_liste_field_titre($arrayfields['m.rowid']['label'], $_SERVER["PHP_SELF"], 'm.rowid', '', $param, '', $sortfield, $sortorder);
1348}
1349if (!empty($arrayfields['m.datem']['checked'])) {
1350 print_liste_field_titre($arrayfields['m.datem']['label'], $_SERVER["PHP_SELF"], 'm.datem', '', $param, '', $sortfield, $sortorder, 'center ');
1351}
1352if (!empty($arrayfields['p.ref']['checked'])) {
1353 print_liste_field_titre($arrayfields['p.ref']['label'], $_SERVER["PHP_SELF"], 'p.ref', '', $param, '', $sortfield, $sortorder);
1354}
1355if (!empty($arrayfields['p.label']['checked'])) {
1356 print_liste_field_titre($arrayfields['p.label']['label'], $_SERVER["PHP_SELF"], 'p.label', '', $param, '', $sortfield, $sortorder);
1357}
1358if (!empty($arrayfields['m.batch']['checked'])) {
1359 print_liste_field_titre($arrayfields['m.batch']['label'], $_SERVER["PHP_SELF"], 'm.batch', '', $param, '', $sortfield, $sortorder, 'center ');
1360}
1361if (!empty($arrayfields['pl.eatby']['checked'])) {
1362 print_liste_field_titre($arrayfields['pl.eatby']['label'], $_SERVER["PHP_SELF"], 'pl.eatby', '', $param, '', $sortfield, $sortorder, 'center ');
1363}
1364if (!empty($arrayfields['pl.sellby']['checked'])) {
1365 print_liste_field_titre($arrayfields['pl.sellby']['label'], $_SERVER["PHP_SELF"], 'pl.sellby', '', $param, '', $sortfield, $sortorder, 'center ');
1366}
1367if (!empty($arrayfields['e.ref']['checked'])) {
1368 // We are on a specific warehouse card, no filter on other should be possible
1369 print_liste_field_titre($arrayfields['e.ref']['label'], $_SERVER["PHP_SELF"], "e.ref", "", $param, "", $sortfield, $sortorder);
1370}
1371if (!empty($arrayfields['m.fk_user_author']['checked'])) {
1372 print_liste_field_titre($arrayfields['m.fk_user_author']['label'], $_SERVER["PHP_SELF"], "m.fk_user_author", "", $param, "", $sortfield, $sortorder);
1373}
1374if (!empty($arrayfields['m.inventorycode']['checked'])) {
1375 print_liste_field_titre($arrayfields['m.inventorycode']['label'], $_SERVER["PHP_SELF"], "m.inventorycode", "", $param, "", $sortfield, $sortorder);
1376}
1377if (!empty($arrayfields['m.label']['checked'])) {
1378 print_liste_field_titre($arrayfields['m.label']['label'], $_SERVER["PHP_SELF"], "m.label", "", $param, "", $sortfield, $sortorder);
1379}
1380if (!empty($arrayfields['origin']['checked'])) {
1381 print_liste_field_titre($arrayfields['origin']['label'], $_SERVER["PHP_SELF"], "", "", $param, "", $sortfield, $sortorder);
1382}
1383if (!empty($arrayfields['m.fk_projet']['checked'])) {
1384 print_liste_field_titre($arrayfields['m.fk_projet']['label'], $_SERVER["PHP_SELF"], "m.fk_projet", "", $param, '', $sortfield, $sortorder);
1385}
1386if (!empty($arrayfields['m.type_mouvement']['checked'])) {
1387 print_liste_field_titre($arrayfields['m.type_mouvement']['label'], $_SERVER["PHP_SELF"], "m.type_mouvement", "", $param, '', $sortfield, $sortorder, 'center ');
1388}
1389if (!empty($arrayfields['m.value']['checked'])) {
1390 print_liste_field_titre($arrayfields['m.value']['label'], $_SERVER["PHP_SELF"], "m.value", "", $param, '', $sortfield, $sortorder, 'right ');
1391}
1392if (!empty($arrayfields['m.price']['checked'])) {
1393 print_liste_field_titre($arrayfields['m.price']['label'], $_SERVER["PHP_SELF"], "m.price", "", $param, '', $sortfield, $sortorder, 'right ');
1394}
1395
1396// Extra fields
1397include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_title.tpl.php';
1398
1399// Hook fields
1400$parameters = array('arrayfields' => $arrayfields, 'param' => $param, 'sortfield' => $sortfield, 'sortorder' => $sortorder, 'totalarray' => &$totalarray);
1401$reshook = $hookmanager->executeHooks('printFieldListTitle', $parameters, $warehouse, $action); // Note that $action and $warehouse may have been modified by hook
1402print $hookmanager->resPrint;
1403if (!empty($arrayfields['m.datec']['checked'])) {
1404 print_liste_field_titre($arrayfields['m.datec']['label'], $_SERVER["PHP_SELF"], "m.datec", "", $param, '', $sortfield, $sortorder, 'center nowrap ');
1405}
1406if (!empty($arrayfields['m.tms']['checked'])) {
1407 print_liste_field_titre($arrayfields['m.tms']['label'], $_SERVER["PHP_SELF"], "m.tms", "", $param, '', $sortfield, $sortorder, 'center nowrap ');
1408}
1409// Action column
1410if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
1411 print getTitleFieldOfList($selectedfields, 0, $_SERVER["PHP_SELF"], '', '', '', '', $sortfield, $sortorder, 'center maxwidthsearch ')."\n";
1412 $totalarray['nbfield']++;
1413}
1414print '</tr>'."\n";
1415
1416
1417$arrayofuniqueproduct = array();
1418
1419
1420// Loop on record
1421// --------------------------------------------------------------------
1422$i = 0;
1423$savnbfield = $totalarray['nbfield'];
1424$totalarray = array();
1425$totalarray['nbfield'] = 0;
1426$imaxinloop = ($limit ? min($num, $limit) : $num);
1427while ($i < $imaxinloop) {
1428 $obj = $db->fetch_object($resql);
1429 if (empty($obj)) {
1430 break; // Should not happen
1431 }
1432
1433 $userstatic->id = $obj->fk_user_author;
1434 $userstatic->login = $obj->login;
1435 $userstatic->lastname = $obj->lastname;
1436 $userstatic->firstname = $obj->firstname;
1437 $userstatic->photo = $obj->photo;
1438 $userstatic->email = $obj->user_email;
1439 $userstatic->status = $obj->user_status;
1440
1441 // Multilangs
1442 if (getDolGlobalInt('MAIN_MULTILANGS')) { // If multilang is enabled
1443 // TODO Use a cache
1444 $sql = "SELECT label";
1445 $sql .= " FROM ".MAIN_DB_PREFIX."product_lang";
1446 $sql .= " WHERE fk_product = ".((int) $obj->rowid);
1447 $sql .= " AND lang = '".$db->escape($langs->getDefaultLang())."'";
1448 $sql .= " LIMIT 1";
1449
1450 $result = $db->query($sql);
1451 if ($result) {
1452 $objtp = $db->fetch_object($result);
1453 if (!empty($objtp->label)) {
1454 $obj->produit = $objtp->label;
1455 }
1456 }
1457 }
1458
1459 $productstatic->id = $obj->rowid;
1460 $productstatic->ref = $obj->product_ref;
1461 $productstatic->label = $obj->produit;
1462 $productstatic->type = $obj->type;
1463 $productstatic->entity = $obj->entity;
1464 $productstatic->status = $obj->tosell;
1465 $productstatic->status_buy = $obj->tobuy;
1466 $productstatic->status_batch = $obj->tobatch;
1467
1468 $productlot->id = $obj->lotid;
1469 $productlot->batch = $obj->batch;
1470 $productlot->eatby = $obj->eatby;
1471 $productlot->sellby = $obj->sellby;
1472
1473 $warehousestatic->id = $obj->entrepot_id;
1474 $warehousestatic->ref = $obj->warehouse_ref;
1475 $warehousestatic->label = $obj->warehouse_ref;
1476 $warehousestatic->lieu = $obj->lieu;
1477 $warehousestatic->fk_parent = $obj->fk_parent;
1478 $warehousestatic->statut = $obj->statut;
1479
1480 $object->id = $obj->mid;
1481 $object->qty = $obj->qty;
1482 $object->label = $obj->label;
1483 $object->batch = $obj->batch;
1484 $object->warehouse_id = $obj->entrepot_id;
1485 $object->type = $obj->type_mouvement;
1486
1487 $arrayofuniqueproduct[$obj->rowid] = $obj->produit;
1488 if (!empty($obj->fk_origin)) {
1489 $origin = $object->get_origin($obj->fk_origin, $obj->origintype);
1490 } else {
1491 $origin = '';
1492 }
1493
1494 if ($mode == 'kanban') {
1495 if ($i == 0) {
1496 print '<tr class="trkanban"><td colspan="'.$savnbfield.'">';
1497 print '<div class="box-flex-container kanban">';
1498 }
1499 // Output Kanban
1500 $selected = -1;
1501 if ($massactionbutton || $massaction) { // If we are in select mode (massactionbutton defined) or if we have already selected and sent an action ($massaction) defined
1502 $selected = 0;
1503 if (in_array($warehouse->id, $arrayofselected)) {
1504 $selected = 1;
1505 }
1506 }
1507 print $warehouse->getKanbanView('', array('selected' => $selected));
1508 if ($i == ($imaxinloop - 1)) {
1509 print '</div>';
1510 print '</td></tr>';
1511 }
1512 } else {
1513 // Show here line of result
1514 $j = 0;
1515 print '<tr data-rowid="'.$warehouse->id.'" class="oddeven">';
1516 // Action column
1517 if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
1518 print '<td class="nowrap center">';
1519 if ($massactionbutton || $massaction) { // If we are in select mode (massactionbutton defined) or if we have already selected and sent an action ($massaction) defined
1520 $selected = 0;
1521 if (in_array($obj->mid, $arrayofselected)) {
1522 $selected = 1;
1523 }
1524 print '<input id="cb'.$obj->mid.'" class="flat checkforselect" type="checkbox" name="toselect[]" value="'.$obj->mid.'"'.($selected ? ' checked="checked"' : '').'>';
1525 }
1526 print '</td>';
1527 if (!$i) {
1528 $totalarray['nbfield']++;
1529 }
1530 }
1531 // Id movement
1532 if (!empty($arrayfields['m.rowid']['checked'])) {
1533 print '<td class="nowraponall">';
1534 //print img_picto($langs->trans("StockMovement"), 'movement', 'class="pictofixedwidth"');
1535 print $object->getNomUrl(1);
1536 ;
1537 print '</td>'; // This is primary not movement id
1538 }
1539 // Date
1540 if (!empty($arrayfields['m.datem']['checked'])) {
1541 print '<td class="nowraponall center">'.dol_print_date($db->jdate($obj->datem), 'dayhour', 'tzuserrel').'</td>';
1542 }
1543 // Product ref
1544 if (!empty($arrayfields['p.ref']['checked'])) {
1545 print '<td class="nowraponall">';
1546 print $productstatic->getNomUrl(1, 'stock', 16);
1547 print "</td>\n";
1548 }
1549 // Product label
1550 if (!empty($arrayfields['p.label']['checked'])) {
1551 print '<td class="tdoverflowmax150" title="'.dol_escape_htmltag($productstatic->label).'">';
1552 print $productstatic->label;
1553 print "</td>\n";
1554 }
1555 // Lot
1556 if (!empty($arrayfields['m.batch']['checked'])) {
1557 print '<td class="center nowraponall">';
1558 if ($productlot->id > 0) {
1559 print $productlot->getNomUrl(1);
1560 } else {
1561 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.
1562 }
1563 print '</td>';
1564 }
1565 // Eatby
1566 if (!empty($arrayfields['pl.eatby']['checked'])) {
1567 print '<td class="center">'.dol_print_date($obj->eatby, 'day').'</td>';
1568 }
1569 // Sellby
1570 if (!empty($arrayfields['pl.sellby']['checked'])) {
1571 print '<td class="center">'.dol_print_date($obj->sellby, 'day').'</td>';
1572 }
1573 // Warehouse
1574 if (!empty($arrayfields['e.ref']['checked'])) {
1575 print '<td class="tdoverflowmax150">';
1576 print $warehousestatic->getNomUrl(1);
1577 print "</td>\n";
1578 }
1579 // Author
1580 if (!empty($arrayfields['m.fk_user_author']['checked'])) {
1581 print '<td class="tdoverflowmax100">';
1582 print $userstatic->getNomUrl(-1);
1583 print "</td>\n";
1584 }
1585 // Inventory code
1586 if (!empty($arrayfields['m.inventorycode']['checked'])) {
1587 print '<td class="tdoverflowmax150" title="'.dolPrintHTML($obj->inventorycode).'">';
1588 if ($obj->inventorycode) {
1589 print img_picto('', 'movement', 'class="pictofixedwidth"');
1590 print '<a href="'.$_SERVER["PHP_SELF"].'?search_inventorycode='.urlencode('^'.$obj->inventorycode.'$').'">'.dol_escape_htmltag($obj->inventorycode).'</a>';
1591 }
1592 print '</td>';
1593 }
1594 // Label of movement
1595 if (!empty($arrayfields['m.label']['checked'])) {
1596 print '<td class="tdoverflowmax200" title="'.dol_escape_htmltag($obj->label).'">'.dol_escape_htmltag($obj->label).'</td>';
1597 }
1598 // Origin of movement
1599 if (!empty($arrayfields['origin']['checked'])) {
1600 print '<td class="nowraponall">'.$origin.'</td>';
1601 }
1602 // Project
1603 if (!empty($arrayfields['m.fk_projet']['checked'])) {
1604 print '<td>';
1605 if ($obj->fk_project != 0) {
1606 print $object->get_origin($obj->fk_project, 'project');
1607 }
1608 print '</td>';
1609 }
1610 // Type of movement
1611 if (!empty($arrayfields['m.type_mouvement']['checked'])) {
1612 print '<td class="center">';
1613 print $object->getTypeMovement();
1614 print '</td>';
1615 }
1616 // Qty
1617 if (!empty($arrayfields['m.value']['checked'])) {
1618 print '<td class="right">';
1619 if ($obj->qty > 0) {
1620 print '<span class="stockmovemententry">';
1621 print '+';
1622 print $obj->qty;
1623 print '</span>';
1624 } else {
1625 print '<span class="stockmovementexit">';
1626 print $obj->qty;
1627 print '</span>';
1628 }
1629 print '</td>';
1630 }
1631 // Price
1632 if (!empty($arrayfields['m.price']['checked'])) {
1633 $usercancreadsupplierprice = getDolGlobalString('MAIN_USE_ADVANCED_PERMS') ? $user->hasRight('product', 'product_advance', 'read_supplier_prices') : $user->hasRight('product', 'lire');
1634 if ($productstatic->isService()) {
1635 $usercancreadsupplierprice = getDolGlobalString('MAIN_USE_ADVANCED_PERMS') ? $user->hasRight('service', 'service_advance', 'read_supplier_prices') : $user->hasRight('service', 'lire');
1636 }
1637 print '<td class="right">';
1638 if ($obj->price != 0 && $usercancreadsupplierprice) {
1639 print price($obj->price);
1640 }
1641 print '</td>';
1642 }
1643
1644 // Extra fields
1645 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_print_fields.tpl.php';
1646 // Fields from hook
1647 $parameters = array('arrayfields' => $arrayfields, 'object' => $object, 'obj' => $obj, 'i' => $i, 'totalarray' => &$totalarray);
1648 $reshook = $hookmanager->executeHooks('printFieldListValue', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
1649 print $hookmanager->resPrint;
1650
1651 // Action column
1652 if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
1653 print '<td class="nowrap center">';
1654 if ($massactionbutton || $massaction) { // If we are in select mode (massactionbutton defined) or if we have already selected and sent an action ($massaction) defined
1655 $selected = 0;
1656 if (in_array($obj->mid, $arrayofselected)) {
1657 $selected = 1;
1658 }
1659 print '<input id="cb'.$obj->mid.'" class="flat checkforselect" type="checkbox" name="toselect[]" value="'.$obj->mid.'"'.($selected ? ' checked="checked"' : '').'>';
1660 }
1661 print '</td>';
1662 if (!$i) {
1663 $totalarray['nbfield']++;
1664 }
1665 }
1666
1667 print '</tr>'."\n";
1668 }
1669
1670 $i++;
1671}
1672
1673// If no record found
1674if ($num == 0) {
1675 $colspan = 1;
1676 foreach ($arrayfields as $key => $val) {
1677 if (!empty($val['checked'])) {
1678 $colspan++;
1679 }
1680 }
1681 print '<tr><td colspan="'.$colspan.'"><span class="opacitymedium">'.$langs->trans("NoRecordFound").'</span></td></tr>';
1682}
1683
1684$db->free($resql);
1685
1686$parameters = array('arrayfields' => $arrayfields, 'sql' => $sql);
1687$reshook = $hookmanager->executeHooks('printFieldListFooter', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
1688print $hookmanager->resPrint;
1689
1690print '</table>'."\n";
1691print '</div>'."\n";
1692
1693print '</form>'."\n";
1694
1695// Add number of product when there is a filter on period
1696if (count($arrayofuniqueproduct) == 1 && !empty($year) && is_numeric($year)) {
1697 print "<br>";
1698
1699 $productidselected = 0;
1700 foreach ($arrayofuniqueproduct as $key => $val) {
1701 $productidselected = $key;
1702 $productlabelselected = $val;
1703 }
1704 $datebefore = dol_get_first_day($year ? $year : (int) dol_print_date(time(), "%Y"), $month ? $month : 1, true);
1705 $dateafter = dol_get_last_day($year ? $year : (int) dol_print_date(time(), "%Y"), $month ? $month : 12, true);
1706 $balancebefore = $object->calculateBalanceForProductBefore($productidselected, $datebefore);
1707 $balanceafter = $object->calculateBalanceForProductBefore($productidselected, $dateafter);
1708
1709 //print '<tr class="total"><td class="liste_total">';
1710 print $langs->trans("NbOfProductBeforePeriod", $productlabelselected, dol_print_date($datebefore, 'day', 'gmt'));
1711 //print '</td>';
1712 //print '<td class="liste_total right" colspan="6">';
1713 print ': '.$balancebefore;
1714 print "<br>\n";
1715 //print '</td></tr>';
1716 //print '<tr class="total"><td class="liste_total">';
1717 print $langs->trans("NbOfProductAfterPeriod", $productlabelselected, dol_print_date($dateafter, 'day', 'gmt'));
1718 //print '</td>';
1719 //print '<td class="liste_total right" colspan="6">';
1720 print ': '.$balanceafter;
1721 print "<br>\n";
1722 //print '</td></tr>';
1723}
1724
1725if (in_array('builddoc', array_keys($arrayofmassactions)) && ($nbtotalofrecords === '' || $nbtotalofrecords)) {
1726 $hidegeneratedfilelistifempty = 1;
1727 if ($massaction == 'builddoc' || $action == 'remove_file' || $show_files) {
1728 $hidegeneratedfilelistifempty = 0;
1729 }
1730
1731 require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php';
1732 $formfile = new FormFile($db);
1733
1734 // Show list of available documents
1735 $urlsource = $_SERVER['PHP_SELF'].'?sortfield='.$sortfield.'&sortorder='.$sortorder;
1736 $urlsource .= str_replace('&amp;', '&', $param);
1737
1738 $filedir = $diroutputmassaction;
1739 $genallowed = $permissiontoread;
1740 $delallowed = $permissiontoadd;
1741
1742 print $formfile->showdocuments('massfilesarea_stock', '', $filedir, $urlsource, 0, $delallowed, '', 1, 1, 0, 48, 1, $param, $title, '', '', '', null, $hidegeneratedfilelistifempty);
1743}
1744
1745// End of page
1746llxFooter();
1747$db->close();
$id
Support class for third parties, contacts, members, users or resources.
Definition account.php:48
if( $user->socid > 0) if(! $user->hasRight('accounting', 'chartofaccount')) $object
Definition card.php:67
$totalarray
Definition export.php:1206
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:475
llxFooter($comment='', $zone='private', $disabledoutputofmessages=0)
Empty footer.
Definition wrapper.php:91
if(!defined('NOREQUIRESOC')) if(!defined( 'NOREQUIRETRAN')) if(!defined('NOTOKENRENEWAL')) if(!defined( 'NOREQUIREMENU')) if(!defined('NOREQUIREHTML')) if(!defined( 'NOREQUIREAJAX')) llxHeader($head='', $title='', $help_url='', $target='', $disablejs=0, $disablehead=0, $arrayofjs='', $arrayofcss='', $morequerystring='', $morecssonbody='', $replacemainareaby='', $disablenofollow=0, $disablenoindex=0)
Empty header.
Definition wrapper.php:73
Class to manage warehouses.
Class to manage standard extra fields.
Class to offer components to list and upload files.
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 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 projects.
Class to manage translations.
Class to manage Dolibarr users.
dol_get_first_day($year, $month=1, $gm=false)
Return GMT time for first day of a month or year.
Definition date.lib.php:600
dol_get_last_day($year, $month=12, $gm=false)
Return GMT time for last day of a month or year.
Definition date.lib.php:619
dol_dir_list($utf8_path, $types="all", $recursive=0, $filter="", $excludefilter=null, $sortcriteria="name", $sortorder=SORT_ASC, $mode=0, $nohook=0, $relativename="", $donotfollowsymlinks=0, $nbsecondsold=0)
Scan a directory and return a list of files/directories.
Definition files.lib.php:63
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...
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='', $noduplicate=0, $attop=0)
Set event messages in dol_events session object.
GETPOSTDATE($prefix, $hourTime='', $gm='auto', $saverestore='')
Helper function that combines values of a dolibarr DatePicker (such as Form\selectDate) for year,...
print_liste_field_titre($name, $file="", $field="", $begin="", $param="", $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, $selectlimitsuffix=0, $hidenavigation=0, $pagenavastextinput=0, $morehtmlrightbeforearrow='')
Print a title with navigation controls for pagination.
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2, $allowothertags=array())
Show picto whatever it's its name (generic function)
GETPOSTINT($paramname, $method=0)
Return the value of a $_GET or $_POST supervariable, converted into integer.
dol_get_fiche_head($links=array(), $active='', $title='', $notab=0, $picto='', $pictoisfullpath=0, $morehtmlright='', $morecss='', $limittoshow=0, $moretabssuffix='', $dragdropfile=0, $morecssdiv='')
Show tabs of a record.
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
dol_get_fiche_end($notab=0)
Return tab footer of a card.
dol_eval($s, $returnvalue=1, $hideerrors=1, $onlysimplestring='1')
Replace eval function to add more security.
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...
setEventMessage($mesgs, $style='mesgs', $noduplicate=0, $attop=0)
Set event message in dol_events session object.
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.
dol_now($mode='auto')
Return date for now.
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'.
getTitleFieldOfList($name, $thead=0, $file="", $field="", $begin="", $moreparam="", $moreattrib="", $sortfield="", $sortorder="", $prefix="", $disablesortlink=0, $tooltip='', $forcenowrapcolumntitle=0)
Get 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.
GETPOSTFLOAT($paramname, $rounding='')
Return the value of a $_GET or $_POST supervariable, converted into float.
dol_clone($object, $native=2)
Create a clone of instance of object (new instance with same value for each properties) With native =...
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...
dol_sanitizeFileName($str, $newstr='_', $unaccent=1, $includequotes=0)
Clean a string to use it as a file name.
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
img_edit($titlealt='default', $float=0, $other='')
Show logo edit/modify fiche.
dol_mkdir($dir, $dataroot='', $newmask='')
Creation of a directory (this can create recursive subdir)
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...
global $conf
The following vars must be defined: $type2label $form $conf, $lang, The following vars may also be de...
Definition member.php:79
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.
accessforbidden($message='', $printheader=1, $printfooter=1, $showonlymessage=0, $params=null)
Show a message to say access is forbidden and stop program.
stock_prepare_head($object)
Prepare array with list of tabs.
Definition stock.lib.php:31