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