2014-03-05 10:30:06 +01:00
< ? php
2024-10-27 19:24:48 +01:00
/* Copyright ( C ) 2007 - 2023 Laurent Destailleur < eldy @ users . sourceforge . net >
* Copyright ( C ) 2013 - 2014 Cedric GROSS < c . gross @ kreiz - it . fr >
* Copyright ( C ) 2024 Frédéric France < frederic . france @ free . fr >
* Copyright ( C ) 2024 Ferran Marcet < fmarcet @ 2 byte . es >
2025-02-18 21:48:21 +01:00
* Copyright ( C ) 2024 - 2025 MDW < mdeweerd @ users . noreply . github . com >
2014-03-05 10:30:06 +01:00
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 3 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
2019-09-23 21:55:30 +02:00
* along with this program . If not , see < https :// www . gnu . org / licenses />.
2014-03-05 10:30:06 +01:00
*/
/**
* \file product / class / productbatch . class . php
* \ingroup productbatch
2023-04-01 14:38:07 +02:00
* \brief Manage record and specific data for batch number management .
* Manage table llx_product_batch ( should have been named product_stock_batch )
2014-03-05 10:30:06 +01:00
*/
2018-07-26 11:57:25 +02:00
require_once DOL_DOCUMENT_ROOT . " /core/class/commonobject.class.php " ;
2014-03-05 10:30:06 +01:00
/**
* Manage record for batch number management
*/
class Productbatch extends CommonObject
{
2020-02-21 11:08:34 +01:00
/**
* Batches rules
*/
const BATCH_RULE_SELLBY_EATBY_DATES_FIRST = 1 ;
2018-08-22 11:48:26 +02:00
/**
* @ var string ID to identify managed object
*/
2019-11-13 19:37:08 +01:00
public $element = 'productbatch' ;
2018-08-29 15:37:35 +02:00
2024-11-06 20:15:15 +01:00
/**
* @ var string
*/
2019-11-13 19:37:08 +01:00
private static $_table_element = 'product_batch' ; //!< Name of table without prefix where object is stored
2014-03-05 10:30:06 +01:00
2024-11-06 20:15:15 +01:00
/**
* @ var ? int
*/
2018-10-12 09:26:58 +02:00
public $fk_product_stock ;
2023-06-29 13:16:44 +02:00
2024-10-27 19:24:48 +01:00
/**
* @ var string batch number
*/
2019-11-13 19:37:08 +01:00
public $batch = '' ;
2024-06-04 14:46:54 +02:00
/**
* @ var float Quantity
*/
2018-10-12 09:26:58 +02:00
public $qty ;
2024-10-27 19:24:48 +01:00
/**
* @ var int warehouse ID
*/
2015-01-06 13:23:51 +01:00
public $warehouseid ;
2018-10-12 09:26:58 +02:00
/**
2020-10-31 14:32:18 +01:00
* @ var int ID
*/
2016-05-17 14:02:18 +02:00
public $fk_product ;
2014-11-15 18:24:38 +01:00
2024-10-27 19:24:48 +01:00
/**
* @ var int Properties of the lot
* ID in table of the details of properties of each lots
*/
public $lotid ;
2023-11-01 15:35:29 +01:00
/**
2025-02-18 21:48:21 +01:00
* @ var int | ''
2023-11-01 15:35:29 +01:00
* @ deprecated
*/
2023-06-29 13:16:44 +02:00
public $sellby = '' ; // dlc
2023-11-01 15:35:29 +01:00
/**
2025-02-18 21:48:21 +01:00
* @ var int | ''
2023-11-01 15:35:29 +01:00
* @ deprecated
*/
2023-06-29 13:16:44 +02:00
public $eatby = '' ; // dmd/dluo
2014-03-05 10:30:06 +01:00
2020-10-31 14:32:18 +01:00
/**
* Constructor
*
2024-01-13 15:50:02 +01:00
* @ param DoliDB $db Database handler
2020-10-31 14:32:18 +01:00
*/
public function __construct ( $db )
{
$this -> db = $db ;
}
2014-03-05 10:30:06 +01:00
2020-10-31 14:32:18 +01:00
/**
* Create object into database
*
2025-02-18 21:48:21 +01:00
* @ param User $user User that creates
* @ param int < 0 , 1 > $notrigger 0 = launch triggers after , 1 = disable triggers
* @ return int Return integer < 0 if KO , Id of created object if OK
2020-10-31 14:32:18 +01:00
*/
public function create ( $user , $notrigger = 0 )
{
2019-11-13 19:37:08 +01:00
$error = 0 ;
2014-03-05 10:30:06 +01:00
// Clean parameters
2018-09-01 23:46:13 +02:00
$this -> cleanParam ();
2014-03-05 10:30:06 +01:00
// Check parameters
// Put here code to add control on parameters values
2020-10-31 14:32:18 +01:00
// Insert request
2022-01-27 10:12:10 +01:00
$sql = " INSERT INTO " . $this -> db -> prefix () . " product_batch ( " ;
2019-11-13 19:37:08 +01:00
$sql .= " fk_product_stock, " ;
2020-12-16 12:26:01 +01:00
$sql .= " sellby, " ; // no more used
$sql .= " eatby, " ; // no more used
2019-11-13 19:37:08 +01:00
$sql .= " batch, " ;
$sql .= " qty, " ;
$sql .= " import_key " ;
$sql .= " ) VALUES ( " ;
$sql .= " " . ( ! isset ( $this -> fk_product_stock ) ? 'NULL' : $this -> fk_product_stock ) . " , " ;
2020-12-16 12:26:01 +01:00
$sql .= " " . ( ! isset ( $this -> sellby ) || dol_strlen ( $this -> sellby ) == 0 ? 'NULL' : " ' " . $this -> db -> idate ( $this -> sellby ) . " ' " ) . " , " ; // no more used
$sql .= " " . ( ! isset ( $this -> eatby ) || dol_strlen ( $this -> eatby ) == 0 ? 'NULL' : " ' " . $this -> db -> idate ( $this -> eatby ) . " ' " ) . " , " ; // no more used
2019-11-13 19:37:08 +01:00
$sql .= " " . ( ! isset ( $this -> batch ) ? 'NULL' : " ' " . $this -> db -> escape ( $this -> batch ) . " ' " ) . " , " ;
$sql .= " " . ( ! isset ( $this -> qty ) ? 'NULL' : $this -> qty ) . " , " ;
2022-12-28 13:04:11 +01:00
$sql .= " " . ( ! isset ( $this -> import_key ) ? 'NULL' : " ' " . $this -> db -> escape ( $this -> import_key ) . " ' " );
2019-11-13 19:37:08 +01:00
$sql .= " ) " ;
2014-03-05 10:30:06 +01:00
$this -> db -> begin ();
2014-06-12 11:31:53 +02:00
dol_syslog ( get_class ( $this ) . " ::create " , LOG_DEBUG );
2020-10-31 14:32:18 +01:00
$resql = $this -> db -> query ( $sql );
2021-02-26 14:25:17 +01:00
if ( ! $resql ) {
2023-12-04 13:49:31 +01:00
$error ++ ;
$this -> errors [] = " Error " . $this -> db -> lasterror ();
2021-02-26 14:25:17 +01:00
}
if ( ! $error ) {
2022-01-27 10:12:10 +01:00
$this -> id = $this -> db -> last_insert_id ( $this -> db -> prefix () . self :: $_table_element );
2014-03-05 10:30:06 +01:00
}
2020-10-31 14:32:18 +01:00
// Commit or rollback
2021-02-26 14:25:17 +01:00
if ( $error ) {
2014-03-05 10:30:06 +01:00
$this -> db -> rollback ();
2019-11-13 19:37:08 +01:00
return - 1 * $error ;
2020-05-21 15:05:19 +02:00
} else {
2014-03-05 10:30:06 +01:00
$this -> db -> commit ();
2020-10-31 14:32:18 +01:00
return $this -> id ;
2014-03-05 10:30:06 +01:00
}
2020-10-31 14:32:18 +01:00
}
2014-03-05 10:30:06 +01:00
2020-10-31 14:32:18 +01:00
/**
* Load object in memory from the database
*
* @ param int $id Id object
2023-12-01 19:51:32 +01:00
* @ return int Return integer < 0 if KO , > 0 if OK
2020-10-31 14:32:18 +01:00
*/
public function fetch ( $id )
{
2014-03-05 10:30:06 +01:00
$sql = " SELECT " ;
2019-11-13 19:37:08 +01:00
$sql .= " t.rowid, " ;
$sql .= " t.tms, " ;
$sql .= " t.fk_product_stock, " ;
$sql .= " t.sellby as oldsellby, " ;
$sql .= " t.eatby as oldeatby, " ;
$sql .= " t.batch, " ;
$sql .= " t.qty, " ;
$sql .= " t.import_key, " ;
$sql .= " w.fk_entrepot, " ;
$sql .= " w.fk_product, " ;
$sql .= " pl.eatby, " ;
$sql .= " pl.sellby " ;
2022-09-21 00:46:02 +02:00
$sql .= " FROM " . $this -> db -> prefix () . " product_batch as t " ;
$sql .= " INNER JOIN " . $this -> db -> prefix () . " product_stock w on t.fk_product_stock = w.rowid " ; // llx_product_stock is a parent table so this link does NOT generate duplicate record
2022-01-27 10:12:10 +01:00
$sql .= " LEFT JOIN " . $this -> db -> prefix () . " product_lot as pl on pl.fk_product = w.fk_product and pl.batch = t.batch " ;
2021-03-14 11:48:39 +01:00
$sql .= " WHERE t.rowid = " . (( int ) $id );
2014-03-05 10:30:06 +01:00
2014-06-12 11:31:53 +02:00
dol_syslog ( get_class ( $this ) . " ::fetch " , LOG_DEBUG );
2014-03-05 10:30:06 +01:00
$resql = $this -> db -> query ( $sql );
2021-02-26 14:25:17 +01:00
if ( $resql ) {
if ( $this -> db -> num_rows ( $resql )) {
2014-03-05 10:30:06 +01:00
$obj = $this -> db -> fetch_object ( $resql );
2019-11-13 19:37:08 +01:00
$this -> id = $obj -> rowid ;
2014-03-05 10:30:06 +01:00
$this -> tms = $this -> db -> jdate ( $obj -> tms );
$this -> fk_product_stock = $obj -> fk_product_stock ;
2019-11-13 19:37:08 +01:00
$this -> sellby = $this -> db -> jdate ( $obj -> sellby ? $obj -> sellby : $obj -> oldsellby );
$this -> eatby = $this -> db -> jdate ( $obj -> eatby ? $obj -> eatby : $obj -> oldeatby );
2014-03-05 10:30:06 +01:00
$this -> batch = $obj -> batch ;
$this -> qty = $obj -> qty ;
$this -> import_key = $obj -> import_key ;
2019-11-13 19:37:08 +01:00
$this -> warehouseid = $obj -> fk_entrepot ;
$this -> fk_product = $obj -> fk_product ;
2014-03-05 10:30:06 +01:00
}
$this -> db -> free ( $resql );
return 1 ;
2020-05-21 15:05:19 +02:00
} else {
2014-03-05 10:30:06 +01:00
$this -> error = " Error " . $this -> db -> lasterror ();
return - 1 ;
}
}
2020-10-31 14:32:18 +01:00
/**
* Update object into database
*
* @ param User $user User that modifies
* @ param int $notrigger 0 = launch triggers after , 1 = disable triggers
2023-12-01 19:51:32 +01:00
* @ return int Return integer < 0 if KO , > 0 if OK
2020-10-31 14:32:18 +01:00
*/
public function update ( $user = null , $notrigger = 0 )
{
2019-11-13 19:37:08 +01:00
$error = 0 ;
2014-03-05 10:30:06 +01:00
// Clean parameters
2018-09-01 23:46:13 +02:00
$this -> cleanParam ();
2014-03-05 10:30:06 +01:00
2015-08-14 23:53:59 +02:00
// TODO Check qty is ok for stock move. Negative may not be allowed.
2024-11-06 20:15:15 +01:00
/*
2021-02-26 14:25:17 +01:00
if ( $this -> qty < 0 ) {
2015-08-14 23:53:59 +02:00
}
2024-11-06 20:15:15 +01:00
*/
2017-09-15 10:45:41 +02:00
2020-10-31 14:32:18 +01:00
// Update request
2022-01-27 10:12:10 +01:00
$sql = " UPDATE " . $this -> db -> prefix () . self :: $_table_element . " SET " ;
2020-04-10 10:59:32 +02:00
$sql .= " fk_product_stock= " . ( isset ( $this -> fk_product_stock ) ? $this -> fk_product_stock : " null " ) . " , " ;
$sql .= " sellby= " . ( dol_strlen ( $this -> sellby ) != 0 ? " ' " . $this -> db -> idate ( $this -> sellby ) . " ' " : 'null' ) . " , " ;
$sql .= " eatby= " . ( dol_strlen ( $this -> eatby ) != 0 ? " ' " . $this -> db -> idate ( $this -> eatby ) . " ' " : 'null' ) . " , " ;
$sql .= " batch= " . ( isset ( $this -> batch ) ? " ' " . $this -> db -> escape ( $this -> batch ) . " ' " : " null " ) . " , " ;
$sql .= " qty= " . ( isset ( $this -> qty ) ? $this -> qty : " null " ) . " , " ;
2022-12-28 13:04:11 +01:00
$sql .= " import_key= " . ( isset ( $this -> import_key ) ? " ' " . $this -> db -> escape ( $this -> import_key ) . " ' " : " null " );
2021-03-14 12:20:23 +01:00
$sql .= " WHERE rowid= " . (( int ) $this -> id );
2014-03-05 10:30:06 +01:00
$this -> db -> begin ();
2014-06-12 11:31:53 +02:00
dol_syslog ( get_class ( $this ) . " ::update " , LOG_DEBUG );
2014-03-05 10:30:06 +01:00
$resql = $this -> db -> query ( $sql );
2021-02-26 14:25:17 +01:00
if ( ! $resql ) {
2023-12-04 13:49:31 +01:00
$error ++ ;
$this -> errors [] = " Error " . $this -> db -> lasterror ();
2021-02-26 14:25:17 +01:00
}
2014-03-05 10:30:06 +01:00
2020-10-31 14:32:18 +01:00
// Commit or rollback
2021-02-26 14:25:17 +01:00
if ( $error ) {
foreach ( $this -> errors as $errmsg ) {
2014-03-05 10:30:06 +01:00
dol_syslog ( get_class ( $this ) . " ::update " . $errmsg , LOG_ERR );
2019-11-13 19:37:08 +01:00
$this -> error .= ( $this -> error ? ', ' . $errmsg : $errmsg );
2014-03-05 10:30:06 +01:00
}
$this -> db -> rollback ();
2019-11-13 19:37:08 +01:00
return - 1 * $error ;
2020-05-21 15:05:19 +02:00
} else {
2014-03-05 10:30:06 +01:00
$this -> db -> commit ();
return 1 ;
}
2020-10-31 14:32:18 +01:00
}
/**
* Delete object in database
*
* @ param User $user User that deletes
* @ param int $notrigger 0 = launch triggers after , 1 = disable triggers
2023-12-01 19:51:32 +01:00
* @ return int Return integer < 0 if KO , > 0 if OK
2020-10-31 14:32:18 +01:00
*/
public function delete ( $user , $notrigger = 0 )
{
2019-11-13 19:37:08 +01:00
$error = 0 ;
2014-03-05 10:30:06 +01:00
$this -> db -> begin ();
2021-02-26 14:25:17 +01:00
if ( ! $error ) {
2022-12-28 13:04:11 +01:00
$sql = " DELETE FROM " . $this -> db -> prefix () . self :: $_table_element ;
2021-03-14 12:20:23 +01:00
$sql .= " WHERE rowid= " . (( int ) $this -> id );
2014-03-05 10:30:06 +01:00
2020-10-31 14:32:18 +01:00
dol_syslog ( get_class ( $this ) . " ::delete " , LOG_DEBUG );
$resql = $this -> db -> query ( $sql );
2021-02-26 14:25:17 +01:00
if ( ! $resql ) {
2023-12-04 13:49:31 +01:00
$error ++ ;
$this -> errors [] = " Error " . $this -> db -> lasterror ();
2021-02-26 14:25:17 +01:00
}
2014-03-05 10:30:06 +01:00
}
2020-10-31 14:32:18 +01:00
// Commit or rollback
2021-02-26 14:25:17 +01:00
if ( $error ) {
foreach ( $this -> errors as $errmsg ) {
2020-10-31 14:32:18 +01:00
dol_syslog ( get_class ( $this ) . " ::delete " . $errmsg , LOG_ERR );
$this -> error .= ( $this -> error ? ', ' . $errmsg : $errmsg );
2014-03-05 10:30:06 +01:00
}
$this -> db -> rollback ();
2019-11-13 19:37:08 +01:00
return - 1 * $error ;
2020-05-21 15:05:19 +02:00
} else {
2014-03-05 10:30:06 +01:00
$this -> db -> commit ();
return 1 ;
}
}
/**
* Load an object from its id and create a new one in database
*
2019-04-25 12:11:32 +02:00
* @ param User $user User making the clone
2014-03-05 10:30:06 +01:00
* @ param int $fromid Id of object to clone
* @ return int New id of clone
*/
2019-04-25 12:11:32 +02:00
public function createFromClone ( User $user , $fromid )
2014-03-05 10:30:06 +01:00
{
2020-04-10 10:59:32 +02:00
$error = 0 ;
2014-03-05 10:30:06 +01:00
2020-04-10 10:59:32 +02:00
$object = new Productbatch ( $this -> db );
2014-03-05 10:30:06 +01:00
2021-02-26 14:25:17 +01:00
$this -> db -> begin ();
2014-03-05 10:30:06 +01:00
// Load source object
$object -> fetch ( $fromid );
2020-04-10 10:59:32 +02:00
$object -> id = 0 ;
$object -> statut = 0 ;
2014-03-05 10:30:06 +01:00
// Clear fields
// ...
// Create clone
2020-04-10 10:59:32 +02:00
$object -> context [ 'createfromclone' ] = 'createfromclone' ;
$result = $object -> create ( $user );
2014-03-05 10:30:06 +01:00
// Other options
2021-02-26 14:25:17 +01:00
if ( $result < 0 ) {
2020-04-10 10:59:32 +02:00
$this -> error = $object -> error ;
$this -> errors = array_merge ( $this -> errors , $object -> errors );
2014-03-05 10:30:06 +01:00
$error ++ ;
}
2021-02-26 14:25:17 +01:00
if ( ! $error ) {
2014-03-05 10:30:06 +01:00
}
2015-02-26 13:03:17 +01:00
unset ( $object -> context [ 'createfromclone' ]);
2014-03-05 10:30:06 +01:00
// End
2021-02-26 14:25:17 +01:00
if ( ! $error ) {
2014-03-05 10:30:06 +01:00
$this -> db -> commit ();
return $object -> id ;
2020-05-21 15:05:19 +02:00
} else {
2014-03-05 10:30:06 +01:00
$this -> db -> rollback ();
return - 1 ;
}
}
/**
* Initialise object with example values
* Id must be 0 if object instance is a specimen
*
2024-03-02 16:38:35 +01:00
* @ return int
2014-03-05 10:30:06 +01:00
*/
2019-02-24 23:32:09 +01:00
public function initAsSpecimen ()
2014-03-05 10:30:06 +01:00
{
2019-11-13 19:37:08 +01:00
$this -> id = 0 ;
2024-02-18 14:56:31 +01:00
$this -> tms = dol_now ();
2024-11-06 20:15:15 +01:00
$this -> fk_product_stock = 0 ;
2019-11-13 19:37:08 +01:00
$this -> sellby = '' ;
$this -> eatby = '' ;
$this -> batch = '' ;
$this -> import_key = '' ;
2024-03-02 16:38:35 +01:00
return 1 ;
2014-03-05 10:30:06 +01:00
}
2014-03-05 11:13:23 +01:00
/**
2024-01-12 17:55:52 +01:00
* Clean fields ( trimming )
2014-03-05 11:30:43 +01:00
*
2018-08-14 10:21:34 +02:00
* @ return void
2014-11-15 18:24:38 +01:00
*/
2018-09-01 23:46:13 +02:00
private function cleanParam ()
2015-08-14 23:53:59 +02:00
{
2021-02-26 14:25:17 +01:00
if ( isset ( $this -> fk_product_stock )) {
2024-11-06 20:15:15 +01:00
$this -> fk_product_stock = ( int ) trim (( string ) $this -> fk_product_stock );
2021-02-26 14:25:17 +01:00
}
if ( isset ( $this -> batch )) {
$this -> batch = trim ( $this -> batch );
}
if ( isset ( $this -> qty )) {
2024-03-19 22:06:56 +01:00
$this -> qty = ( float ) trim (( string ) $this -> qty );
2021-02-26 14:25:17 +01:00
}
if ( isset ( $this -> import_key )) {
$this -> import_key = trim ( $this -> import_key );
}
2014-03-05 10:30:06 +01:00
}
2020-10-31 14:32:18 +01:00
/**
2024-02-09 15:58:49 +01:00
* Find first detailed record that match either eat - by , sell - by or batch within the warehouse
2020-10-31 14:32:18 +01:00
*
2024-01-12 17:55:52 +01:00
* @ param int $fk_product_stock id product_stock for object
2025-02-18 21:48:21 +01:00
* @ param int | '' $eatby eat - by date for object - deprecated : a search must be done on batch number
* @ param int | '' $sellby sell - by date for object - deprecated : a search must be done on batch number
2020-10-31 14:32:18 +01:00
* @ param string $batch_number batch number for object
2023-11-01 15:35:29 +01:00
* @ param int $fk_warehouse filter on warehouse ( use it if you don ' t have $fk_product_stock )
2023-12-01 19:51:32 +01:00
* @ return int Return integer < 0 if KO , > 0 if OK
2020-10-31 14:32:18 +01:00
*/
2025-02-18 21:48:21 +01:00
public function find ( $fk_product_stock = 0 , $eatby = '' , $sellby = '' , $batch_number = '' , $fk_warehouse = 0 )
2020-10-31 14:32:18 +01:00
{
2014-03-05 10:30:06 +01:00
$where = array ();
2024-03-05 00:15:33 +01:00
2014-03-05 10:30:06 +01:00
$sql = " SELECT " ;
2019-11-13 19:37:08 +01:00
$sql .= " t.rowid, " ;
$sql .= " t.tms, " ;
$sql .= " t.fk_product_stock, " ;
$sql .= " t.sellby, " ; // deprecated
$sql .= " t.eatby, " ; // deprecated
$sql .= " t.batch, " ;
$sql .= " t.qty, " ;
$sql .= " t.import_key " ;
2022-01-27 10:12:10 +01:00
$sql .= " FROM " . $this -> db -> prefix () . self :: $_table_element . " as t " ;
2023-11-01 15:35:29 +01:00
if ( $fk_product_stock > 0 || empty ( $fk_warehouse )) {
$sql .= " WHERE t.fk_product_stock = " . (( int ) $fk_product_stock );
} else {
$sql .= " , " . $this -> db -> prefix () . " product_stock as ps " ;
2023-11-06 00:36:49 +01:00
$sql .= " WHERE t.fk_product_stock = ps.rowid AND ps.fk_entrepot = " . (( int ) $fk_warehouse );
2023-11-01 15:35:29 +01:00
}
2021-02-26 14:25:17 +01:00
if ( ! empty ( $eatby )) {
array_push ( $where , " eatby = ' " . $this -> db -> idate ( $eatby ) . " ' " ); // deprecated
}
if ( ! empty ( $sellby )) {
array_push ( $where , " sellby = ' " . $this -> db -> idate ( $sellby ) . " ' " ); // deprecated
}
2017-09-15 10:45:41 +02:00
2021-02-26 14:25:17 +01:00
if ( ! empty ( $batch_number )) {
$sql .= " AND batch = ' " . $this -> db -> escape ( $batch_number ) . " ' " ;
}
2014-03-05 10:30:06 +01:00
2021-02-26 14:25:17 +01:00
if ( ! empty ( $where )) {
2024-03-05 00:15:33 +01:00
$sql .= " AND ( " . $this -> db -> sanitize ( implode ( " OR " , $where ), 1 , 1 , 1 ) . " ) " ;
2021-02-26 14:25:17 +01:00
}
2014-11-15 18:24:38 +01:00
2020-10-31 14:32:18 +01:00
dol_syslog ( get_class ( $this ) . " ::fetch " , LOG_DEBUG );
$resql = $this -> db -> query ( $sql );
2021-02-26 14:25:17 +01:00
if ( $resql ) {
if ( $this -> db -> num_rows ( $resql )) {
2020-10-31 14:32:18 +01:00
$obj = $this -> db -> fetch_object ( $resql );
2014-03-05 10:30:06 +01:00
2020-10-31 14:32:18 +01:00
$this -> id = $obj -> rowid ;
2014-11-15 18:24:38 +01:00
2014-03-05 10:30:06 +01:00
$this -> tms = $this -> db -> jdate ( $obj -> tms );
$this -> fk_product_stock = $obj -> fk_product_stock ;
2023-11-01 15:35:29 +01:00
$this -> sellby = $this -> db -> jdate ( $obj -> sellby ); // deprecated. do no tuse this data.
$this -> eatby = $this -> db -> jdate ( $obj -> eatby ); // deprecated. do not use this data.
2014-03-05 10:30:06 +01:00
$this -> batch = $obj -> batch ;
$this -> qty = $obj -> qty ;
$this -> import_key = $obj -> import_key ;
2020-10-31 14:32:18 +01:00
}
$this -> db -> free ( $resql );
return 1 ;
} else {
2021-02-26 14:25:17 +01:00
$this -> error = " Error " . $this -> db -> lasterror ();
2020-10-31 14:32:18 +01:00
return - 1 ;
}
}
/**
* Return all batch detail records for a given product and warehouse
*
2023-11-01 15:35:29 +01:00
* @ param DoliDB $dbs database object
2024-01-12 17:55:52 +01:00
* @ param int $fk_product_stock id product_stock for object
2025-02-18 21:48:21 +01:00
* @ param int < 0 , 1 > $with_qty 1 = doesn ' t return line with 0 quantity
2023-11-01 15:35:29 +01:00
* @ param int $fk_product If set to a product id , get eatby and sellby from table llx_product_lot
2024-11-06 20:15:15 +01:00
* @ return Productbatch [] | int Return integer < 0 if KO , array of batch
2020-10-31 14:32:18 +01:00
*/
2022-03-01 00:01:13 +01:00
public static function findAll ( $dbs , $fk_product_stock , $with_qty = 0 , $fk_product = 0 )
2020-10-31 14:32:18 +01:00
{
2022-01-27 14:17:14 +01:00
global $conf ;
2021-09-27 15:50:19 +02:00
2014-03-05 10:30:06 +01:00
$ret = array ();
2015-07-13 11:22:18 +02:00
$sql = " SELECT " ;
2019-11-13 19:37:08 +01:00
$sql .= " t.rowid, " ;
$sql .= " t.tms, " ;
$sql .= " t.fk_product_stock, " ;
$sql .= " t.sellby as oldsellby, " ; // deprecated but may not be migrated into new table
$sql .= " t.eatby as oldeatby, " ; // deprecated but may not be migrated into new table
$sql .= " t.batch, " ;
$sql .= " t.qty, " ;
2023-12-04 13:49:31 +01:00
if ( getDolGlobalString ( 'SHIPPING_DISPLAY_STOCK_ENTRY_DATE' )) {
$sql .= " MAX(sm.datem) as date_entree, " ;
}
2019-11-13 19:37:08 +01:00
$sql .= " t.import_key " ;
2021-02-26 14:25:17 +01:00
if ( $fk_product > 0 ) {
2020-10-31 14:32:18 +01:00
$sql .= " , pl.rowid as lotid, pl.eatby as eatby, pl.sellby as sellby " ;
// TODO May add extrafields to ?
}
2022-03-01 00:01:13 +01:00
$sql .= " FROM " . $dbs -> prefix () . " product_batch as t " ;
2023-06-29 13:16:44 +02:00
if ( $fk_product > 0 ) { // Add link to the table of details of a lot
2022-03-01 00:01:13 +01:00
$sql .= " LEFT JOIN " . $dbs -> prefix () . " product_lot as pl ON pl.fk_product = " . (( int ) $fk_product ) . " AND pl.batch = t.batch " ;
2020-10-31 14:32:18 +01:00
// TODO May add extrafields to ?
2016-05-17 14:02:18 +02:00
}
2023-11-27 11:56:32 +01:00
if ( getDolGlobalString ( 'SHIPPING_DISPLAY_STOCK_ENTRY_DATE' )) {
2023-10-16 18:38:37 +02:00
$sql .= ' LEFT JOIN ' . MAIN_DB_PREFIX . 'product_stock AS ps ON (ps.rowid = fk_product_stock)' ;
2024-01-17 10:55:08 +01:00
$sql .= ' LEFT JOIN ' . MAIN_DB_PREFIX . 'stock_mouvement AS sm ON (sm.batch = t.batch AND ps.fk_entrepot=sm.fk_entrepot AND sm.type_mouvement IN (0,3))' ;
2023-10-16 18:38:37 +02:00
}
2021-06-09 15:36:47 +02:00
$sql .= " WHERE fk_product_stock= " . (( int ) $fk_product_stock );
2021-02-26 14:25:17 +01:00
if ( $with_qty ) {
$sql .= " AND t.qty <> 0 " ;
}
2023-11-27 11:56:32 +01:00
if ( getDolGlobalString ( 'SHIPPING_DISPLAY_STOCK_ENTRY_DATE' )) {
2023-10-16 18:38:37 +02:00
$sql .= ' GROUP BY t.rowid, t.tms, t.fk_product_stock,t.sellby,t.eatby , t.batch,t.qty,t.import_key' ;
if ( $fk_product > 0 ) {
$sql .= ', pl.rowid, pl.eatby, pl.sellby' ;
}
}
2021-06-01 21:43:05 +02:00
$sql .= " ORDER BY " ;
// TODO : use product lifo and fifo when product will implement it
2023-11-27 11:56:32 +01:00
if ( getDolGlobalString ( 'SHIPPING_DISPLAY_STOCK_ENTRY_DATE' )) {
2023-10-17 15:51:35 +02:00
$sql .= 'date_entree ASC,t.batch ASC,' ;
}
2023-12-04 13:49:31 +01:00
if ( $fk_product > 0 ) {
$sql .= " pl.eatby ASC, pl.sellby ASC, " ;
}
2021-06-01 21:43:05 +02:00
$sql .= " t.eatby ASC, t.sellby ASC " ;
2023-12-04 13:49:31 +01:00
$sql .= " , t.qty " . ( ! getDolGlobalString ( 'DO_NOT_TRY_TO_DEFRAGMENT_STOCKS_WAREHOUSE' ) ? 'ASC' : 'DESC' ); // Note : qty ASC is important for expedition card, to avoid stock fragmentation
2023-11-14 02:47:12 +01:00
$sql .= " , t.batch ASC " ;
2021-06-01 21:43:05 +02:00
2014-06-12 11:31:53 +02:00
dol_syslog ( " productbatch::findAll " , LOG_DEBUG );
2023-06-29 13:16:44 +02:00
2022-03-01 00:01:13 +01:00
$resql = $dbs -> query ( $sql );
2020-10-31 14:32:18 +01:00
if ( $resql ) {
2022-03-01 00:01:13 +01:00
$num = $dbs -> num_rows ( $resql );
2020-10-31 14:32:18 +01:00
$i = 0 ;
2021-02-26 14:25:17 +01:00
while ( $i < $num ) {
2022-03-01 00:11:30 +01:00
$obj = $dbs -> fetch_object ( $resql );
2014-03-05 10:30:06 +01:00
2022-03-01 00:11:30 +01:00
$tmp = new Productbatch ( $dbs );
2014-03-05 10:30:06 +01:00
$tmp -> id = $obj -> rowid ;
2022-03-01 00:11:30 +01:00
$tmp -> tms = $dbs -> jdate ( $obj -> tms );
2014-03-05 10:30:06 +01:00
$tmp -> fk_product_stock = $obj -> fk_product_stock ;
$tmp -> batch = $obj -> batch ;
$tmp -> qty = $obj -> qty ;
$tmp -> import_key = $obj -> import_key ;
2023-10-16 21:35:00 +02:00
2023-11-27 11:56:32 +01:00
if ( getDolGlobalString ( 'SHIPPING_DISPLAY_STOCK_ENTRY_DATE' )) {
2024-03-12 17:01:59 +01:00
$tmp -> context [ 'stock_entry_date' ] = $dbs -> jdate ( $obj -> date_entree );
2023-10-17 15:51:35 +02:00
}
2023-10-16 20:57:07 +02:00
2024-01-03 19:54:15 +01:00
if ( $fk_product > 0 ) {
// Some properties of the lot
$tmp -> lotid = $obj -> lotid ; // ID in table of the details of properties of each lots
$tmp -> sellby = $dbs -> jdate ( $obj -> sellby ? $obj -> sellby : $obj -> oldsellby );
$tmp -> eatby = $dbs -> jdate ( $obj -> eatby ? $obj -> eatby : $obj -> oldeatby );
}
2014-03-05 10:30:06 +01:00
2019-11-13 19:37:08 +01:00
$ret [ $tmp -> batch ] = $tmp ; // $ret is for a $fk_product_stock and unique key is on $fk_product_stock+batch
2014-03-05 10:30:06 +01:00
$i ++ ;
2020-10-31 14:32:18 +01:00
}
2022-03-01 00:11:30 +01:00
$dbs -> free ( $resql );
2020-10-31 14:32:18 +01:00
return $ret ;
} else {
2023-10-16 21:35:00 +02:00
//$error = "Error ".$dbs->lasterror();
2020-10-31 14:32:18 +01:00
return - 1 ;
}
}
2020-02-21 11:08:34 +01:00
/**
2023-11-01 15:35:29 +01:00
* Return all batch known for a product and a warehouse ( batch that was one day used )
2020-02-21 11:08:34 +01:00
*
* @ param int $fk_product Id of product
* @ param int $fk_warehouse Id of warehouse
* @ param int $qty_min [ = NULL ] Minimum quantity
* @ param string $sortfield [ = NULL ] List of sort fields , separated by comma . Example : 't1.fielda,t2.fieldb'
* @ param string $sortorder [ = NULL ] Sort order , separated by comma . Example : 'ASC,DESC' ;
2024-11-06 20:15:15 +01:00
* @ return int <- 1 , - 1 >| Productbatch [] Return integer < 0 if KO , array of batch
2020-02-21 11:08:34 +01:00
*
* @ throws Exception
*/
2022-03-01 00:01:13 +01:00
public function findAllForProduct ( $fk_product , $fk_warehouse = 0 , $qty_min = null , $sortfield = null , $sortorder = null )
2020-02-21 11:08:34 +01:00
{
$productBatchList = array ();
2020-04-10 10:59:32 +02:00
dol_syslog ( __METHOD__ . ' fk_product=' . $fk_product . ', fk_warehouse=' . $fk_warehouse . ', qty_min=' . $qty_min . ', sortfield=' . $sortfield . ', sortorder=' . $sortorder , LOG_DEBUG );
2020-02-21 11:08:34 +01:00
$sql = " SELECT " ;
$sql .= " pl.rowid " ;
$sql .= " , pl.fk_product " ;
$sql .= " , pl.batch " ;
$sql .= " , pl.sellby " ;
$sql .= " , pl.eatby " ;
$sql .= " , pb.qty " ;
2022-03-01 00:01:13 +01:00
$sql .= " FROM " . $this -> db -> prefix () . " product_lot as pl " ;
$sql .= " LEFT JOIN " . $this -> db -> prefix () . " product as p ON p.rowid = pl.fk_product " ;
$sql .= " LEFT JOIN " . $this -> db -> prefix () . " product_batch AS pb ON pl.batch = pb.batch " ;
2022-06-02 19:39:42 +02:00
$sql .= " LEFT JOIN " . $this -> db -> prefix () . " product_stock AS ps ON ps.rowid = pb.fk_product_stock AND ps.fk_product = " . (( int ) $fk_product );
2020-04-10 10:59:32 +02:00
$sql .= " WHERE p.entity IN ( " . getEntity ( 'product' ) . " ) " ;
2021-08-23 18:56:46 +02:00
$sql .= " AND pl.fk_product = " . (( int ) $fk_product );
2020-02-21 11:08:34 +01:00
if ( $fk_warehouse > 0 ) {
2021-08-23 18:56:46 +02:00
$sql .= " AND ps.fk_entrepot = " . (( int ) $fk_warehouse );
2020-02-21 11:08:34 +01:00
}
if ( $qty_min !== null ) {
2021-08-23 18:56:46 +02:00
$sql .= " AND pb.qty > " . (( float ) price2num ( $qty_min , 'MS' ));
2020-02-21 11:08:34 +01:00
}
2022-03-01 00:01:13 +01:00
$sql .= $this -> db -> order ( $sortfield , $sortorder );
2020-02-21 11:08:34 +01:00
2022-03-01 00:01:13 +01:00
$resql = $this -> db -> query ( $sql );
2020-02-21 11:08:34 +01:00
if ( $resql ) {
2022-03-01 00:01:13 +01:00
while ( $obj = $this -> db -> fetch_object ( $resql )) {
$productBatch = new self ( $this -> db );
2020-02-21 11:08:34 +01:00
$productBatch -> id = $obj -> rowid ;
$productBatch -> fk_product = $obj -> fk_product ;
$productBatch -> batch = $obj -> batch ;
2022-03-01 00:01:13 +01:00
$productBatch -> eatby = $this -> db -> jdate ( $obj -> eatby );
$productBatch -> sellby = $this -> db -> jdate ( $obj -> sellby );
2020-02-21 11:08:34 +01:00
$productBatch -> qty = $obj -> qty ;
$productBatchList [] = $productBatch ;
}
2022-03-01 00:01:13 +01:00
$this -> db -> free ( $resql );
2020-02-21 11:08:34 +01:00
return $productBatchList ;
} else {
2022-03-01 00:01:13 +01:00
dol_syslog ( __METHOD__ . ' Error: ' . $this -> db -> lasterror (), LOG_ERR );
2020-02-21 11:08:34 +01:00
return - 1 ;
}
}
2014-03-05 10:30:06 +01:00
}