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