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