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-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
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 {
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) {
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) {
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 {
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, $conf->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 ($conf->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 (!$conf->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 ($conf->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 (!$conf->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 ($conf->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 tdoverflowmax150 cell2linesheight">';
1564 print $productstatic->getNomUrl(1, 'stock', 16);
1565 print '<br><span class="opacitymedium">'.$productstatic->label.'</span>';
1566 print "</td>\n";
1567 }
1568 // Product label
1569 if (!empty($arrayfields['p.label']['checked'])) {
1570 print '<td class="tdoverflowmax150" title="'.dol_escape_htmltag($productstatic->label).'">';
1571 print $productstatic->label;
1572 print "</td>\n";
1573 }
1574 // Lot
1575 if (!empty($arrayfields['m.batch']['checked'])) {
1576 print '<td class="center nowraponall">';
1577 if ($productlot->id > 0) {
1578 print $productlot->getNomUrl(1);
1579 } else {
1580 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.
1581 }
1582 print '</td>';
1583 }
1584 // Eatby
1585 if (!empty($arrayfields['pl.eatby']['checked'])) {
1586 print '<td class="center">'.dol_print_date($obj->eatby, 'day').'</td>';
1587 }
1588 // Sellby
1589 if (!empty($arrayfields['pl.sellby']['checked'])) {
1590 print '<td class="center">'.dol_print_date($obj->sellby, 'day').'</td>';
1591 }
1592 // Warehouse
1593 if (!empty($arrayfields['e.ref']['checked'])) {
1594 print '<td class="tdoverflowmax150">';
1595 print $warehousestatic->getNomUrl(1);
1596 print "</td>\n";
1597 }
1598 // Author
1599 if (!empty($arrayfields['m.fk_user_author']['checked'])) {
1600 print '<td class="tdoverflowmax100">';
1601 print $userstatic->getNomUrl(-1);
1602 print "</td>\n";
1603 }
1604 // Inventory code
1605 if (!empty($arrayfields['m.inventorycode']['checked'])) {
1606 print '<td class="tdoverflowmax150" title="'.dolPrintHTML($obj->inventorycode).'">';
1607 if ($obj->inventorycode) {
1608 print img_picto('', 'movement', 'class="pictofixedwidth"');
1609 print '<a href="'.$_SERVER["PHP_SELF"].'?search_inventorycode='.urlencode('^'.$obj->inventorycode.'$').'">'.dol_escape_htmltag($obj->inventorycode).'</a>';
1610 }
1611 print '</td>';
1612 }
1613 // Label of movement
1614 if (!empty($arrayfields['m.label']['checked'])) {
1615 print '<td class="tdoverflowmax200" title="'.dol_escape_htmltag($obj->label).'">'.dol_escape_htmltag($obj->label).'</td>';
1616 }
1617 // Origin of movement
1618 if (!empty($arrayfields['origin']['checked'])) {
1619 print '<td class="nowraponall">'.$origin.'</td>';
1620 }
1621 // Project
1622 if (!empty($arrayfields['m.fk_projet']['checked'])) {
1623 print '<td>';
1624 if ($obj->fk_project != 0) {
1625 print $object->get_origin($obj->fk_project, 'project');
1626 }
1627 print '</td>';
1628 }
1629 // Type of movement
1630 if (!empty($arrayfields['m.type_mouvement']['checked'])) {
1631 print '<td class="center">';
1632 print $object->getTypeMovement();
1633 print '</td>';
1634 }
1635 // Qty
1636 if (!empty($arrayfields['m.value']['checked'])) {
1637 print '<td class="right">';
1638 if ($obj->qty > 0) {
1639 print '<span class="stockmovemententry">';
1640 print '+';
1641 print $obj->qty;
1642 print '</span>';
1643 } else {
1644 print '<span class="stockmovementexit">';
1645 print $obj->qty;
1646 print '</span>';
1647 }
1648 print '</td>';
1649 }
1650 // Price
1651 if (!empty($arrayfields['m.price']['checked'])) {
1652 // Product and service differentiation, if we have permissions for only one of them
1653 $displayprice = getDolGlobalString('MAIN_USE_ADVANCED_PERMS') ? $user->hasRight('product', 'product_advance', 'read_supplier_prices') : $user->hasRight('product', 'lire');
1654 if ($productstatic->isService()) {
1655 $displayprice = getDolGlobalString('MAIN_USE_ADVANCED_PERMS') ? $user->hasRight('service', 'service_advance', 'read_supplier_prices') : $user->hasRight('service', 'lire');
1656 }
1657 print '<td class="right">';
1658 if ($obj->price != 0 && $displayprice) {
1659 print price($obj->price);
1660 }
1661 print '</td>';
1662 }
1663
1664 // Extra fields
1665 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_print_fields.tpl.php';
1666 // Fields from hook
1667 $parameters = array('arrayfields' => $arrayfields, 'object' => $object, 'obj' => $obj, 'i' => $i, 'totalarray' => &$totalarray);
1668 $reshook = $hookmanager->executeHooks('printFieldListValue', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
1669 print $hookmanager->resPrint;
1670
1671 // Action column
1672 if (!$conf->main_checkbox_left_column) {
1673 print '<td class="nowrap center">';
1674 if ($massactionbutton || $massaction) { // If we are in select mode (massactionbutton defined) or if we have already selected and sent an action ($massaction) defined
1675 $selected = 0;
1676 if (in_array($obj->mid, $arrayofselected)) {
1677 $selected = 1;
1678 }
1679 print '<input id="cb'.$obj->mid.'" class="flat checkforselect" type="checkbox" name="toselect[]" value="'.$obj->mid.'"'.($selected ? ' checked="checked"' : '').'>';
1680 }
1681 print '</td>';
1682 if (!$i) {
1683 $totalarray['nbfield']++;
1684 }
1685 }
1686
1687 print '</tr>'."\n";
1688 }
1689
1690 $i++;
1691}
1692
1693// If no record found
1694if ($num == 0) {
1695 $colspan = 1;
1696 foreach ($arrayfields as $key => $val) {
1697 if (!empty($val['checked'])) {
1698 $colspan++;
1699 }
1700 }
1701 print '<tr><td colspan="'.$colspan.'"><span class="opacitymedium">'.$langs->trans("NoRecordFound").'</span></td></tr>';
1702}
1703
1704$db->free($resql);
1705
1706$parameters = array('arrayfields' => $arrayfields, 'sql' => $sql);
1707$reshook = $hookmanager->executeHooks('printFieldListFooter', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
1708print $hookmanager->resPrint;
1709
1710print '</table>'."\n";
1711print '</div>'."\n";
1712
1713print '</form>'."\n";
1714
1715// Add number of product when there is a filter on period
1716if (count($arrayofuniqueproduct) == 1 && !empty($search_date_startyear) && is_numeric($search_date_startyear)) {
1717 print "<br>";
1718
1719 $productidselected = 0;
1720 foreach ($arrayofuniqueproduct as $key => $val) {
1721 $productidselected = $key;
1722 $productlabelselected = $val;
1723 }
1724 $datebefore = dol_get_first_day($search_date_startyear ? $search_date_startyear : dol_print_date(time(), "%Y"), $search_date_startmonth ? $search_date_startmonth : 1, true);
1725 $dateafter = dol_get_last_day($search_date_endyear ? $search_date_endyear : dol_print_date(time(), "%Y"), $search_date_endmonth ? $search_date_endmonth : 12, true);
1726 $balancebefore = $object->calculateBalanceForProductBefore($productidselected, $datebefore);
1727 $balanceafter = $object->calculateBalanceForProductBefore($productidselected, $dateafter);
1728
1729 //print '<tr class="total"><td class="liste_total">';
1730 print $langs->trans("NbOfProductBeforePeriod", $productlabelselected, dol_print_date($datebefore, 'day', 'gmt'));
1731 //print '</td>';
1732 //print '<td class="liste_total right" colspan="6">';
1733 print ': '.$balancebefore;
1734 print "<br>\n";
1735 //print '</td></tr>';
1736 //print '<tr class="total"><td class="liste_total">';
1737 print $langs->trans("NbOfProductAfterPeriod", $productlabelselected, dol_print_date($dateafter, 'day', 'gmt'));
1738 //print '</td>';
1739 //print '<td class="liste_total right" colspan="6">';
1740 print ': '.$balanceafter;
1741 print "<br>\n";
1742 //print '</td></tr>';
1743}
1744
1745if (in_array('builddoc', array_keys($arrayofmassactions)) && ($nbtotalofrecords === '' || $nbtotalofrecords)) {
1746 $hidegeneratedfilelistifempty = 1;
1747 if ($massaction == 'builddoc' || $action == 'remove_file' || $show_files) {
1748 $hidegeneratedfilelistifempty = 0;
1749 }
1750
1751 require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php';
1752 $formfile = new FormFile($db);
1753
1754 // Show list of available documents
1755 $urlsource = $_SERVER['PHP_SELF'].'?sortfield='.$sortfield.'&sortorder='.$sortorder;
1756 $urlsource .= str_replace('&amp;', '&', $param);
1757
1758 $filedir = $diroutputmassaction;
1759 $genallowed = $permissiontoread;
1760 $delallowed = $permissiontoadd;
1761
1762 print $formfile->showdocuments('massfilesarea_stock', '', $filedir, $urlsource, 0, $delallowed, '', 1, 1, 0, 48, 1, $param, $title, '', '', '', null, $hidegeneratedfilelistifempty);
1763}
1764
1765// End of page
1766llxFooter();
1767$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:498
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: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)
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'.
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.
getTitleFieldOfList($name, $thead=0, $file="", $field="", $begin="", $moreparam="", $moreattrib="", $sortfield="", $sortorder="", $prefix="", $disablesortlink=0, $tooltip='', $forcenowrapcolumntitle=0)
Get title line of an array.
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_print_error($db=null, $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
GETPOSTISSET($paramname)
Return true if we are in a context of submitting the parameter $paramname from a POST of a form.
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...
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
buildzip.php
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