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