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