2018-10-03 12:22:41 +02:00
< ? php
/* Copyright ( C ) 2003 - 2008 Rodolphe Quiedeville < rodolphe @ quiedeville . org >
* Copyright ( C ) 2005 - 2012 Regis Houssin < regis . houssin @ capnetworks . com >
* Copyright ( C ) 2007 Franky Van Liedekerke < franky . van . liedekerke @ telenet . be >
* Copyright ( C ) 2006 - 2012 Laurent Destailleur < eldy @ users . sourceforge . net >
* Copyright ( C ) 2011 - 2017 Juanjo Menent < jmenent @ 2 byte . es >
* Copyright ( C ) 2013 Florian Henry < florian . henry @ open - concept . pro >
* Copyright ( C ) 2014 Cedric GROSS < c . gross @ kreiz - it . fr >
* Copyright ( C ) 2014 - 2015 Marcos García < marcosgdf @ gmail . com >
2020-11-05 14:30:30 +01:00
* Copyright ( C ) 2014 - 2020 Francis Appels < francis . appels @ yahoo . com >
2018-10-03 12:22:41 +02:00
* Copyright ( C ) 2015 Claudio Aschieri < c . aschieri @ 19. coop >
2022-03-22 13:46:55 +01:00
* Copyright ( C ) 2016 - 2022 Ferran Marcet < fmarcet @ 2 byte . es >
2018-10-10 17:30:44 +02:00
* Copyright ( C ) 2018 Quentin Vial - Gouteyron < quentin . vial - gouteyron @ atm - consulting . fr >
2024-03-02 16:38:35 +01:00
* Copyright ( C ) 2022 - 2024 Frédéric France < frederic . france @ free . fr >
2025-02-03 11:24:16 +01:00
* Copyright ( C ) 2024 - 2025 MDW < mdeweerd @ users . noreply . github . com >
2018-10-03 12:22:41 +02: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 />.
2018-10-03 12:22:41 +02:00
*/
/**
* \file htdocs / reception / class / reception . class . php
* \ingroup reception
2024-01-12 17:18:52 +01:00
* \brief File for class to manage receptions
2018-10-03 12:22:41 +02:00
*/
require_once DOL_DOCUMENT_ROOT . '/core/class/commonobject.class.php' ;
require_once DOL_DOCUMENT_ROOT . " /core/class/commonobjectline.class.php " ;
2020-09-16 02:50:18 +02:00
require_once DOL_DOCUMENT_ROOT . '/core/class/commonincoterm.class.php' ;
2022-08-23 20:01:34 +02:00
if ( isModEnabled ( " propal " )) {
2021-02-26 20:53:03 +01:00
require_once DOL_DOCUMENT_ROOT . '/comm/propal/class/propal.class.php' ;
}
2024-02-27 15:30:37 +01:00
if ( isModEnabled ( 'order' )) {
2021-02-26 20:53:03 +01:00
require_once DOL_DOCUMENT_ROOT . '/commande/class/commande.class.php' ;
}
2018-10-03 12:22:41 +02:00
/**
* Class to manage receptions
*/
class Reception extends CommonObject
{
2020-09-16 02:50:18 +02:00
use CommonIncoterm ;
2022-11-15 17:10:04 +01:00
/**
* @ var string code
*/
public $code = " " ;
2020-12-05 23:53:55 +01:00
/**
* @ var string element name
*/
2019-11-13 18:32:11 +01:00
public $element = " reception " ;
2020-12-05 23:53:55 +01:00
/**
* @ var string Fieldname with ID of parent key if this field has a parent
*/
2019-11-13 18:32:11 +01:00
public $fk_element = " fk_reception " ;
public $table_element = " reception " ;
2024-01-15 09:40:59 +01:00
public $table_element_line = " receptiondet_batch " ;
2024-04-05 13:44:59 +02:00
2019-10-30 10:09:08 +01:00
/**
* @ var string String with name of icon for myobject . Must be the part after the 'object_' into object_myobject . png
*/
2020-04-20 15:57:15 +02:00
public $picto = 'dollyrevert' ;
2018-10-03 12:22:41 +02:00
2024-10-07 14:07:24 +02:00
/**
* @ var int
*/
2020-10-28 17:49:52 +01:00
public $socid ;
2024-10-07 14:07:24 +02:00
/**
* @ var string
*/
2020-10-28 17:49:52 +01:00
public $ref_supplier ;
2020-03-06 14:38:06 +01:00
2024-10-07 14:07:24 +02:00
/**
* @ var int
*/
2020-10-28 17:49:52 +01:00
public $entrepot_id ;
2024-10-07 14:07:24 +02:00
/**
* @ var string
*/
2020-10-28 17:49:52 +01:00
public $tracking_number ;
2024-10-07 14:07:24 +02:00
/**
* @ var string
*/
2020-10-28 17:49:52 +01:00
public $tracking_url ;
2024-10-07 14:07:24 +02:00
/**
* @ var int < 0 , 1 >
*/
2020-10-28 17:49:52 +01:00
public $billed ;
2024-10-07 14:07:24 +02:00
/**
* @ var int | float
*/
FIX|Fix some minor issues on Reception and add a new test for it (#26310)
* reception: reOpen: mirror $this->statut in $this->status
$this->statut is the deprecated variable, $this->status should also get
the correct value.
* reception: setDraft: mirror $this->statut in $this->status
$this->statut is the deprecated variable, $this->status should also get
the correct value.
* reception: add missing $weight field
Fix warning:
Undefined property: Reception::$weight
* societe: add country_id field
* reception: use getDolGlobalInt when suitable
Using empty() implies that the value actually exists on the stdClass at
$conf->global, but it's not always the case. getDolGlobalInt will handle
this smoothly by checking first, which solves warnings like those:
Undefined property: stdClass::$STOCK_CALCULATE_ON_RECEPTION
* ReceptionTest: add new test
The test checks the usual workflow of the Reception class, with, on the
one hand, the common CRUD operations:
- create
- fetch
- update
- delete
And on the other hand, the status handling for Reception:
- valid: STATUS_DRAFT -> STATUS_VALID
- setClosed: STATUS_VALID -> STATUS_CLOSED
- reOpen: STATUS_CLOSED -> STATUS_VALID
- setDraft: STATUS_VALID -> STATUS_DRAFT
The stocks lines are not tested yet, and the error cases, like any other
transition not described above, are not tested either. The permissions
for some of the operations are hardcoded for the test and there is no
failure check when the permission is not set yet.
2023-10-21 16:28:30 +02:00
public $weight ;
2024-10-07 14:07:24 +02:00
/**
* @ var int | float
*/
2020-10-28 17:49:52 +01:00
public $trueWeight ;
2024-10-07 14:07:24 +02:00
/**
* @ var null | float | int
*/
2020-10-28 17:49:52 +01:00
public $weight_units ;
2024-10-07 14:07:24 +02:00
/**
* @ var int | float
*/
2020-10-28 17:49:52 +01:00
public $trueWidth ;
2024-10-07 14:07:24 +02:00
/**
* @ var int
*/
2020-10-28 17:49:52 +01:00
public $width_units ;
2024-10-07 14:07:24 +02:00
/**
* @ var int | float
*/
2020-10-28 17:49:52 +01:00
public $trueHeight ;
2024-10-07 14:07:24 +02:00
/**
* @ var int
*/
2020-10-28 17:49:52 +01:00
public $height_units ;
2024-10-07 14:07:24 +02:00
/**
* @ var int | float
*/
2020-10-28 17:49:52 +01:00
public $trueDepth ;
2024-10-07 14:07:24 +02:00
/**
* @ var int
*/
2020-10-28 17:49:52 +01:00
public $depth_units ;
2024-10-07 14:07:24 +02:00
/**
* @ var string A denormalized value
*/
2020-10-28 17:49:52 +01:00
public $trueSize ;
2024-10-07 14:07:24 +02:00
/**
* @ var int | string
*/
2023-09-01 14:54:35 +02:00
public $size_units ;
2024-10-07 14:07:24 +02:00
/**
* @ var int
*/
2023-11-18 23:25:16 +01:00
public $user_author_id ;
2018-10-03 12:22:41 +02:00
2024-10-07 14:07:24 +02:00
/**
* @ var int | string Planned date of delivery
*/
public $date_delivery ;
2018-12-15 13:58:39 +01:00
2023-02-08 21:57:07 +01:00
/**
2024-08-07 02:49:38 +02:00
* @ var int | string Effective delivery date
2024-10-07 14:07:24 +02:00
* @ deprecated Use $date_reception
2023-02-08 21:57:07 +01:00
* @ see $date_reception
*/
public $date ;
2018-10-03 12:22:41 +02:00
/**
2024-08-07 02:49:38 +02:00
* @ var int | string Effective delivery date
2018-10-03 12:22:41 +02:00
*/
public $date_reception ;
2019-11-02 10:39:05 +01:00
2019-11-10 12:14:39 +01:00
/**
2024-08-07 02:49:38 +02:00
* @ var int | string date_validation
2019-11-10 12:14:39 +01:00
*/
2019-11-02 10:35:43 +01:00
public $date_valid ;
2018-10-03 12:22:41 +02:00
2024-10-07 14:07:24 +02:00
/**
* @ var array < int , string >
*/
2020-10-28 17:49:52 +01:00
public $meths ;
2024-10-07 14:07:24 +02:00
/**
* @ var array < array { rowid : int , code : string , libelle : string , description : string , tracking : string , active : string } >
*/
2020-10-28 17:49:52 +01:00
public $listmeths ; // List of carriers
2018-10-03 12:22:41 +02:00
2022-12-12 12:53:50 +01:00
/**
2024-04-29 12:03:01 +02:00
* @ var ReceptionLineBatch [] | CommandeFournisseurDispatch []
2022-12-12 12:53:50 +01:00
*/
2020-11-28 14:47:39 +01:00
public $lines = array ();
2018-10-03 12:22:41 +02:00
2024-10-07 14:07:24 +02:00
/**
* @ var stdClass [] detail of lot and qty = array ( id in receptiondet_batch , batch , qty )
* // We can use this to know warehouse planned to be used for each lot.
*/
2022-11-18 10:27:49 +01:00
public $detail_batch ;
2018-10-03 12:22:41 +02:00
const STATUS_DRAFT = 0 ;
const STATUS_VALIDATED = 1 ;
const STATUS_CLOSED = 2 ;
/**
* Constructor
*
* @ param DoliDB $db Database handler
*/
2020-10-28 17:49:52 +01:00
public function __construct ( $db )
2018-10-03 12:22:41 +02:00
{
$this -> db = $db ;
2024-05-05 00:34:19 +02:00
$this -> ismultientitymanaged = 1 ; // 0=No test on entity, 1=Test with field entity, 2=Test with link by societe
2018-10-03 12:22:41 +02:00
}
/**
* Return next contract ref
*
* @ param Societe $soc Thirdparty object
* @ return string Free reference for contract
*/
2020-10-28 17:49:52 +01:00
public function getNextNumRef ( $soc )
2018-10-03 12:22:41 +02:00
{
global $langs , $conf ;
$langs -> load ( " receptions " );
2023-11-27 11:56:32 +01:00
if ( getDolGlobalString ( 'RECEPTION_ADDON_NUMBER' )) {
2018-10-03 12:22:41 +02:00
$mybool = false ;
2023-11-27 13:26:44 +01:00
$file = getDolGlobalString ( 'RECEPTION_ADDON_NUMBER' ) . " .php " ;
2024-01-05 04:18:53 +01:00
$classname = getDolGlobalString ( 'RECEPTION_ADDON_NUMBER' );
2018-10-03 12:22:41 +02:00
2020-10-28 17:49:52 +01:00
// Include file with class
$dirmodels = array_merge ( array ( '/' ), ( array ) $conf -> modules_parts [ 'models' ]);
2018-10-03 12:22:41 +02:00
2020-10-28 17:49:52 +01:00
foreach ( $dirmodels as $reldir ) {
$dir = dol_buildpath ( $reldir . " core/modules/reception/ " );
2018-10-03 12:22:41 +02:00
2020-10-28 17:49:52 +01:00
// Load file with numbering class (if found)
2024-03-21 13:22:15 +01:00
$mybool = (( bool ) @ include_once $dir . $file ) || $mybool ;
2020-10-28 17:49:52 +01:00
}
2018-10-03 12:22:41 +02:00
2021-02-26 20:53:03 +01:00
if ( ! $mybool ) {
2024-01-20 09:22:38 +01:00
dol_print_error ( null , " Failed to include file " . $file );
2020-10-28 17:49:52 +01:00
return '' ;
}
2018-10-03 12:22:41 +02:00
$obj = new $classname ();
2024-10-07 14:07:24 +02:00
'@phan-var-force ModelNumRefReception $obj' ;
2018-12-15 13:58:39 +01:00
2019-01-27 11:55:16 +01:00
$numref = $obj -> getNextValue ( $soc , $this );
2018-12-15 13:58:39 +01:00
2021-02-26 20:53:03 +01:00
if ( $numref != " " ) {
2018-10-03 12:22:41 +02:00
return $numref ;
2020-05-21 15:05:19 +02:00
} else {
2019-01-27 11:55:16 +01:00
dol_print_error ( $this -> db , get_class ( $this ) . " ::getNextNumRef " . $obj -> error );
2018-10-03 12:22:41 +02:00
return " " ;
}
2020-10-28 17:49:52 +01:00
} else {
print $langs -> trans ( " Error " ) . " " . $langs -> trans ( " Error_RECEPTION_ADDON_NUMBER_NotDefined " );
return " " ;
}
2018-10-03 12:22:41 +02:00
}
/**
* Create reception en base
*
2024-01-12 17:18:52 +01:00
* @ param User $user Object du user qui cree
2018-10-17 11:56:32 +02:00
* @ param int $notrigger 1 = Does not execute triggers , 0 = execute triggers
2023-12-06 15:46:39 +01:00
* @ return int Return integer < 0 si erreur , id reception creee si ok
2018-10-03 12:22:41 +02:00
*/
2020-10-28 17:49:52 +01:00
public function create ( $user , $notrigger = 0 )
2018-10-03 12:22:41 +02:00
{
2023-08-06 00:16:25 +02:00
global $conf ;
2018-10-03 12:22:41 +02:00
2019-11-13 18:32:11 +01:00
$now = dol_now ();
2018-10-03 12:22:41 +02:00
2019-11-13 18:32:11 +01:00
require_once DOL_DOCUMENT_ROOT . '/product/stock/class/mouvementstock.class.php' ;
2018-10-03 12:22:41 +02:00
$error = 0 ;
// Clean parameters
$this -> tracking_number = dol_sanitizeFileName ( $this -> tracking_number );
2021-02-26 20:53:03 +01:00
if ( empty ( $this -> fk_project )) {
$this -> fk_project = 0 ;
}
if ( empty ( $this -> weight_units )) {
$this -> weight_units = 0 ;
}
if ( empty ( $this -> size_units )) {
$this -> size_units = 0 ;
}
2018-10-03 12:22:41 +02:00
$this -> user = $user ;
$this -> db -> begin ();
$sql = " INSERT INTO " . MAIN_DB_PREFIX . " reception ( " ;
2019-11-13 18:32:11 +01:00
$sql .= " ref " ;
$sql .= " , entity " ;
$sql .= " , ref_supplier " ;
$sql .= " , date_creation " ;
$sql .= " , fk_user_author " ;
$sql .= " , date_reception " ;
$sql .= " , date_delivery " ;
$sql .= " , fk_soc " ;
$sql .= " , fk_projet " ;
$sql .= " , fk_shipping_method " ;
$sql .= " , tracking_number " ;
$sql .= " , weight " ;
$sql .= " , size " ;
$sql .= " , width " ;
$sql .= " , height " ;
$sql .= " , weight_units " ;
$sql .= " , size_units " ;
$sql .= " , note_private " ;
$sql .= " , note_public " ;
$sql .= " , model_pdf " ;
$sql .= " , fk_incoterms, location_incoterms " ;
$sql .= " ) VALUES ( " ;
$sql .= " '(PROV)' " ;
2021-09-03 21:25:17 +02:00
$sql .= " , " . (( int ) $conf -> entity );
2019-11-13 18:32:11 +01:00
$sql .= " , " . ( $this -> ref_supplier ? " ' " . $this -> db -> escape ( $this -> ref_supplier ) . " ' " : " null " );
$sql .= " , ' " . $this -> db -> idate ( $now ) . " ' " ;
2021-09-03 21:25:17 +02:00
$sql .= " , " . (( int ) $user -> id );
2019-11-13 18:32:11 +01:00
$sql .= " , " . ( $this -> date_reception > 0 ? " ' " . $this -> db -> idate ( $this -> date_reception ) . " ' " : " null " );
$sql .= " , " . ( $this -> date_delivery > 0 ? " ' " . $this -> db -> idate ( $this -> date_delivery ) . " ' " : " null " );
2021-09-03 21:25:17 +02:00
$sql .= " , " . (( int ) $this -> socid );
$sql .= " , " . (( int ) $this -> fk_project );
$sql .= " , " . ( $this -> shipping_method_id > 0 ? (( int ) $this -> shipping_method_id ) : " null " );
2019-11-13 18:32:11 +01:00
$sql .= " , ' " . $this -> db -> escape ( $this -> tracking_number ) . " ' " ;
2023-12-04 13:53:48 +01:00
$sql .= " , " . ( is_null ( $this -> weight ) ? " NULL " : (( float ) $this -> weight ));
$sql .= " , " . ( is_null ( $this -> trueDepth ) ? " NULL " : (( float ) $this -> trueDepth ));
$sql .= " , " . ( is_null ( $this -> trueWidth ) ? " NULL " : (( float ) $this -> trueWidth ));
$sql .= " , " . ( is_null ( $this -> trueHeight ) ? " NULL " : (( float ) $this -> trueHeight ));
$sql .= " , " . ( is_null ( $this -> weight_units ) ? " NULL " : (( float ) $this -> weight_units ));
$sql .= " , " . ( is_null ( $this -> size_units ) ? " NULL " : (( float ) $this -> size_units ));
2019-11-13 18:32:11 +01:00
$sql .= " , " . ( ! empty ( $this -> note_private ) ? " ' " . $this -> db -> escape ( $this -> note_private ) . " ' " : " null " );
$sql .= " , " . ( ! empty ( $this -> note_public ) ? " ' " . $this -> db -> escape ( $this -> note_public ) . " ' " : " null " );
$sql .= " , " . ( ! empty ( $this -> model_pdf ) ? " ' " . $this -> db -> escape ( $this -> model_pdf ) . " ' " : " null " );
2020-10-28 17:49:52 +01:00
$sql .= " , " . ( int ) $this -> fk_incoterms ;
$sql .= " , ' " . $this -> db -> escape ( $this -> location_incoterms ) . " ' " ;
2019-11-13 18:32:11 +01:00
$sql .= " ) " ;
2018-10-03 12:22:41 +02:00
dol_syslog ( get_class ( $this ) . " ::create " , LOG_DEBUG );
2018-12-15 13:58:39 +01:00
2019-11-13 18:32:11 +01:00
$resql = $this -> db -> query ( $sql );
2018-12-15 13:58:39 +01:00
2021-02-26 20:53:03 +01:00
if ( $resql ) {
2018-10-03 12:22:41 +02:00
$this -> id = $this -> db -> last_insert_id ( MAIN_DB_PREFIX . " reception " );
$sql = " UPDATE " . MAIN_DB_PREFIX . " reception " ;
2024-04-29 11:04:19 +02:00
$sql .= " SET ref = '(PROV " . (( int ) $this -> id ) . " )' " ;
2021-08-27 16:33:03 +02:00
$sql .= " WHERE rowid = " . (( int ) $this -> id );
2018-10-03 12:22:41 +02:00
dol_syslog ( get_class ( $this ) . " ::create " , LOG_DEBUG );
2021-02-26 20:53:03 +01:00
if ( $this -> db -> query ( $sql )) {
2019-06-29 16:29:32 +02:00
// Insert of lines
2019-11-13 18:32:11 +01:00
$num = count ( $this -> lines );
2021-02-26 20:53:03 +01:00
for ( $i = 0 ; $i < $num ; $i ++ ) {
2018-10-17 15:36:47 +02:00
$this -> lines [ $i ] -> fk_reception = $this -> id ;
2018-12-15 13:58:39 +01:00
2021-02-26 20:53:03 +01:00
if ( ! $this -> lines [ $i ] -> create ( $user ) > 0 ) {
2018-10-17 15:36:47 +02:00
$error ++ ;
2018-10-03 12:22:41 +02:00
}
}
2021-02-26 20:53:03 +01:00
if ( ! $error && $this -> id && $this -> origin_id ) {
2018-10-03 12:22:41 +02:00
$ret = $this -> add_object_linked ();
2021-02-26 20:53:03 +01:00
if ( ! $ret ) {
2018-10-03 12:22:41 +02:00
$error ++ ;
}
}
2020-04-23 12:54:28 +02:00
// Create extrafields
2021-02-26 20:53:03 +01:00
if ( ! $error ) {
2020-04-25 13:52:07 +02:00
$result = $this -> insertExtraFields ();
2021-02-26 20:53:03 +01:00
if ( $result < 0 ) {
$error ++ ;
}
2018-10-03 12:22:41 +02:00
}
2021-02-26 20:53:03 +01:00
if ( ! $error && ! $notrigger ) {
2020-10-28 17:49:52 +01:00
// Call trigger
$result = $this -> call_trigger ( 'RECEPTION_CREATE' , $user );
2021-02-26 20:53:03 +01:00
if ( $result < 0 ) {
$error ++ ;
}
2020-10-28 17:49:52 +01:00
// End call triggers
2020-04-23 12:54:28 +02:00
}
2018-10-03 12:22:41 +02:00
2021-02-26 20:53:03 +01:00
if ( ! $error ) {
2020-04-23 12:54:28 +02:00
$this -> db -> commit ();
return $this -> id ;
2020-05-21 15:05:19 +02:00
} else {
2021-02-26 20:53:03 +01:00
foreach ( $this -> errors as $errmsg ) {
2020-04-23 12:54:28 +02:00
dol_syslog ( get_class ( $this ) . " ::create " . $errmsg , LOG_ERR );
$this -> error .= ( $this -> error ? ', ' . $errmsg : $errmsg );
}
2018-10-03 12:22:41 +02:00
$this -> db -> rollback ();
2020-04-23 12:54:28 +02:00
return - 1 * $error ;
2018-10-03 12:22:41 +02:00
}
2020-05-21 15:05:19 +02:00
} else {
2018-10-03 12:22:41 +02:00
$error ++ ;
2019-11-13 18:32:11 +01:00
$this -> error = $this -> db -> lasterror () . " - sql= $sql " ;
2018-10-03 12:22:41 +02:00
$this -> db -> rollback ();
return - 2 ;
}
2020-05-21 15:05:19 +02:00
} else {
2018-10-03 12:22:41 +02:00
$error ++ ;
2019-11-13 18:32:11 +01:00
$this -> error = $this -> db -> error () . " - sql= $sql " ;
2018-10-03 12:22:41 +02:00
$this -> db -> rollback ();
return - 1 ;
}
}
2018-12-15 13:58:39 +01:00
2018-10-03 12:22:41 +02:00
/**
* Get object and lines from database
*
* @ param int $id Id of object to load
* @ param string $ref Ref of object
* @ param string $ref_ext External reference of object
* @ return int > 0 if OK , 0 if not found , < 0 if KO
*/
2022-09-23 09:21:07 +02:00
public function fetch ( $id , $ref = '' , $ref_ext = '' )
2018-10-03 12:22:41 +02:00
{
// Check parameters
2021-02-26 20:53:03 +01:00
if ( empty ( $id ) && empty ( $ref ) && empty ( $ref_ext )) {
return - 1 ;
}
2018-10-03 12:22:41 +02:00
2023-10-18 03:44:07 +02:00
$sql = " SELECT e.rowid, e.entity, e.ref, e.fk_soc as socid, e.date_creation, e.ref_supplier, e.ref_ext, e.fk_user_author, e.fk_statut as status, e.billed " ;
2019-11-13 18:32:11 +01:00
$sql .= " , e.weight, e.weight_units, e.size, e.size_units, e.width, e.height " ;
2024-11-05 17:30:47 +01:00
$sql .= " , e.date_reception as date_reception, e.model_pdf, e.date_delivery, e.date_valid " ;
2019-11-13 18:32:11 +01:00
$sql .= " , e.fk_shipping_method, e.tracking_number " ;
$sql .= " , el.fk_source as origin_id, el.sourcetype as origin " ;
$sql .= " , e.note_private, e.note_public " ;
2020-10-28 17:49:52 +01:00
$sql .= ', e.fk_incoterms, e.location_incoterms' ;
$sql .= ', i.libelle as label_incoterms' ;
2019-11-13 18:32:11 +01:00
$sql .= " FROM " . MAIN_DB_PREFIX . " reception as e " ;
$sql .= " LEFT JOIN " . MAIN_DB_PREFIX . " element_element as el ON el.fk_target = e.rowid AND el.targettype = ' " . $this -> db -> escape ( $this -> element ) . " ' " ;
$sql .= ' LEFT JOIN ' . MAIN_DB_PREFIX . 'c_incoterms as i ON e.fk_incoterms = i.rowid' ;
$sql .= " WHERE e.entity IN ( " . getEntity ( 'reception' ) . " ) " ;
2021-02-26 20:53:03 +01:00
if ( $id ) {
2023-10-18 03:44:07 +02:00
$sql .= " AND e.rowid = " . (( int ) $id );
2021-02-26 20:53:03 +01:00
}
if ( $ref ) {
2023-10-18 03:44:07 +02:00
$sql .= " AND e.ref = ' " . $this -> db -> escape ( $ref ) . " ' " ;
2021-02-26 20:53:03 +01:00
}
if ( $ref_ext ) {
2023-10-18 03:44:07 +02:00
$sql .= " AND e.ref_ext = ' " . $this -> db -> escape ( $ref_ext ) . " ' " ;
2021-02-26 20:53:03 +01:00
}
2018-10-03 12:22:41 +02:00
dol_syslog ( get_class ( $this ) . " ::fetch " , LOG_DEBUG );
$result = $this -> db -> query ( $sql );
2021-02-26 20:53:03 +01:00
if ( $result ) {
if ( $this -> db -> num_rows ( $result )) {
2018-10-03 12:22:41 +02:00
$obj = $this -> db -> fetch_object ( $result );
$this -> id = $obj -> rowid ;
2023-08-23 11:24:09 +02:00
$this -> entity = $obj -> entity ;
2018-10-03 12:22:41 +02:00
$this -> ref = $obj -> ref ;
$this -> socid = $obj -> socid ;
2019-11-13 18:32:11 +01:00
$this -> ref_supplier = $obj -> ref_supplier ;
2020-12-01 02:41:19 +01:00
$this -> ref_ext = $obj -> ref_ext ;
2023-09-03 21:38:11 +02:00
$this -> statut = $obj -> status ;
$this -> status = $obj -> status ;
2023-10-18 03:44:07 +02:00
$this -> billed = $obj -> billed ;
2018-10-03 12:22:41 +02:00
$this -> user_author_id = $obj -> fk_user_author ;
$this -> date_creation = $this -> db -> jdate ( $obj -> date_creation );
2023-02-08 21:57:07 +01:00
$this -> date = $this -> db -> jdate ( $obj -> date_reception ); // TODO deprecated
2019-11-13 18:32:11 +01:00
$this -> date_reception = $this -> db -> jdate ( $obj -> date_reception ); // Date real
2024-01-12 17:18:52 +01:00
$this -> date_delivery = $this -> db -> jdate ( $obj -> date_delivery ); // Date planned
2024-11-05 17:30:47 +01:00
$this -> date_valid = $this -> db -> jdate ( $obj -> date_valid ); // Date validation
2020-08-18 14:48:38 +02:00
$this -> model_pdf = $obj -> model_pdf ;
2019-11-13 18:32:11 +01:00
$this -> shipping_method_id = $obj -> fk_shipping_method ;
2018-10-03 12:22:41 +02:00
$this -> tracking_number = $obj -> tracking_number ;
2019-11-13 18:32:11 +01:00
$this -> origin = ( $obj -> origin ? $obj -> origin : 'commande' ); // For compatibility
2024-04-29 11:04:19 +02:00
$this -> origin_type = ( $obj -> origin ? $obj -> origin : 'commande' ); // For compatibility
2018-10-03 12:22:41 +02:00
$this -> origin_id = $obj -> origin_id ;
$this -> trueWeight = $obj -> weight ;
$this -> weight_units = $obj -> weight_units ;
$this -> trueWidth = $obj -> width ;
$this -> width_units = $obj -> size_units ;
$this -> trueHeight = $obj -> height ;
$this -> height_units = $obj -> size_units ;
$this -> trueDepth = $obj -> size ;
$this -> depth_units = $obj -> size_units ;
$this -> note_public = $obj -> note_public ;
$this -> note_private = $obj -> note_private ;
// A denormalized value
2019-11-13 18:32:11 +01:00
$this -> trueSize = $obj -> size . " x " . $obj -> width . " x " . $obj -> height ;
$this -> size_units = $obj -> size_units ;
2018-10-03 12:22:41 +02:00
//Incoterms
$this -> fk_incoterms = $obj -> fk_incoterms ;
$this -> location_incoterms = $obj -> location_incoterms ;
2019-06-25 13:00:02 +02:00
$this -> label_incoterms = $obj -> label_incoterms ;
2018-10-03 12:22:41 +02:00
$this -> db -> free ( $result );
2022-09-21 01:13:53 +02:00
//$file = $conf->reception->dir_output."/".get_exdir(0, 0, 0, 1, $this, 'reception')."/".$this->id.".pdf";
//$this->pdf_filename = $file;
2018-10-03 12:22:41 +02:00
// Tracking url
2018-12-15 18:30:35 +01:00
$this -> getUrlTrackingStatus ( $obj -> tracking_number );
2018-10-03 12:22:41 +02:00
/*
2019-01-17 15:57:17 +01:00
* Thirdparty
2018-10-03 12:22:41 +02:00
*/
2019-11-13 18:32:11 +01:00
$result = $this -> fetch_thirdparty ();
2018-12-15 13:58:39 +01:00
2018-10-03 12:22:41 +02:00
// Retrieve all extrafields for reception
// fetch optionals attributes and labels
require_once DOL_DOCUMENT_ROOT . '/core/class/extrafields.class.php' ;
2019-11-13 18:32:11 +01:00
$extrafields = new ExtraFields ( $this -> db );
2019-10-06 14:41:52 +02:00
$extrafields -> fetch_name_optionals_label ( $this -> table_element , true );
2020-03-27 16:02:58 +01:00
$this -> fetch_optionals ();
2018-10-03 12:22:41 +02:00
/*
* Lines
*/
2019-11-13 18:32:11 +01:00
$result = $this -> fetch_lines ();
2021-02-26 20:53:03 +01:00
if ( $result < 0 ) {
2018-10-03 12:22:41 +02:00
return - 3 ;
}
return 1 ;
2020-05-21 15:05:19 +02:00
} else {
2018-10-03 12:22:41 +02:00
dol_syslog ( get_class ( $this ) . '::Fetch no reception found' , LOG_ERR );
2023-09-03 22:34:14 +02:00
$this -> error = 'Reception with id ' . $id . ' not found' ;
2018-10-03 12:22:41 +02:00
return 0 ;
}
2020-05-21 15:05:19 +02:00
} else {
2019-11-13 18:32:11 +01:00
$this -> error = $this -> db -> error ();
2018-10-03 12:22:41 +02:00
return - 1 ;
}
}
/**
* Validate object and update stock if option enabled
*
* @ param User $user Object user that validate
2020-10-28 17:49:52 +01:00
* @ param int $notrigger 1 = Does not execute triggers , 0 = execute triggers
2023-12-06 15:46:39 +01:00
* @ return int Return integer < 0 if OK , > 0 if KO
2018-10-03 12:22:41 +02:00
*/
2020-10-28 17:49:52 +01:00
public function valid ( $user , $notrigger = 0 )
2018-10-03 12:22:41 +02:00
{
global $conf , $langs ;
2020-10-28 17:49:52 +01:00
require_once DOL_DOCUMENT_ROOT . '/core/lib/files.lib.php' ;
2018-10-03 12:22:41 +02:00
dol_syslog ( get_class ( $this ) . " ::valid " );
// Protection
2021-02-26 20:53:03 +01:00
if ( $this -> statut ) {
2018-10-03 12:22:41 +02:00
dol_syslog ( get_class ( $this ) . " ::valid no draft status " , LOG_WARNING );
return 0 ;
}
2023-11-27 13:26:44 +01:00
if ( ! (( ! getDolGlobalInt ( 'MAIN_USE_ADVANCED_PERMS' ) && $user -> hasRight ( 'reception' , 'creer' ))
|| ( getDolGlobalInt ( 'MAIN_USE_ADVANCED_PERMS' ) && $user -> hasRight ( 'reception' , 'reception_advance' , 'validate' )))) {
2019-11-13 18:32:11 +01:00
$this -> error = 'Permission denied' ;
2018-10-03 12:22:41 +02:00
dol_syslog ( get_class ( $this ) . " ::valid " . $this -> error , LOG_ERR );
return - 1 ;
}
$this -> db -> begin ();
$error = 0 ;
// Define new ref
$soc = new Societe ( $this -> db );
$soc -> fetch ( $this -> socid );
2018-12-15 13:58:39 +01:00
2018-10-03 12:22:41 +02:00
// Define new ref
2021-02-26 20:53:03 +01:00
if ( ! $error && ( preg_match ( '/^[\(]?PROV/i' , $this -> ref ) || empty ( $this -> ref ))) { // empty should not happened, but when it occurs, the test save life
2018-10-03 12:22:41 +02:00
$numref = $this -> getNextNumRef ( $soc );
2020-05-21 15:05:19 +02:00
} else {
2018-10-03 12:22:41 +02:00
$numref = $this -> ref ;
}
2018-12-15 13:58:39 +01:00
2020-10-28 17:49:52 +01:00
$this -> newref = dol_sanitizeFileName ( $numref );
2018-10-03 12:22:41 +02:00
2019-11-13 18:32:11 +01:00
$now = dol_now ();
2018-10-03 12:22:41 +02:00
// Validate
$sql = " UPDATE " . MAIN_DB_PREFIX . " reception SET " ;
2019-11-13 18:32:11 +01:00
$sql .= " ref=' " . $this -> db -> escape ( $numref ) . " ' " ;
$sql .= " , fk_statut = 1 " ;
$sql .= " , date_valid = ' " . $this -> db -> idate ( $now ) . " ' " ;
2024-10-29 02:18:17 +01:00
$sql .= " , fk_user_valid = " . (( int ) $user -> id );
2021-08-27 16:33:03 +02:00
$sql .= " WHERE rowid = " . (( int ) $this -> id );
2018-10-03 12:22:41 +02:00
dol_syslog ( get_class ( $this ) . " ::valid update reception " , LOG_DEBUG );
2019-11-13 18:32:11 +01:00
$resql = $this -> db -> query ( $sql );
2021-02-26 20:53:03 +01:00
if ( ! $resql ) {
2019-11-13 18:32:11 +01:00
$this -> error = $this -> db -> lasterror ();
2018-10-03 12:22:41 +02:00
$error ++ ;
}
2024-01-12 17:18:52 +01:00
// If stock increment is done on reception (recommended choice)
FIX|Fix some minor issues on Reception and add a new test for it (#26310)
* reception: reOpen: mirror $this->statut in $this->status
$this->statut is the deprecated variable, $this->status should also get
the correct value.
* reception: setDraft: mirror $this->statut in $this->status
$this->statut is the deprecated variable, $this->status should also get
the correct value.
* reception: add missing $weight field
Fix warning:
Undefined property: Reception::$weight
* societe: add country_id field
* reception: use getDolGlobalInt when suitable
Using empty() implies that the value actually exists on the stdClass at
$conf->global, but it's not always the case. getDolGlobalInt will handle
this smoothly by checking first, which solves warnings like those:
Undefined property: stdClass::$STOCK_CALCULATE_ON_RECEPTION
* ReceptionTest: add new test
The test checks the usual workflow of the Reception class, with, on the
one hand, the common CRUD operations:
- create
- fetch
- update
- delete
And on the other hand, the status handling for Reception:
- valid: STATUS_DRAFT -> STATUS_VALID
- setClosed: STATUS_VALID -> STATUS_CLOSED
- reOpen: STATUS_CLOSED -> STATUS_VALID
- setDraft: STATUS_VALID -> STATUS_DRAFT
The stocks lines are not tested yet, and the error cases, like any other
transition not described above, are not tested either. The permissions
for some of the operations are hardcoded for the test and there is no
failure check when the permission is not set yet.
2023-10-21 16:28:30 +02:00
if ( ! $error && isModEnabled ( 'stock' ) && getDolGlobalInt ( 'STOCK_CALCULATE_ON_RECEPTION' )) {
2018-10-03 12:22:41 +02:00
require_once DOL_DOCUMENT_ROOT . '/product/stock/class/mouvementstock.class.php' ;
$langs -> load ( " agenda " );
// Loop on each product line to add a stock movement
// TODO in future, reception lines may not be linked to order line
2022-03-22 11:17:27 +01:00
$sql = " SELECT cd.fk_product, cd.subprice, cd.remise_percent, " ;
2019-11-13 18:32:11 +01:00
$sql .= " ed.rowid, ed.qty, ed.fk_entrepot, " ;
2021-09-28 13:22:44 +02:00
$sql .= " ed.eatby, ed.sellby, ed.batch, " ;
$sql .= " ed.cost_price " ;
2019-11-13 18:32:11 +01:00
$sql .= " FROM " . MAIN_DB_PREFIX . " commande_fournisseurdet as cd, " ;
2024-01-15 09:40:59 +01:00
$sql .= " " . MAIN_DB_PREFIX . " receptiondet_batch as ed " ;
2021-08-23 19:33:24 +02:00
$sql .= " WHERE ed.fk_reception = " . (( int ) $this -> id );
2024-03-19 15:49:42 +01:00
$sql .= " AND cd.rowid = ed.fk_elementdet " ;
2018-12-15 13:58:39 +01:00
2018-10-03 12:22:41 +02:00
dol_syslog ( get_class ( $this ) . " ::valid select details " , LOG_DEBUG );
2019-11-13 18:32:11 +01:00
$resql = $this -> db -> query ( $sql );
2021-02-26 20:53:03 +01:00
if ( $resql ) {
2018-10-03 12:22:41 +02:00
$cpt = $this -> db -> num_rows ( $resql );
2021-02-26 20:53:03 +01:00
for ( $i = 0 ; $i < $cpt ; $i ++ ) {
2018-10-03 12:22:41 +02:00
$obj = $this -> db -> fetch_object ( $resql );
2018-12-15 13:58:39 +01:00
2018-10-09 11:33:41 +02:00
$qty = $obj -> qty ;
2018-12-15 13:58:39 +01:00
2022-11-05 15:39:31 +01:00
if ( $qty == 0 || ( $qty < 0 && ! getDolGlobalInt ( 'RECEPTION_ALLOW_NEGATIVE_QTY' ))) {
2021-02-26 20:53:03 +01:00
continue ;
}
2018-10-03 12:22:41 +02:00
dol_syslog ( get_class ( $this ) . " ::valid movement index " . $i . " ed.rowid= " . $obj -> rowid . " edb.rowid= " . $obj -> edbrowid );
//var_dump($this->lines[$i]);
$mouvS = new MouvementStock ( $this -> db );
$mouvS -> origin = & $this ;
2022-03-22 13:46:55 +01:00
$mouvS -> setOrigin ( $this -> element , $this -> id );
2018-10-03 12:22:41 +02:00
2021-02-26 20:53:03 +01:00
if ( empty ( $obj -> batch )) {
2018-10-03 12:22:41 +02:00
// line without batch detail
// We decrement stock of product (and sub-products) -> update table llx_product_stock (key of this table is fk_product+fk_entrepot) and add a movement record.
2021-11-19 13:46:30 +01:00
$inventorycode = '' ;
2022-06-08 18:27:47 +02:00
$result = $mouvS -> reception ( $user , $obj -> fk_product , $obj -> fk_entrepot , $qty , $obj -> cost_price , $langs -> trans ( " ReceptionValidatedInDolibarr " , $numref ), '' , '' , '' , '' , 0 , $inventorycode );
2022-03-23 17:04:31 +01:00
2022-06-23 11:55:20 +02:00
if ( intval ( $result ) < 0 ) {
2018-10-03 12:22:41 +02:00
$error ++ ;
2024-12-17 20:56:08 +01:00
$this -> setErrorsFromObject ( $mouvS );
2018-10-03 12:22:41 +02:00
break ;
}
2020-05-21 15:05:19 +02:00
} else {
2018-10-03 12:22:41 +02:00
// line with batch detail
// We decrement stock of product (and sub-products) -> update table llx_product_stock (key of this table is fk_product+fk_entrepot) and add a movement record.
2020-10-28 17:49:52 +01:00
// Note: ->fk_origin_stock = id into table llx_product_batch (may be rename into llx_product_stock_batch in another version)
2021-11-19 13:46:30 +01:00
$inventorycode = '' ;
2022-06-08 18:27:47 +02:00
$result = $mouvS -> reception ( $user , $obj -> fk_product , $obj -> fk_entrepot , $qty , $obj -> cost_price , $langs -> trans ( " ReceptionValidatedInDolibarr " , $numref ), $this -> db -> jdate ( $obj -> eatby ), $this -> db -> jdate ( $obj -> sellby ), $obj -> batch , '' , 0 , $inventorycode );
2022-03-23 17:04:31 +01:00
2022-06-23 11:55:20 +02:00
if ( intval ( $result ) < 0 ) {
2018-10-03 12:22:41 +02:00
$error ++ ;
2024-12-17 20:56:08 +01:00
$this -> setErrorsFromObject ( $mouvS );
2018-10-03 12:22:41 +02:00
break ;
}
}
}
2020-05-21 15:05:19 +02:00
} else {
2018-10-03 12:22:41 +02:00
$this -> db -> rollback ();
2019-11-13 18:32:11 +01:00
$this -> error = $this -> db -> error ();
2018-10-03 12:22:41 +02:00
return - 2 ;
}
}
2018-12-15 13:58:39 +01:00
2024-01-11 10:16:18 +01:00
if ( ! $error ) {
2024-04-03 00:51:18 +02:00
// Change status of purchase order to "reception in process" or "totally received"
2024-01-11 10:16:18 +01:00
$status = $this -> getStatusDispatch ();
if ( $status < 0 ) {
$error ++ ;
2022-02-15 09:54:40 +01:00
} else {
2024-01-11 10:16:18 +01:00
$trigger_key = '' ;
2024-04-03 00:51:18 +02:00
if ( $this -> origin_object instanceof CommandeFournisseur && $status == CommandeFournisseur :: STATUS_RECEIVED_COMPLETELY ) {
$ret = $this -> origin_object -> Livraison ( $user , dol_now (), 'tot' , '' );
2024-01-11 10:16:18 +01:00
if ( $ret < 0 ) {
$error ++ ;
2024-04-03 00:51:18 +02:00
$this -> errors = array_merge ( $this -> errors , $this -> origin_object -> errors );
2024-01-11 10:16:18 +01:00
}
} else {
$ret = $this -> setStatut ( $status , $this -> origin_id , 'commande_fournisseur' , $trigger_key );
if ( $ret < 0 ) {
$error ++ ;
}
2022-02-15 09:54:40 +01:00
}
2022-02-14 18:07:18 +01:00
}
2018-10-03 12:22:41 +02:00
}
2021-02-26 20:53:03 +01:00
if ( ! $error && ! $notrigger ) {
2020-10-28 17:49:52 +01:00
// Call trigger
$result = $this -> call_trigger ( 'RECEPTION_VALIDATE' , $user );
2021-02-26 20:53:03 +01:00
if ( $result < 0 ) {
$error ++ ;
}
2020-10-28 17:49:52 +01:00
// End call triggers
2018-10-03 12:22:41 +02:00
}
2021-02-26 20:53:03 +01:00
if ( ! $error ) {
2020-10-28 17:49:52 +01:00
$this -> oldref = $this -> ref ;
2018-10-03 12:22:41 +02:00
// Rename directory if dir was a temporary ref
2021-02-26 20:53:03 +01:00
if ( preg_match ( '/^[\(]?PROV/i' , $this -> ref )) {
2019-07-28 22:26:55 +02:00
// Now we rename also files into index
2019-11-13 18:32:11 +01:00
$sql = 'UPDATE ' . MAIN_DB_PREFIX . " ecm_files set filename = CONCAT(' " . $this -> db -> escape ( $this -> newref ) . " ', SUBSTR(filename, " . ( strlen ( $this -> ref ) + 1 ) . " )), filepath = 'reception/ " . $this -> db -> escape ( $this -> newref ) . " ' " ;
2022-01-03 18:15:19 +01:00
$sql .= " WHERE filename LIKE ' " . $this -> db -> escape ( $this -> ref ) . " %' AND filepath = 'reception/ " . $this -> db -> escape ( $this -> ref ) . " ' AND entity = " . (( int ) $conf -> entity );
2019-07-28 22:26:55 +02:00
$resql = $this -> db -> query ( $sql );
2021-02-26 20:53:03 +01:00
if ( ! $resql ) {
2023-12-04 13:53:48 +01:00
$error ++ ;
$this -> error = $this -> db -> lasterror ();
2021-02-26 20:53:03 +01:00
}
2023-10-31 19:28:11 +01:00
$sql = 'UPDATE ' . MAIN_DB_PREFIX . " ecm_files set filepath = 'reception/ " . $this -> db -> escape ( $this -> newref ) . " ' " ;
$sql .= " WHERE filepath = 'reception/ " . $this -> db -> escape ( $this -> ref ) . " ' and entity = " . $conf -> entity ;
$resql = $this -> db -> query ( $sql );
if ( ! $resql ) {
2023-12-04 13:53:48 +01:00
$error ++ ;
$this -> error = $this -> db -> lasterror ();
2023-10-31 19:28:11 +01:00
}
2019-07-28 22:26:55 +02:00
// We rename directory ($this->ref = old ref, $num = new ref) in order not to lose the attachments
2018-10-03 12:22:41 +02:00
$oldref = dol_sanitizeFileName ( $this -> ref );
$newref = dol_sanitizeFileName ( $numref );
2018-10-09 11:33:41 +02:00
$dirsource = $conf -> reception -> dir_output . '/' . $oldref ;
$dirdest = $conf -> reception -> dir_output . '/' . $newref ;
2021-02-26 20:53:03 +01:00
if ( ! $error && file_exists ( $dirsource )) {
2018-10-03 12:22:41 +02:00
dol_syslog ( get_class ( $this ) . " ::valid rename dir " . $dirsource . " into " . $dirdest );
2021-02-26 20:53:03 +01:00
if ( @ rename ( $dirsource , $dirdest )) {
2020-10-28 17:49:52 +01:00
dol_syslog ( " Rename ok " );
// Rename docs starting with $oldref with $newref
$listoffiles = dol_dir_list ( $conf -> reception -> dir_output . '/' . $newref , 'files' , 1 , '^' . preg_quote ( $oldref , '/' ));
2021-02-26 20:53:03 +01:00
foreach ( $listoffiles as $fileentry ) {
2020-10-28 17:49:52 +01:00
$dirsource = $fileentry [ 'name' ];
$dirdest = preg_replace ( '/^' . preg_quote ( $oldref , '/' ) . '/' , $newref , $dirsource );
$dirsource = $fileentry [ 'path' ] . '/' . $dirsource ;
$dirdest = $fileentry [ 'path' ] . '/' . $dirdest ;
@ rename ( $dirsource , $dirdest );
}
2018-10-03 12:22:41 +02:00
}
}
}
}
// Set new ref and current status
2021-02-26 20:53:03 +01:00
if ( ! $error ) {
2018-10-03 12:22:41 +02:00
$this -> ref = $numref ;
2023-10-20 02:35:18 +02:00
$this -> statut = self :: STATUS_VALIDATED ;
$this -> status = self :: STATUS_VALIDATED ;
2018-10-03 12:22:41 +02:00
}
2021-02-26 20:53:03 +01:00
if ( ! $error ) {
2018-10-03 12:22:41 +02:00
$this -> db -> commit ();
return 1 ;
2020-05-21 15:05:19 +02:00
} else {
2021-02-26 20:53:03 +01:00
foreach ( $this -> errors as $errmsg ) {
2020-10-28 17:49:52 +01:00
dol_syslog ( get_class ( $this ) . " ::valid " . $errmsg , LOG_ERR );
$this -> error .= ( $this -> error ? ', ' . $errmsg : $errmsg );
2018-10-03 12:22:41 +02:00
}
$this -> db -> rollback ();
2019-11-13 18:32:11 +01:00
return - 1 * $error ;
2018-10-03 12:22:41 +02:00
}
}
2022-02-14 18:07:18 +01:00
/**
* Get status from all dispatched lines
*
2023-12-06 15:46:39 +01:00
* @ return int Return integer < 0 if KO , Status of reception if OK
2022-02-14 18:07:18 +01:00
*/
public function getStatusDispatch ()
{
require_once DOL_DOCUMENT_ROOT . '/fourn/class/fournisseur.commande.class.php' ;
require_once DOL_DOCUMENT_ROOT . '/fourn/class/fournisseur.commande.dispatch.class.php' ;
$status = CommandeFournisseur :: STATUS_RECEIVED_PARTIALLY ;
if ( ! empty ( $this -> origin ) && $this -> origin_id > 0 && ( $this -> origin == 'order_supplier' || $this -> origin == 'commandeFournisseur' )) {
2023-11-17 11:19:51 +01:00
if ( empty ( $this -> origin_object )) {
2022-02-14 18:07:18 +01:00
$this -> fetch_origin ();
2024-03-23 21:56:37 +01:00
if ( $this -> origin_object instanceof CommonObject && empty ( $this -> origin_object -> lines )) {
2023-11-17 11:19:51 +01:00
$res = $this -> origin_object -> fetch_lines ();
2025-01-04 10:43:01 +01:00
$this -> commandeFournisseur = null ; // deprecated
2023-11-17 11:19:51 +01:00
if ( $res < 0 ) {
return $res ;
2024-03-13 21:37:09 +01:00
}
2025-01-05 17:47:24 +01:00
} elseif ( $this -> origin_object instanceof CommandeFournisseur && empty ( $this -> origin_object -> lines )) {
$res = $this -> origin_object -> fetch_lines ();
$this -> commandeFournisseur = $this -> origin_object ; // deprecated
2023-11-17 11:19:51 +01:00
if ( $res < 0 ) {
return $res ;
}
2022-02-14 18:07:18 +01:00
}
}
$qty_received = array ();
$qty_wished = array ();
$supplierorderdispatch = new CommandeFournisseurDispatch ( $this -> db );
2024-03-19 15:56:44 +01:00
$filter = array ( 't.fk_element' => $this -> origin_id );
FIX|Fix some minor issues on Reception and add a new test for it (#26310)
* reception: reOpen: mirror $this->statut in $this->status
$this->statut is the deprecated variable, $this->status should also get
the correct value.
* reception: setDraft: mirror $this->statut in $this->status
$this->statut is the deprecated variable, $this->status should also get
the correct value.
* reception: add missing $weight field
Fix warning:
Undefined property: Reception::$weight
* societe: add country_id field
* reception: use getDolGlobalInt when suitable
Using empty() implies that the value actually exists on the stdClass at
$conf->global, but it's not always the case. getDolGlobalInt will handle
this smoothly by checking first, which solves warnings like those:
Undefined property: stdClass::$STOCK_CALCULATE_ON_RECEPTION
* ReceptionTest: add new test
The test checks the usual workflow of the Reception class, with, on the
one hand, the common CRUD operations:
- create
- fetch
- update
- delete
And on the other hand, the status handling for Reception:
- valid: STATUS_DRAFT -> STATUS_VALID
- setClosed: STATUS_VALID -> STATUS_CLOSED
- reOpen: STATUS_CLOSED -> STATUS_VALID
- setDraft: STATUS_VALID -> STATUS_DRAFT
The stocks lines are not tested yet, and the error cases, like any other
transition not described above, are not tested either. The permissions
for some of the operations are hardcoded for the test and there is no
failure check when the permission is not set yet.
2023-10-21 16:28:30 +02:00
if ( getDolGlobalInt ( 'SUPPLIER_ORDER_USE_DISPATCH_STATUS' )) {
2022-02-14 18:07:18 +01:00
$filter [ 't.status' ] = 1 ; // Restrict to lines with status validated
}
$ret = $supplierorderdispatch -> fetchAll ( '' , '' , 0 , 0 , $filter );
if ( $ret < 0 ) {
2024-12-17 20:56:08 +01:00
$this -> setErrorsFromObject ( $supplierorderdispatch );
2022-02-14 18:07:18 +01:00
return $ret ;
} else {
// build array with quantity received by product in all supplier orders (origin)
foreach ( $supplierorderdispatch -> lines as $dispatch_line ) {
2023-06-09 11:53:39 +02:00
if ( array_key_exists ( $dispatch_line -> fk_product , $qty_received )) {
$qty_received [ $dispatch_line -> fk_product ] += $dispatch_line -> qty ;
2023-10-26 12:42:07 +02:00
} else {
$qty_received [ $dispatch_line -> fk_product ] = $dispatch_line -> qty ;
2023-06-09 11:53:39 +02:00
}
2022-02-14 18:07:18 +01:00
}
2018-10-03 12:22:41 +02:00
2024-04-03 00:51:18 +02:00
// qty wished in origin (purchase order, ...)
foreach ( $this -> origin_object -> lines as $origin_line ) {
2022-02-14 18:07:18 +01:00
// exclude lines not qualified for reception
2024-05-21 20:12:45 +02:00
if (( ! getDolGlobalInt ( 'STOCK_SUPPORTS_SERVICES' ) && $origin_line -> product_type > 0 ) || $origin_line -> product_type > 1 ) {
2022-02-14 18:07:18 +01:00
continue ;
}
2025-01-09 20:16:46 +01:00
if ( array_key_exists ( $origin_line -> fk_product , $qty_wished )) {
$qty_wished [ $origin_line -> fk_product ] += $origin_line -> qty ;
} else {
$qty_wished [ $origin_line -> fk_product ] = $origin_line -> qty ;
}
2022-02-14 18:07:18 +01:00
}
// compare array
$diff_array = array_diff_assoc ( $qty_received , $qty_wished ); // Warning: $diff_array is done only on common keys.
$keys_in_wished_not_in_received = array_diff ( array_keys ( $qty_wished ), array_keys ( $qty_received ));
$keys_in_received_not_in_wished = array_diff ( array_keys ( $qty_received ), array_keys ( $qty_wished ));
if ( count ( $diff_array ) == 0 && count ( $keys_in_wished_not_in_received ) == 0 && count ( $keys_in_received_not_in_wished ) == 0 ) { // no diff => mean everything is received
$status = CommandeFournisseur :: STATUS_RECEIVED_COMPLETELY ;
FIX|Fix some minor issues on Reception and add a new test for it (#26310)
* reception: reOpen: mirror $this->statut in $this->status
$this->statut is the deprecated variable, $this->status should also get
the correct value.
* reception: setDraft: mirror $this->statut in $this->status
$this->statut is the deprecated variable, $this->status should also get
the correct value.
* reception: add missing $weight field
Fix warning:
Undefined property: Reception::$weight
* societe: add country_id field
* reception: use getDolGlobalInt when suitable
Using empty() implies that the value actually exists on the stdClass at
$conf->global, but it's not always the case. getDolGlobalInt will handle
this smoothly by checking first, which solves warnings like those:
Undefined property: stdClass::$STOCK_CALCULATE_ON_RECEPTION
* ReceptionTest: add new test
The test checks the usual workflow of the Reception class, with, on the
one hand, the common CRUD operations:
- create
- fetch
- update
- delete
And on the other hand, the status handling for Reception:
- valid: STATUS_DRAFT -> STATUS_VALID
- setClosed: STATUS_VALID -> STATUS_CLOSED
- reOpen: STATUS_CLOSED -> STATUS_VALID
- setDraft: STATUS_VALID -> STATUS_DRAFT
The stocks lines are not tested yet, and the error cases, like any other
transition not described above, are not tested either. The permissions
for some of the operations are hardcoded for the test and there is no
failure check when the permission is not set yet.
2023-10-21 16:28:30 +02:00
} elseif ( getDolGlobalInt ( 'SUPPLIER_ORDER_MORE_THAN_WISHED' )) {
2022-02-14 18:07:18 +01:00
// set totally received if more products received than ordered
$close = 0 ;
if ( count ( $diff_array ) > 0 ) {
// there are some difference between the two arrays
// scan the array of results
foreach ( $diff_array as $key => $value ) {
2024-09-29 21:52:31 +02:00
// if the quantity delivered is greater or equal to ordered quantity @phan-suppress-next-line PhanTypeInvalidDimOffset
2022-02-14 18:07:18 +01:00
if ( $qty_received [ $key ] >= $qty_wished [ $key ]) {
$close ++ ;
}
}
}
if ( $close == count ( $diff_array )) {
// all the products are received equal or more than the ordered quantity
$status = CommandeFournisseur :: STATUS_RECEIVED_COMPLETELY ;
}
}
}
}
return $status ;
}
2018-10-03 12:22:41 +02:00
/**
* Add an reception line .
* If STOCK_WAREHOUSE_NOT_REQUIRED_FOR_RECEPTIONS is set , you can add a reception line , with no stock source defined
* If STOCK_MUST_BE_ENOUGH_FOR_RECEPTION is not set , you can add a reception line , even if not enough into stock
*
2018-10-04 17:32:50 +02:00
* @ param int $entrepot_id Id of warehouse
* @ param int $id Id of source line ( supplier order line )
2024-03-19 15:55:46 +01:00
* @ param float $qty Quantity
2024-10-07 14:07:24 +02:00
* @ param array < string , mixed > $array_options extrafields array
2024-01-14 12:12:21 +01:00
* @ param string $comment Comment for stock movement
* @ param int $eatby eat - by date
* @ param int $sellby sell - by date
* @ param string $batch Lot number
2024-10-07 14:07:24 +02:00
* @ param float $cost_price Line cost
2023-12-06 15:46:39 +01:00
* @ return int Return integer < 0 if KO , index of line if OK
2018-10-03 12:22:41 +02:00
*/
2024-01-14 12:12:21 +01:00
public function addline ( $entrepot_id , $id , $qty , $array_options = [], $comment = '' , $eatby = null , $sellby = null , $batch = '' , $cost_price = 0 )
2018-10-03 12:22:41 +02:00
{
2018-10-04 17:32:50 +02:00
global $conf , $langs , $user ;
2018-10-03 12:22:41 +02:00
$num = count ( $this -> lines );
2018-10-04 17:32:50 +02:00
$line = new CommandeFournisseurDispatch ( $this -> db );
2018-10-03 12:22:41 +02:00
2018-10-04 17:32:50 +02:00
$line -> fk_entrepot = $entrepot_id ;
$line -> fk_commandefourndet = $id ;
2018-10-03 12:22:41 +02:00
$line -> qty = $qty ;
2018-10-04 17:32:50 +02:00
$supplierorderline = new CommandeFournisseurLigne ( $this -> db );
2022-03-17 18:53:50 +01:00
$result = $supplierorderline -> fetch ( $id );
if ( $result <= 0 ) {
2024-12-17 20:56:08 +01:00
$this -> setErrorsFromObject ( $supplierorderline );
2022-03-17 18:53:50 +01:00
return - 1 ;
}
2018-12-15 13:58:39 +01:00
2022-03-17 18:53:50 +01:00
$fk_product = 0 ;
2022-09-25 06:06:06 +02:00
if ( isModEnabled ( 'stock' ) && ! empty ( $supplierorderline -> fk_product )) {
2018-10-04 17:32:50 +02:00
$fk_product = $supplierorderline -> fk_product ;
2018-12-15 13:58:39 +01:00
FIX|Fix some minor issues on Reception and add a new test for it (#26310)
* reception: reOpen: mirror $this->statut in $this->status
$this->statut is the deprecated variable, $this->status should also get
the correct value.
* reception: setDraft: mirror $this->statut in $this->status
$this->statut is the deprecated variable, $this->status should also get
the correct value.
* reception: add missing $weight field
Fix warning:
Undefined property: Reception::$weight
* societe: add country_id field
* reception: use getDolGlobalInt when suitable
Using empty() implies that the value actually exists on the stdClass at
$conf->global, but it's not always the case. getDolGlobalInt will handle
this smoothly by checking first, which solves warnings like those:
Undefined property: stdClass::$STOCK_CALCULATE_ON_RECEPTION
* ReceptionTest: add new test
The test checks the usual workflow of the Reception class, with, on the
one hand, the common CRUD operations:
- create
- fetch
- update
- delete
And on the other hand, the status handling for Reception:
- valid: STATUS_DRAFT -> STATUS_VALID
- setClosed: STATUS_VALID -> STATUS_CLOSED
- reOpen: STATUS_CLOSED -> STATUS_VALID
- setDraft: STATUS_VALID -> STATUS_DRAFT
The stocks lines are not tested yet, and the error cases, like any other
transition not described above, are not tested either. The permissions
for some of the operations are hardcoded for the test and there is no
failure check when the permission is not set yet.
2023-10-21 16:28:30 +02:00
if ( ! ( $entrepot_id > 0 ) && ! getDolGlobalInt ( 'STOCK_WAREHOUSE_NOT_REQUIRED_FOR_RECEPTIONS' )) {
2020-10-28 17:49:52 +01:00
$langs -> load ( " errors " );
2019-11-13 18:32:11 +01:00
$this -> error = $langs -> trans ( " ErrorWarehouseRequiredIntoReceptionLine " );
2018-10-03 12:22:41 +02:00
return - 1 ;
}
}
2022-07-08 15:30:31 +02:00
// Check batch is set
$product = new Product ( $this -> db );
$product -> fetch ( $fk_product );
2022-08-31 21:55:55 +02:00
if ( isModEnabled ( 'productbatch' )) {
2022-07-08 15:30:31 +02:00
$langs -> load ( " errors " );
if ( ! empty ( $product -> status_batch ) && empty ( $batch )) {
$this -> error = $langs -> trans ( 'ErrorProductNeedBatchNumber' , $product -> ref );
return - 1 ;
} elseif ( empty ( $product -> status_batch ) && ! empty ( $batch )) {
$this -> error = $langs -> trans ( 'ErrorProductDoesNotNeedBatchNumber' , $product -> ref );
return - 1 ;
}
2023-05-30 08:37:17 +02:00
// check sell-by / eat-by date is mandatory
$errorMsgArr = Productlot :: checkSellOrEatByMandatoryFromProductAndDates ( $product , $sellby , $eatby );
if ( ! empty ( $errorMsgArr )) {
$errorMessage = '<b>' . $product -> ref . '</b> : ' ;
$errorMessage .= '<ul>' ;
foreach ( $errorMsgArr as $errorMsg ) {
$errorMessage .= '<li>' . $errorMsg . '</li>' ;
}
$errorMessage .= '</ul>' ;
$this -> error = $errorMessage ;
return - 1 ;
}
2022-07-08 15:30:31 +02:00
}
2022-07-08 15:53:41 +02:00
unset ( $product );
2022-07-08 15:30:31 +02:00
2018-10-03 12:22:41 +02:00
// extrafields
2020-04-24 18:58:47 +02:00
$line -> array_options = $supplierorderline -> array_options ;
FIX|Fix some minor issues on Reception and add a new test for it (#26310)
* reception: reOpen: mirror $this->statut in $this->status
$this->statut is the deprecated variable, $this->status should also get
the correct value.
* reception: setDraft: mirror $this->statut in $this->status
$this->statut is the deprecated variable, $this->status should also get
the correct value.
* reception: add missing $weight field
Fix warning:
Undefined property: Reception::$weight
* societe: add country_id field
* reception: use getDolGlobalInt when suitable
Using empty() implies that the value actually exists on the stdClass at
$conf->global, but it's not always the case. getDolGlobalInt will handle
this smoothly by checking first, which solves warnings like those:
Undefined property: stdClass::$STOCK_CALCULATE_ON_RECEPTION
* ReceptionTest: add new test
The test checks the usual workflow of the Reception class, with, on the
one hand, the common CRUD operations:
- create
- fetch
- update
- delete
And on the other hand, the status handling for Reception:
- valid: STATUS_DRAFT -> STATUS_VALID
- setClosed: STATUS_VALID -> STATUS_CLOSED
- reOpen: STATUS_CLOSED -> STATUS_VALID
- setDraft: STATUS_VALID -> STATUS_DRAFT
The stocks lines are not tested yet, and the error cases, like any other
transition not described above, are not tested either. The permissions
for some of the operations are hardcoded for the test and there is no
failure check when the permission is not set yet.
2023-10-21 16:28:30 +02:00
if ( ! getDolGlobalInt ( 'MAIN_EXTRAFIELDS_DISABLED' ) && is_array ( $array_options ) && count ( $array_options ) > 0 ) {
2020-04-23 19:29:52 +02:00
foreach ( $array_options as $key => $value ) {
$line -> array_options [ $key ] = $value ;
}
}
2018-12-15 13:58:39 +01:00
2018-10-04 17:32:50 +02:00
$line -> fk_product = $fk_product ;
2019-11-13 18:32:11 +01:00
$line -> fk_commande = $supplierorderline -> fk_commande ;
$line -> fk_user = $user -> id ;
2018-10-04 17:32:50 +02:00
$line -> comment = $comment ;
$line -> batch = $batch ;
$line -> eatby = $eatby ;
$line -> sellby = $sellby ;
2019-11-13 18:32:11 +01:00
$line -> status = 1 ;
2021-09-22 14:56:44 +02:00
$line -> cost_price = $cost_price ;
2019-11-13 18:32:11 +01:00
$line -> fk_reception = $this -> id ;
2022-07-10 18:35:23 +02:00
2018-10-03 12:22:41 +02:00
$this -> lines [ $num ] = $line ;
2020-11-04 17:44:02 +01:00
return $num ;
2018-10-03 12:22:41 +02:00
}
2020-10-28 17:49:52 +01:00
/**
* Update database
*
* @ param User $user User that modify
* @ 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-28 17:49:52 +01:00
*/
public function update ( $user = null , $notrigger = 0 )
{
global $conf ;
2019-11-13 18:32:11 +01:00
$error = 0 ;
2018-10-03 12:22:41 +02:00
// Clean parameters
2021-02-26 20:53:03 +01:00
if ( isset ( $this -> ref )) {
$this -> ref = trim ( $this -> ref );
}
if ( isset ( $this -> entity )) {
2024-03-05 17:12:36 +01:00
$this -> entity = ( int ) $this -> entity ;
2021-02-26 20:53:03 +01:00
}
if ( isset ( $this -> ref_supplier )) {
$this -> ref_supplier = trim ( $this -> ref_supplier );
}
if ( isset ( $this -> socid )) {
2024-10-07 14:07:24 +02:00
$this -> socid = ( int ) trim (( string ) $this -> socid );
2021-02-26 20:53:03 +01:00
}
if ( isset ( $this -> fk_user_author )) {
2024-03-05 17:12:36 +01:00
$this -> fk_user_author = ( int ) $this -> fk_user_author ;
2021-02-26 20:53:03 +01:00
}
if ( isset ( $this -> fk_user_valid )) {
2024-03-05 17:12:36 +01:00
$this -> fk_user_valid = ( int ) $this -> fk_user_valid ;
2021-02-26 20:53:03 +01:00
}
if ( isset ( $this -> shipping_method_id )) {
2024-02-25 22:10:04 +01:00
$this -> shipping_method_id = ( int ) $this -> shipping_method_id ;
2021-02-26 20:53:03 +01:00
}
if ( isset ( $this -> tracking_number )) {
$this -> tracking_number = trim ( $this -> tracking_number );
}
if ( isset ( $this -> statut )) {
$this -> statut = ( int ) $this -> statut ;
}
if ( isset ( $this -> trueDepth )) {
2024-10-07 14:07:24 +02:00
$this -> trueDepth = ( float ) trim (( string ) $this -> trueDepth );
2021-02-26 20:53:03 +01:00
}
if ( isset ( $this -> trueWidth )) {
2024-10-07 14:07:24 +02:00
$this -> trueWidth = ( float ) trim (( string ) $this -> trueWidth );
2021-02-26 20:53:03 +01:00
}
if ( isset ( $this -> trueHeight )) {
2024-10-07 14:07:24 +02:00
$this -> trueHeight = ( float ) trim (( string ) $this -> trueHeight );
2021-02-26 20:53:03 +01:00
}
if ( isset ( $this -> size_units )) {
2024-03-19 22:27:20 +01:00
$this -> size_units = trim (( string ) $this -> size_units );
2021-02-26 20:53:03 +01:00
}
if ( isset ( $this -> weight_units )) {
2024-10-07 14:07:24 +02:00
$this -> weight_units = ( float ) trim (( string ) $this -> weight_units );
2021-02-26 20:53:03 +01:00
}
if ( isset ( $this -> trueWeight )) {
2024-10-07 14:07:24 +02:00
$this -> weight = ( float ) trim (( string ) $this -> trueWeight );
2021-02-26 20:53:03 +01:00
}
if ( isset ( $this -> note_private )) {
$this -> note_private = trim ( $this -> note_private );
}
if ( isset ( $this -> note_public )) {
$this -> note_public = trim ( $this -> note_public );
}
if ( isset ( $this -> model_pdf )) {
$this -> model_pdf = trim ( $this -> model_pdf );
}
2018-10-03 12:22:41 +02:00
// Check parameters
// Put here code to add control on parameters values
2020-10-28 17:49:52 +01:00
// Update request
$sql = " UPDATE " . MAIN_DB_PREFIX . " reception SET " ;
2018-10-03 12:22:41 +02:00
2019-11-13 18:32:11 +01:00
$sql .= " ref= " . ( isset ( $this -> ref ) ? " ' " . $this -> db -> escape ( $this -> ref ) . " ' " : " null " ) . " , " ;
$sql .= " ref_supplier= " . ( isset ( $this -> ref_supplier ) ? " ' " . $this -> db -> escape ( $this -> ref_supplier ) . " ' " : " null " ) . " , " ;
$sql .= " fk_soc= " . ( isset ( $this -> socid ) ? $this -> socid : " null " ) . " , " ;
$sql .= " date_creation= " . ( dol_strlen ( $this -> date_creation ) != 0 ? " ' " . $this -> db -> idate ( $this -> date_creation ) . " ' " : 'null' ) . " , " ;
$sql .= " fk_user_author= " . ( isset ( $this -> fk_user_author ) ? $this -> fk_user_author : " null " ) . " , " ;
$sql .= " date_valid= " . ( dol_strlen ( $this -> date_valid ) != 0 ? " ' " . $this -> db -> idate ( $this -> date_valid ) . " ' " : 'null' ) . " , " ;
$sql .= " fk_user_valid= " . ( isset ( $this -> fk_user_valid ) ? $this -> fk_user_valid : " null " ) . " , " ;
$sql .= " date_reception= " . ( dol_strlen ( $this -> date_reception ) != 0 ? " ' " . $this -> db -> idate ( $this -> date_reception ) . " ' " : 'null' ) . " , " ;
$sql .= " date_delivery= " . ( dol_strlen ( $this -> date_delivery ) != 0 ? " ' " . $this -> db -> idate ( $this -> date_delivery ) . " ' " : 'null' ) . " , " ;
$sql .= " fk_shipping_method= " . (( isset ( $this -> shipping_method_id ) && $this -> shipping_method_id > 0 ) ? $this -> shipping_method_id : " null " ) . " , " ;
$sql .= " tracking_number= " . ( isset ( $this -> tracking_number ) ? " ' " . $this -> db -> escape ( $this -> tracking_number ) . " ' " : " null " ) . " , " ;
$sql .= " fk_statut= " . ( isset ( $this -> statut ) ? $this -> statut : " null " ) . " , " ;
$sql .= " height= " . (( $this -> trueHeight != '' ) ? $this -> trueHeight : " null " ) . " , " ;
$sql .= " width= " . (( $this -> trueWidth != '' ) ? $this -> trueWidth : " null " ) . " , " ;
$sql .= " size_units= " . ( isset ( $this -> size_units ) ? $this -> size_units : " null " ) . " , " ;
$sql .= " size= " . (( $this -> trueDepth != '' ) ? $this -> trueDepth : " null " ) . " , " ;
$sql .= " weight_units= " . ( isset ( $this -> weight_units ) ? $this -> weight_units : " null " ) . " , " ;
$sql .= " weight= " . (( $this -> trueWeight != '' ) ? $this -> trueWeight : " null " ) . " , " ;
$sql .= " note_private= " . ( isset ( $this -> note_private ) ? " ' " . $this -> db -> escape ( $this -> note_private ) . " ' " : " null " ) . " , " ;
$sql .= " note_public= " . ( isset ( $this -> note_public ) ? " ' " . $this -> db -> escape ( $this -> note_public ) . " ' " : " null " ) . " , " ;
2022-01-03 18:15:19 +01:00
$sql .= " model_pdf= " . ( isset ( $this -> model_pdf ) ? " ' " . $this -> db -> escape ( $this -> model_pdf ) . " ' " : " null " ) . " , " ;
$sql .= " entity = " . (( int ) $conf -> entity );
2021-03-14 12:20:23 +01:00
$sql .= " WHERE rowid= " . (( int ) $this -> id );
2018-10-03 12:22:41 +02:00
$this -> db -> begin ();
dol_syslog ( get_class ( $this ) . " ::update " , LOG_DEBUG );
2020-10-28 17:49:52 +01:00
$resql = $this -> db -> query ( $sql );
2021-02-26 20:53:03 +01:00
if ( ! $resql ) {
2023-12-04 13:53:48 +01:00
$error ++ ;
$this -> errors [] = " Error " . $this -> db -> lasterror ();
2021-02-26 20:53:03 +01:00
}
2018-10-03 12:22:41 +02:00
2021-02-26 20:53:03 +01:00
if ( ! $error ) {
if ( ! $notrigger ) {
2020-10-28 17:49:52 +01:00
// Call trigger
$result = $this -> call_trigger ( 'RECEPTION_MODIFY' , $user );
2021-02-26 20:53:03 +01:00
if ( $result < 0 ) {
$error ++ ;
}
2020-10-28 17:49:52 +01:00
// End call triggers
}
2018-10-03 12:22:41 +02:00
}
2020-10-28 17:49:52 +01:00
// Commit or rollback
2021-02-26 20:53:03 +01:00
if ( $error ) {
foreach ( $this -> errors as $errmsg ) {
2020-10-28 17:49:52 +01:00
dol_syslog ( get_class ( $this ) . " ::update " . $errmsg , LOG_ERR );
$this -> error .= ( $this -> error ? ', ' . $errmsg : $errmsg );
2018-10-03 12:22:41 +02:00
}
$this -> db -> rollback ();
2019-11-13 18:32:11 +01:00
return - 1 * $error ;
2020-05-21 15:05:19 +02:00
} else {
2018-10-03 12:22:41 +02:00
$this -> db -> commit ();
return 1 ;
}
2018-12-15 15:43:30 +01:00
}
2018-10-03 12:22:41 +02:00
/**
* Delete reception .
*
2018-12-15 16:37:00 +01:00
* @ param User $user Object user
* @ return int > 0 if OK , 0 if deletion done but failed to delete files , < 0 if KO
2018-10-03 12:22:41 +02:00
*/
2020-10-28 17:49:52 +01:00
public function delete ( User $user )
2018-10-03 12:22:41 +02:00
{
global $conf , $langs , $user ;
require_once DOL_DOCUMENT_ROOT . '/core/lib/files.lib.php' ;
2018-12-15 13:58:39 +01:00
2019-11-13 18:32:11 +01:00
$error = 0 ;
$this -> error = '' ;
2018-10-03 12:22:41 +02:00
2018-12-15 13:58:39 +01:00
2018-10-03 12:22:41 +02:00
$this -> db -> begin ();
2018-12-15 15:43:30 +01:00
2018-10-03 12:22:41 +02:00
// Stock control
2024-12-09 16:08:25 +01:00
if ( isModEnabled ( 'stock' ) && (( getDolGlobalInt ( 'STOCK_CALCULATE_ON_RECEPTION' ) && $this -> status > Reception :: STATUS_DRAFT )
|| ( getDolGlobalInt ( 'STOCK_CALCULATE_ON_RECEPTION_CLOSE' ) && $this -> status == Reception :: STATUS_CLOSED ))
) {
2018-12-15 15:43:30 +01:00
require_once DOL_DOCUMENT_ROOT . " /product/stock/class/mouvementstock.class.php " ;
2018-10-03 12:22:41 +02:00
$langs -> load ( " agenda " );
// Loop on each product line to add a stock movement
2024-01-15 09:40:59 +01:00
$sql = " SELECT cd.fk_product, cd.subprice, ed.qty, ed.fk_entrepot, ed.eatby, ed.sellby, ed.batch, ed.rowid as receptiondet_batch_id " ;
2019-11-13 18:32:11 +01:00
$sql .= " FROM " . MAIN_DB_PREFIX . " commande_fournisseurdet as cd, " ;
2024-01-15 09:40:59 +01:00
$sql .= " " . MAIN_DB_PREFIX . " receptiondet_batch as ed " ;
2021-08-23 19:33:24 +02:00
$sql .= " WHERE ed.fk_reception = " . (( int ) $this -> id );
2024-03-19 15:49:42 +01:00
$sql .= " AND cd.rowid = ed.fk_elementdet " ;
2018-10-03 12:22:41 +02:00
dol_syslog ( get_class ( $this ) . " ::delete select details " , LOG_DEBUG );
2019-11-13 18:32:11 +01:00
$resql = $this -> db -> query ( $sql );
2021-02-26 20:53:03 +01:00
if ( $resql ) {
2018-10-03 12:22:41 +02:00
$cpt = $this -> db -> num_rows ( $resql );
2021-02-26 20:53:03 +01:00
for ( $i = 0 ; $i < $cpt ; $i ++ ) {
2018-10-03 12:22:41 +02:00
dol_syslog ( get_class ( $this ) . " ::delete movement index " . $i );
$obj = $this -> db -> fetch_object ( $resql );
$mouvS = new MouvementStock ( $this -> db );
// we do not log origin because it will be deleted
$mouvS -> origin = null ;
2018-12-15 13:58:39 +01:00
2024-12-09 11:44:09 +01:00
$result = $mouvS -> livraison ( $user , $obj -> fk_product , $obj -> fk_entrepot , $obj -> qty , 0 , $langs -> trans ( " ReceptionDeletedInDolibarr " , $this -> ref ), '' , $obj -> eatby ? $this -> db -> jdate ( $obj -> eatby ) : null , $obj -> sellby ? $this -> db -> jdate ( $obj -> sellby ) : null , $obj -> batch ); // Price is set to 0, because we don't want to see WAP changed
2024-10-23 23:11:02 +02:00
if ( $result < 0 ) {
$error ++ ;
$this -> error = $mouvS -> error ;
$this -> errors = $mouvS -> errors ;
}
2018-10-03 12:22:41 +02:00
}
2020-05-21 15:05:19 +02:00
} else {
2023-12-04 13:53:48 +01:00
$error ++ ;
$this -> errors [] = " Error " . $this -> db -> lasterror ();
2018-10-03 12:22:41 +02:00
}
}
2021-02-26 20:53:03 +01:00
if ( ! $error ) {
2024-01-15 09:40:59 +01:00
$main = MAIN_DB_PREFIX . 'receptiondet_batch' ;
2021-09-30 15:59:47 +02:00
$ef = $main . " _extrafields " ;
$sqlef = " DELETE FROM " . $ef . " WHERE fk_object IN (SELECT rowid FROM " . $main . " WHERE fk_reception = " . (( int ) $this -> id ) . " ) " ;
2020-04-23 19:22:25 +02:00
2024-01-15 09:40:59 +01:00
$sql = " DELETE FROM " . MAIN_DB_PREFIX . " receptiondet_batch " ;
2021-08-23 19:33:24 +02:00
$sql .= " WHERE fk_reception = " . (( int ) $this -> id );
2018-10-03 12:22:41 +02:00
2021-02-26 20:53:03 +01:00
if ( $this -> db -> query ( $sqlef ) && $this -> db -> query ( $sql )) {
2018-10-03 12:22:41 +02:00
// Delete linked object
$res = $this -> deleteObjectLinked ();
2021-02-26 20:53:03 +01:00
if ( $res < 0 ) {
$error ++ ;
}
2018-10-03 12:22:41 +02:00
2021-02-26 20:53:03 +01:00
if ( ! $error ) {
2018-10-03 12:22:41 +02:00
$sql = " DELETE FROM " . MAIN_DB_PREFIX . " reception " ;
2021-08-27 16:33:03 +02:00
$sql .= " WHERE rowid = " . (( int ) $this -> id );
2018-10-03 12:22:41 +02:00
2021-02-26 20:53:03 +01:00
if ( $this -> db -> query ( $sql )) {
2018-10-03 12:22:41 +02:00
// Call trigger
2019-11-13 18:32:11 +01:00
$result = $this -> call_trigger ( 'RECEPTION_DELETE' , $user );
2021-02-26 20:53:03 +01:00
if ( $result < 0 ) {
$error ++ ;
}
2018-10-03 12:22:41 +02:00
// End call triggers
2021-02-26 20:53:03 +01:00
if ( ! empty ( $this -> origin ) && $this -> origin_id > 0 ) {
2020-10-28 17:49:52 +01:00
$this -> fetch_origin ();
2024-10-07 14:07:24 +02:00
$origin_object = $this -> origin_object ;
'@phan-var-force CommandeFournisseur $origin_object' ;
if ( $origin_object -> statut == 4 ) { // If order source of reception is "partially received"
2020-10-28 17:49:52 +01:00
// Check if there is no more reception. If not, we can move back status of order to "validated" instead of "reception in progress"
2024-10-07 14:07:24 +02:00
$origin_object -> loadReceptions ();
2020-10-28 17:49:52 +01:00
//var_dump($this->$origin->receptions);exit;
2024-10-07 14:07:24 +02:00
if ( count ( $origin_object -> receptions ) <= 0 ) {
$origin_object -> setStatut ( 3 ); // ordered
2020-10-28 17:49:52 +01:00
}
}
2018-10-03 12:22:41 +02:00
}
2021-02-26 20:53:03 +01:00
if ( ! $error ) {
2018-10-03 12:22:41 +02:00
$this -> db -> commit ();
// We delete PDFs
$ref = dol_sanitizeFileName ( $this -> ref );
2021-02-26 20:53:03 +01:00
if ( ! empty ( $conf -> reception -> dir_output )) {
2019-11-13 18:32:11 +01:00
$dir = $conf -> reception -> dir_output . '/' . $ref ;
$file = $dir . '/' . $ref . '.pdf' ;
2021-02-26 20:53:03 +01:00
if ( file_exists ( $file )) {
if ( ! dol_delete_file ( $file )) {
2018-10-03 12:22:41 +02:00
return 0 ;
}
}
2021-02-26 20:53:03 +01:00
if ( file_exists ( $dir )) {
if ( ! dol_delete_dir_recursive ( $dir )) {
2019-11-13 18:32:11 +01:00
$this -> error = $langs -> trans ( " ErrorCanNotDeleteDir " , $dir );
2018-10-03 12:22:41 +02:00
return 0 ;
}
}
}
return 1 ;
2020-05-21 15:05:19 +02:00
} else {
2018-10-03 12:22:41 +02:00
$this -> db -> rollback ();
return - 1 ;
}
2020-05-21 15:05:19 +02:00
} else {
2019-11-13 18:32:11 +01:00
$this -> error = $this -> db -> lasterror () . " - sql= $sql " ;
2018-10-03 12:22:41 +02:00
$this -> db -> rollback ();
return - 3 ;
}
2020-05-21 15:05:19 +02:00
} else {
2019-11-13 18:32:11 +01:00
$this -> error = $this -> db -> lasterror () . " - sql= $sql " ;
2018-10-03 12:22:41 +02:00
$this -> db -> rollback ();
return - 2 ;
}
2020-05-21 15:05:19 +02:00
} else {
2019-11-13 18:32:11 +01:00
$this -> error = $this -> db -> lasterror () . " - sql= $sql " ;
2018-10-03 12:22:41 +02:00
$this -> db -> rollback ();
return - 1 ;
}
2020-05-21 15:05:19 +02:00
} else {
2018-10-03 12:22:41 +02:00
$this -> db -> rollback ();
return - 1 ;
}
}
2018-12-15 15:43:30 +01:00
2020-10-28 17:49:52 +01:00
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2018-10-03 12:22:41 +02:00
/**
* Load lines
*
* @ return int > 0 if OK , Otherwise if KO
*/
2020-10-28 17:49:52 +01:00
public function fetch_lines ()
2018-10-03 12:22:41 +02:00
{
2018-10-23 14:31:58 +02:00
// phpcs:enable
2022-03-28 13:50:47 +02:00
$this -> lines = array ();
require_once DOL_DOCUMENT_ROOT . '/fourn/class/fournisseur.commande.dispatch.class.php' ;
2021-09-30 15:59:47 +02:00
2024-04-29 11:04:19 +02:00
$sql = " SELECT rowid FROM " . MAIN_DB_PREFIX . " receptiondet_batch " ;
$sql .= " WHERE fk_reception = " . (( int ) $this -> id );
2020-09-20 03:32:43 +02:00
$resql = $this -> db -> query ( $sql );
2018-12-15 13:58:39 +01:00
2019-11-13 18:32:11 +01:00
if ( ! empty ( $resql )) {
2020-10-26 18:30:32 +01:00
while ( $obj = $this -> db -> fetch_object ( $resql )) {
2020-09-20 03:32:43 +02:00
$line = new CommandeFournisseurDispatch ( $this -> db );
2022-03-28 13:50:47 +02:00
2018-10-05 16:21:50 +02:00
$line -> fetch ( $obj -> rowid );
2022-09-21 01:13:53 +02:00
// TODO Remove or keep this ?
2018-10-05 16:21:50 +02:00
$line -> fetch_product ();
2022-03-28 13:50:47 +02:00
2022-09-23 09:21:07 +02:00
$sql_commfourndet = 'SELECT qty, ref, label, description, tva_tx, vat_src_code, subprice, multicurrency_subprice, remise_percent, total_ht, total_ttc, total_tva' ;
2021-05-10 11:53:19 +02:00
$sql_commfourndet .= ' FROM ' . MAIN_DB_PREFIX . 'commande_fournisseurdet' ;
$sql_commfourndet .= ' WHERE rowid = ' . (( int ) $line -> fk_commandefourndet );
2022-03-15 14:59:26 +01:00
$sql_commfourndet .= ' ORDER BY rang' ;
2022-03-28 13:50:47 +02:00
2020-10-26 18:30:32 +01:00
$resql_commfourndet = $this -> db -> query ( $sql_commfourndet );
2019-11-13 18:32:11 +01:00
if ( ! empty ( $resql_commfourndet )) {
2020-09-20 03:32:43 +02:00
$obj = $this -> db -> fetch_object ( $resql_commfourndet );
2018-10-08 12:15:17 +02:00
$line -> qty_asked = $obj -> qty ;
2021-05-10 11:53:19 +02:00
$line -> description = $obj -> description ;
$line -> desc = $obj -> description ;
2018-10-09 16:26:40 +02:00
$line -> tva_tx = $obj -> tva_tx ;
$line -> vat_src_code = $obj -> vat_src_code ;
$line -> subprice = $obj -> subprice ;
$line -> multicurrency_subprice = $obj -> multicurrency_subprice ;
$line -> remise_percent = $obj -> remise_percent ;
2024-04-29 11:04:19 +02:00
$line -> label = ! empty ( $obj -> label ) ? $obj -> label : ( is_object ( $line -> product ) ? $line -> product -> label : '' );
2018-10-22 14:32:50 +02:00
$line -> ref_supplier = $obj -> ref ;
2022-09-23 09:21:07 +02:00
$line -> total_ht = $obj -> total_ht ;
$line -> total_ttc = $obj -> total_ttc ;
$line -> total_tva = $obj -> total_tva ;
2019-11-13 18:32:11 +01:00
} else {
2018-10-08 12:15:17 +02:00
$line -> qty_asked = 0 ;
2018-10-08 16:54:33 +02:00
$line -> description = '' ;
2021-05-10 11:53:19 +02:00
$line -> desc = '' ;
2018-10-08 16:54:33 +02:00
$line -> label = $obj -> label ;
2018-10-08 12:15:17 +02:00
}
2018-12-15 13:58:39 +01:00
2019-11-13 18:32:11 +01:00
$pu_ht = ( $line -> subprice * $line -> qty ) * ( 100 - $line -> remise_percent ) / 100 ;
$tva = $pu_ht * $line -> tva_tx / 100 ;
2018-10-09 16:26:40 +02:00
$this -> total_ht += $pu_ht ;
2019-11-13 18:32:11 +01:00
$this -> total_tva += $pu_ht * $line -> tva_tx / 100 ;
2018-12-15 13:58:39 +01:00
2019-11-13 18:32:11 +01:00
$this -> total_ttc += $pu_ht + $tva ;
2018-12-15 13:58:39 +01:00
2022-11-18 10:27:49 +01:00
if ( isModEnabled ( 'productbatch' ) && ! empty ( $line -> batch )) {
$detail_batch = new stdClass ();
$detail_batch -> eatby = $line -> eatby ;
$detail_batch -> sellby = $line -> sellby ;
$detail_batch -> batch = $line -> batch ;
$detail_batch -> qty = $line -> qty ;
2024-04-29 11:04:19 +02:00
2022-11-18 10:27:49 +01:00
$line -> detail_batch [] = $detail_batch ;
}
2018-12-15 13:58:39 +01:00
2019-11-13 18:32:11 +01:00
$this -> lines [] = $line ;
2018-10-03 12:22:41 +02:00
}
2018-12-15 13:58:39 +01:00
2018-10-03 12:22:41 +02:00
return 1 ;
2020-05-21 15:05:19 +02:00
} else {
2018-10-05 16:21:50 +02:00
return - 1 ;
2018-10-03 12:22:41 +02:00
}
}
/**
2024-08-07 01:20:43 +02:00
* Return clickable link of object ( with eventually picto )
2020-10-28 17:49:52 +01:00
*
* @ param int $withpicto Add picto into link
* @ param int $option Where point the link
* @ param int $max Max length to show
* @ param int $short Use short labels
* @ param int $notooltip 1 = No tooltip
* @ return string String with URL
*/
public function getNomUrl ( $withpicto = 0 , $option = 0 , $max = 0 , $short = 0 , $notooltip = 0 )
2018-10-03 12:22:41 +02:00
{
2023-12-19 11:51:48 +01:00
global $langs , $hookmanager ;
2019-11-13 18:32:11 +01:00
$result = '' ;
2020-09-11 13:32:40 +02:00
$label = img_picto ( '' , $this -> picto ) . ' <u>' . $langs -> trans ( " Reception " ) . '</u>' ;
2020-10-28 17:49:52 +01:00
$label .= '<br><b>' . $langs -> trans ( 'Ref' ) . ':</b> ' . $this -> ref ;
2021-12-01 15:40:53 +01:00
$label .= '<br><b>' . $langs -> trans ( 'RefSupplier' ) . ':</b> ' . ( $this -> ref_supplier ? $this -> ref_supplier : '' );
2018-10-03 12:22:41 +02:00
$url = DOL_URL_ROOT . '/reception/card.php?id=' . $this -> id ;
2021-02-26 20:53:03 +01:00
if ( $short ) {
return $url ;
}
2018-10-03 12:22:41 +02:00
2019-11-13 18:32:11 +01:00
$linkclose = '' ;
2021-02-26 20:53:03 +01:00
if ( empty ( $notooltip )) {
FIX|Fix some minor issues on Reception and add a new test for it (#26310)
* reception: reOpen: mirror $this->statut in $this->status
$this->statut is the deprecated variable, $this->status should also get
the correct value.
* reception: setDraft: mirror $this->statut in $this->status
$this->statut is the deprecated variable, $this->status should also get
the correct value.
* reception: add missing $weight field
Fix warning:
Undefined property: Reception::$weight
* societe: add country_id field
* reception: use getDolGlobalInt when suitable
Using empty() implies that the value actually exists on the stdClass at
$conf->global, but it's not always the case. getDolGlobalInt will handle
this smoothly by checking first, which solves warnings like those:
Undefined property: stdClass::$STOCK_CALCULATE_ON_RECEPTION
* ReceptionTest: add new test
The test checks the usual workflow of the Reception class, with, on the
one hand, the common CRUD operations:
- create
- fetch
- update
- delete
And on the other hand, the status handling for Reception:
- valid: STATUS_DRAFT -> STATUS_VALID
- setClosed: STATUS_VALID -> STATUS_CLOSED
- reOpen: STATUS_CLOSED -> STATUS_VALID
- setDraft: STATUS_VALID -> STATUS_DRAFT
The stocks lines are not tested yet, and the error cases, like any other
transition not described above, are not tested either. The permissions
for some of the operations are hardcoded for the test and there is no
failure check when the permission is not set yet.
2023-10-21 16:28:30 +02:00
if ( getDolGlobalInt ( 'MAIN_OPTIMIZEFORTEXTBROWSER' )) {
2020-10-28 17:49:52 +01:00
$label = $langs -> trans ( " Reception " );
2025-01-09 01:41:24 +01:00
$linkclose .= ' alt="' . dolPrintHTMLForAttribute ( $label ) . '"' ;
2020-10-28 17:49:52 +01:00
}
2025-01-09 01:41:24 +01:00
$linkclose .= ' title="' . dolPrintHTMLForAttribute ( $label ) . '"' ;
2020-10-28 17:49:52 +01:00
$linkclose .= ' class="classfortooltip"' ;
2018-10-03 12:22:41 +02:00
}
2020-10-28 17:49:52 +01:00
$linkstart = '<a href="' . $url . '"' ;
$linkstart .= $linkclose . '>' ;
2019-11-13 18:32:11 +01:00
$linkend = '</a>' ;
2018-10-03 12:22:41 +02:00
2023-04-18 14:47:02 +02:00
$result .= $linkstart ;
2021-02-26 20:53:03 +01:00
if ( $withpicto ) {
2023-04-18 14:47:02 +02:00
$result .= img_object (( $notooltip ? '' : $label ), $this -> picto , '' , 0 , 0 , $notooltip ? 0 : 1 );
2021-02-26 20:53:03 +01:00
}
2023-04-18 14:47:02 +02:00
if ( $withpicto != 2 ) {
$result .= $this -> ref ;
2021-02-26 20:53:03 +01:00
}
2023-04-18 14:47:02 +02:00
$result .= $linkend ;
2021-11-22 19:57:26 +01:00
global $action ;
2022-02-15 19:04:18 +01:00
$hookmanager -> initHooks ( array ( $this -> element . 'dao' ));
2024-03-13 21:37:09 +01:00
$parameters = array ( 'id' => $this -> id , 'getnomurl' => & $result );
2021-11-22 19:57:26 +01:00
$reshook = $hookmanager -> executeHooks ( 'getNomUrl' , $parameters , $this , $action ); // Note that $action and $object may have been modified by some hooks
if ( $reshook > 0 ) {
$result = $hookmanager -> resPrint ;
} else {
$result .= $hookmanager -> resPrint ;
}
2018-10-03 12:22:41 +02:00
return $result ;
}
/**
2020-10-28 17:49:52 +01:00
* Return status label
*
* @ param int $mode 0 = Long label , 1 = Short label , 2 = Picto + Short label , 3 = Picto , 4 = Picto + Long label , 5 = Short label + Picto
* @ return string Libelle
*/
public function getLibStatut ( $mode = 0 )
{
return $this -> LibStatut ( $this -> statut , $mode );
}
2018-10-03 12:22:41 +02:00
2019-03-01 23:08:57 +01:00
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2018-10-03 12:22:41 +02:00
/**
* Return label of a status
*
2019-11-01 23:58:14 +01:00
* @ param int $status Id status
2018-10-03 12:22:41 +02:00
* @ param int $mode 0 = Long label , 1 = Short label , 2 = Picto + Short label , 3 = Picto , 4 = Picto + Long label , 5 = Short label + Picto
* @ return string Label of status
*/
2020-10-28 17:49:52 +01:00
public function LibStatut ( $status , $mode )
{
// phpcs:enable
global $langs ;
2019-11-04 19:28:04 +01:00
2023-01-12 13:02:04 +01:00
// List of long language codes for status
$this -> labelStatus [ - 1 ] = 'StatusReceptionCanceled' ;
$this -> labelStatus [ 0 ] = 'StatusReceptionDraft' ;
// product to receive if stock increase is on close or already received if stock increase is on validation
$this -> labelStatus [ 1 ] = 'StatusReceptionValidated' ;
if ( getDolGlobalInt ( " STOCK_CALCULATE_ON_RECEPTION " )) {
$this -> labelStatus [ 1 ] = 'StatusReceptionValidatedReceived' ;
}
if ( getDolGlobalInt ( " STOCK_CALCULATE_ON_RECEPTION_CLOSE " )) {
$this -> labelStatus [ 1 ] = 'StatusReceptionValidatedToReceive' ;
}
$this -> labelStatus [ 2 ] = 'StatusReceptionProcessed' ;
// List of short language codes for status
$this -> labelStatusShort [ - 1 ] = 'StatusReceptionCanceledShort' ;
$this -> labelStatusShort [ 0 ] = 'StatusReceptionDraftShort' ;
$this -> labelStatusShort [ 1 ] = 'StatusReceptionValidatedShort' ;
$this -> labelStatusShort [ 2 ] = 'StatusReceptionProcessedShort' ;
$labelStatus = $langs -> transnoentitiesnoconv ( $this -> labelStatus [ $status ]);
$labelStatusShort = $langs -> transnoentitiesnoconv ( $this -> labelStatusShort [ $status ]);
2019-11-04 19:28:04 +01:00
2020-10-28 17:49:52 +01:00
$statusType = 'status' . $status ;
2021-02-26 20:53:03 +01:00
if ( $status == self :: STATUS_VALIDATED ) {
$statusType = 'status4' ;
}
if ( $status == self :: STATUS_CLOSED ) {
$statusType = 'status6' ;
}
2019-11-04 19:28:04 +01:00
2020-10-28 17:49:52 +01:00
return dolGetStatus ( $labelStatus , $labelStatusShort , '' , $statusType , $mode );
2018-10-03 12:22:41 +02:00
}
2023-12-19 11:51:48 +01:00
/**
2024-08-07 01:20:43 +02:00
* Return clickable link of object ( with eventually picto )
2023-12-19 11:51:48 +01:00
*
2025-02-03 11:24:16 +01:00
* @ param string $option Where point the link ( 0 => main card , 1 , 2 => shipment , 'nolink' => No link )
* @ param ? array < string , mixed > $arraydata Array of data
* @ return string HTML Code for Kanban thumb .
2023-12-19 11:51:48 +01:00
*/
public function getKanbanView ( $option = '' , $arraydata = null )
{
$selected = ( empty ( $arraydata [ 'selected' ]) ? 0 : $arraydata [ 'selected' ]);
$return = '<div class="box-flex-item box-flex-grow-zero">' ;
$return .= '<div class="info-box info-box-sm">' ;
$return .= '<div class="info-box-icon bg-infobox-action">' ;
$return .= img_picto ( '' , 'order' );
$return .= '</div>' ;
$return .= '<div class="info-box-content">' ;
$return .= '<span class="info-box-ref inline-block tdoverflowmax150 valignmiddle">' . ( method_exists ( $this , 'getNomUrl' ) ? $this -> getNomUrl () : $this -> ref ) . '</span>' ;
if ( $selected >= 0 ) {
$return .= '<input id="cb' . $this -> id . '" class="flat checkforselect fright" type="checkbox" name="toselect[]" value="' . $this -> id . '"' . ( $selected ? ' checked="checked"' : '' ) . '>' ;
}
if ( property_exists ( $this , 'thirdparty' ) && is_object ( $this -> thirdparty )) {
$return .= '<br><div class="info-box-ref tdoverflowmax150">' . $this -> thirdparty -> getNomUrl ( 1 ) . '</div>' ;
}
2023-12-19 12:33:55 +01:00
/* if ( property_exists ( $this , 'total_ht' )) {
2023-12-19 11:51:48 +01:00
$return .= '<div class="info-box-ref amount">' . price ( $this -> total_ht , 0 , $langs , 0 , - 1 , - 1 , $conf -> currency ) . ' ' . $langs -> trans ( 'HT' ) . '</div>' ;
2023-12-19 12:33:55 +01:00
} */
2023-12-19 11:51:48 +01:00
if ( method_exists ( $this , 'getLibStatut' )) {
$return .= '<div class="info-box-status">' . $this -> getLibStatut ( 3 ) . '</div>' ;
}
$return .= '</div>' ;
$return .= '</div>' ;
$return .= '</div>' ;
2023-12-19 12:33:55 +01:00
2023-12-19 11:51:48 +01:00
return $return ;
}
2018-10-03 12:22:41 +02:00
/**
2020-10-28 17:49:52 +01:00
* Initialise an instance with random values .
* Used to build previews or test instances .
* id must be 0 if object instance is a specimen .
*
2024-03-02 16:38:35 +01:00
* @ return int
2020-10-28 17:49:52 +01:00
*/
public function initAsSpecimen ()
{
2018-10-03 12:22:41 +02:00
global $langs ;
2019-05-09 17:16:35 +02:00
include_once DOL_DOCUMENT_ROOT . '/fourn/class/fournisseur.commande.class.php' ;
include_once DOL_DOCUMENT_ROOT . '/fourn/class/fournisseur.commande.dispatch.class.php' ;
2019-11-13 18:32:11 +01:00
$now = dol_now ();
2018-10-03 12:22:41 +02:00
dol_syslog ( get_class ( $this ) . " ::initAsSpecimen " );
2019-11-13 18:32:11 +01:00
$order = new CommandeFournisseur ( $this -> db );
2018-10-03 12:22:41 +02:00
$order -> initAsSpecimen ();
2024-01-12 17:18:52 +01:00
// Initialise parameters
2019-11-13 18:32:11 +01:00
$this -> id = 0 ;
2018-10-03 12:22:41 +02:00
$this -> ref = 'SPECIMEN' ;
2019-11-13 18:32:11 +01:00
$this -> specimen = 1 ;
2018-10-03 12:22:41 +02:00
$this -> statut = 1 ;
2024-05-22 20:40:11 +02:00
$this -> status = 1 ;
2018-10-03 12:22:41 +02:00
$this -> date = $now ;
$this -> date_creation = $now ;
$this -> date_valid = $now ;
$this -> date_delivery = $now ;
2019-11-13 18:32:11 +01:00
$this -> date_reception = $now + 24 * 3600 ;
2018-10-03 12:22:41 +02:00
$this -> entrepot_id = 0 ;
$this -> socid = 1 ;
2020-10-28 17:49:52 +01:00
$this -> origin_id = 1 ;
2024-04-03 00:51:18 +02:00
$this -> origin_type = 'supplier_order' ;
2023-11-17 11:19:51 +01:00
$this -> origin_object = $order ;
2018-10-03 12:22:41 +02:00
2020-10-28 17:49:52 +01:00
$this -> note_private = 'Private note' ;
$this -> note_public = 'Public note' ;
2018-10-03 12:22:41 +02:00
2024-05-22 20:58:13 +02:00
$this -> tracking_number = 'TRACKID-ABC123' ;
$this -> fk_incoterms = 1 ;
2024-05-22 20:40:11 +02:00
2024-11-21 19:40:52 +01:00
$nbp = min ( 1000 , GETPOSTINT ( 'nblines' ) ? GETPOSTINT ( 'nblines' ) : 5 ); // We can force the nb of lines to test from command line (but not more than 1000)
2018-10-03 12:22:41 +02:00
$xnbp = 0 ;
2021-02-26 20:53:03 +01:00
while ( $xnbp < $nbp ) {
2019-11-13 18:32:11 +01:00
$line = new CommandeFournisseurDispatch ( $this -> db );
$line -> desc = $langs -> trans ( " Description " ) . " " . $xnbp ;
2023-04-08 15:08:55 +02:00
$line -> libelle = $langs -> trans ( " Description " ) . " " . $xnbp ; // deprecated
$line -> label = $langs -> trans ( " Description " ) . " " . $xnbp ;
2019-11-13 18:32:11 +01:00
$line -> qty = 10 ;
2018-12-15 13:58:39 +01:00
2023-11-17 11:19:51 +01:00
$line -> fk_product = $this -> origin_object -> lines [ $xnbp ] -> fk_product ;
2018-10-03 12:22:41 +02:00
2019-11-13 18:32:11 +01:00
$this -> lines [] = $line ;
2018-10-03 12:22:41 +02:00
$xnbp ++ ;
}
2024-03-02 16:38:35 +01:00
return 1 ;
2018-10-03 12:22:41 +02:00
}
2018-12-15 13:58:39 +01:00
2020-10-31 14:32:18 +01:00
/**
2018-10-03 12:22:41 +02:00
* Set the planned delivery date
*
2024-01-12 17:18:52 +01:00
* @ param User $user Object utilisateur qui modifie
2020-10-06 11:37:55 +02:00
* @ param integer $delivery_date Delivery date
2023-12-01 19:51:32 +01:00
* @ return int Return integer < 0 if KO , > 0 if OK
2018-10-03 12:22:41 +02:00
*/
2020-10-31 14:32:18 +01:00
public function setDeliveryDate ( $user , $delivery_date )
2018-10-03 12:22:41 +02:00
{
2018-10-23 14:31:58 +02:00
// phpcs:enable
2023-11-27 13:26:44 +01:00
if ( $user -> hasRight ( 'reception' , 'creer' )) {
2018-10-03 12:22:41 +02:00
$sql = " UPDATE " . MAIN_DB_PREFIX . " reception " ;
2020-10-06 11:37:55 +02:00
$sql .= " SET date_delivery = " . ( $delivery_date ? " ' " . $this -> db -> idate ( $delivery_date ) . " ' " : 'null' );
2021-08-27 16:33:03 +02:00
$sql .= " WHERE rowid = " . (( int ) $this -> id );
2018-10-03 12:22:41 +02:00
2020-10-26 16:50:52 +01:00
dol_syslog ( get_class ( $this ) . " ::setDeliveryDate " , LOG_DEBUG );
2019-11-13 18:32:11 +01:00
$resql = $this -> db -> query ( $sql );
2021-02-26 20:53:03 +01:00
if ( $resql ) {
2020-10-06 11:37:55 +02:00
$this -> date_delivery = $delivery_date ;
2018-10-03 12:22:41 +02:00
return 1 ;
2020-05-21 15:05:19 +02:00
} else {
2019-11-13 18:32:11 +01:00
$this -> error = $this -> db -> error ();
2018-10-03 12:22:41 +02:00
return - 1 ;
}
2020-05-21 15:05:19 +02:00
} else {
2018-10-03 12:22:41 +02:00
return - 2 ;
}
}
2018-12-15 15:01:49 +01:00
2020-10-28 17:49:52 +01:00
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2018-10-03 12:22:41 +02:00
/**
* Fetch deliveries method and return an array . Load array this -> meths ( rowid => label ) .
*
* @ return void
*/
2020-10-31 14:32:18 +01:00
public function fetch_delivery_methods ()
2018-10-03 12:22:41 +02:00
{
2018-10-23 14:31:58 +02:00
// phpcs:enable
2018-10-03 12:22:41 +02:00
global $langs ;
$this -> meths = array ();
$sql = " SELECT em.rowid, em.code, em.libelle " ;
2019-11-13 18:32:11 +01:00
$sql .= " FROM " . MAIN_DB_PREFIX . " c_shipment_mode as em " ;
$sql .= " WHERE em.active = 1 " ;
$sql .= " ORDER BY em.libelle ASC " ;
2018-10-03 12:22:41 +02:00
$resql = $this -> db -> query ( $sql );
2021-02-26 20:53:03 +01:00
if ( $resql ) {
while ( $obj = $this -> db -> fetch_object ( $resql )) {
2019-11-13 18:32:11 +01:00
$label = $langs -> trans ( 'ReceptionMethod' . $obj -> code );
$this -> meths [ $obj -> rowid ] = ( $label != 'ReceptionMethod' . $obj -> code ? $label : $obj -> libelle );
2018-10-03 12:22:41 +02:00
}
}
}
2018-12-15 15:01:49 +01:00
2020-10-28 17:49:52 +01:00
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
/**
* Fetch all deliveries method and return an array . Load array this -> listmeths .
*
* @ param int $id only this carrier , all if none
* @ return void
*/
2024-01-14 12:12:21 +01:00
public function list_delivery_methods ( $id = 0 )
2020-10-28 17:49:52 +01:00
{
2018-10-23 14:31:58 +02:00
// phpcs:enable
2020-10-28 17:49:52 +01:00
global $langs ;
$this -> listmeths = array ();
$i = 0 ;
$sql = " SELECT em.rowid, em.code, em.libelle, em.description, em.tracking, em.active " ;
$sql .= " FROM " . MAIN_DB_PREFIX . " c_shipment_mode as em " ;
2024-01-14 12:12:21 +01:00
if ( ! empty ( $id )) {
2021-04-25 15:55:36 +02:00
$sql .= " WHERE em.rowid = " . (( int ) $id );
2021-02-26 20:53:03 +01:00
}
2020-10-28 17:49:52 +01:00
$resql = $this -> db -> query ( $sql );
if ( $resql ) {
while ( $obj = $this -> db -> fetch_object ( $resql )) {
$this -> listmeths [ $i ][ 'rowid' ] = $obj -> rowid ;
$this -> listmeths [ $i ][ 'code' ] = $obj -> code ;
$label = $langs -> trans ( 'ReceptionMethod' . $obj -> code );
$this -> listmeths [ $i ][ 'libelle' ] = ( $label != 'ReceptionMethod' . $obj -> code ? $label : $obj -> libelle );
$this -> listmeths [ $i ][ 'description' ] = $obj -> description ;
$this -> listmeths [ $i ][ 'tracking' ] = $obj -> tracking ;
$this -> listmeths [ $i ][ 'active' ] = $obj -> active ;
$i ++ ;
}
}
}
2018-12-15 13:58:39 +01:00
2018-10-03 12:22:41 +02:00
/**
* Forge an set tracking url
*
* @ param string $value Value
* @ return void
*/
2020-10-28 17:49:52 +01:00
public function getUrlTrackingStatus ( $value = '' )
2018-10-03 12:22:41 +02:00
{
2021-02-26 20:53:03 +01:00
if ( ! empty ( $this -> shipping_method_id )) {
2018-10-03 12:22:41 +02:00
$sql = " SELECT em.code, em.tracking " ;
2019-11-13 18:32:11 +01:00
$sql .= " FROM " . MAIN_DB_PREFIX . " c_shipment_mode as em " ;
2021-03-30 19:12:07 +02:00
$sql .= " WHERE em.rowid = " . (( int ) $this -> shipping_method_id );
2018-10-03 12:22:41 +02:00
$resql = $this -> db -> query ( $sql );
2021-02-26 20:53:03 +01:00
if ( $resql ) {
if ( $obj = $this -> db -> fetch_object ( $resql )) {
2018-10-03 12:22:41 +02:00
$tracking = $obj -> tracking ;
}
}
}
2021-02-26 20:53:03 +01:00
if ( ! empty ( $tracking ) && ! empty ( $value )) {
2018-10-03 12:22:41 +02:00
$url = str_replace ( '{TRACKID}' , $value , $tracking );
2024-03-17 18:02:56 +01:00
$this -> tracking_url = sprintf ( '<a target="_blank" rel="noopener noreferrer" href="%s">%s</a>' , $url , ( $value ? $value : 'url' ));
2020-05-21 15:05:19 +02:00
} else {
2018-10-03 12:22:41 +02:00
$this -> tracking_url = $value ;
}
}
/**
2024-03-17 18:02:56 +01:00
* Classify the reception as closed ( this records also the stock movement )
2018-10-03 12:22:41 +02:00
*
2023-12-01 19:51:32 +01:00
* @ return int Return integer < 0 if KO , > 0 if OK
2018-10-03 12:22:41 +02:00
*/
2020-10-28 17:49:52 +01:00
public function setClosed ()
2018-10-03 12:22:41 +02:00
{
2019-11-13 18:32:11 +01:00
global $conf , $langs , $user ;
2018-10-03 12:22:41 +02:00
2019-11-13 18:32:11 +01:00
$error = 0 ;
2018-10-03 12:22:41 +02:00
2023-09-03 21:38:11 +02:00
// Protection. This avoid to move stock later when we should not
2023-09-27 11:28:37 +02:00
if ( $this -> statut == Reception :: STATUS_CLOSED ) {
2023-09-30 11:54:12 +02:00
dol_syslog ( get_class ( $this ) . " ::setClosed already in closed status " , LOG_WARNING );
2023-09-03 21:38:11 +02:00
return 0 ;
}
2018-10-03 12:22:41 +02:00
$this -> db -> begin ();
2023-09-03 21:38:11 +02:00
$sql = 'UPDATE ' . MAIN_DB_PREFIX . 'reception SET fk_statut = ' . self :: STATUS_CLOSED ;
2021-08-27 23:36:06 +02:00
$sql .= " WHERE rowid = " . (( int ) $this -> id ) . ' AND fk_statut > 0' ;
2018-10-03 12:22:41 +02:00
2019-11-13 18:32:11 +01:00
$resql = $this -> db -> query ( $sql );
2021-02-26 20:53:03 +01:00
if ( $resql ) {
2018-10-17 11:56:32 +02:00
// Set order billed if 100% of order is received (qty in reception lines match qty in order lines)
2021-02-26 20:53:03 +01:00
if ( $this -> origin == 'order_supplier' && $this -> origin_id > 0 ) {
2018-10-09 11:33:41 +02:00
$order = new CommandeFournisseur ( $this -> db );
2018-10-03 12:22:41 +02:00
$order -> fetch ( $this -> origin_id );
2019-11-13 18:32:11 +01:00
$order -> loadReceptions ( self :: STATUS_CLOSED ); // Fill $order->receptions = array(orderlineid => qty)
2018-10-03 12:22:41 +02:00
$receptions_match_order = 1 ;
2021-02-26 20:53:03 +01:00
foreach ( $order -> lines as $line ) {
2018-10-03 12:22:41 +02:00
$lineid = $line -> id ;
$qty = $line -> qty ;
FIX|Fix some minor issues on Reception and add a new test for it (#26310)
* reception: reOpen: mirror $this->statut in $this->status
$this->statut is the deprecated variable, $this->status should also get
the correct value.
* reception: setDraft: mirror $this->statut in $this->status
$this->statut is the deprecated variable, $this->status should also get
the correct value.
* reception: add missing $weight field
Fix warning:
Undefined property: Reception::$weight
* societe: add country_id field
* reception: use getDolGlobalInt when suitable
Using empty() implies that the value actually exists on the stdClass at
$conf->global, but it's not always the case. getDolGlobalInt will handle
this smoothly by checking first, which solves warnings like those:
Undefined property: stdClass::$STOCK_CALCULATE_ON_RECEPTION
* ReceptionTest: add new test
The test checks the usual workflow of the Reception class, with, on the
one hand, the common CRUD operations:
- create
- fetch
- update
- delete
And on the other hand, the status handling for Reception:
- valid: STATUS_DRAFT -> STATUS_VALID
- setClosed: STATUS_VALID -> STATUS_CLOSED
- reOpen: STATUS_CLOSED -> STATUS_VALID
- setDraft: STATUS_VALID -> STATUS_DRAFT
The stocks lines are not tested yet, and the error cases, like any other
transition not described above, are not tested either. The permissions
for some of the operations are hardcoded for the test and there is no
failure check when the permission is not set yet.
2023-10-21 16:28:30 +02:00
if (( $line -> product_type == 0 || getDolGlobalInt ( 'STOCK_SUPPORTS_SERVICES' )) && $order -> receptions [ $lineid ] < $qty ) {
2018-10-03 12:22:41 +02:00
$receptions_match_order = 0 ;
2019-11-13 18:32:11 +01:00
$text = 'Qty for order line id ' . $lineid . ' is ' . $qty . '. However in the receptions with status Reception::STATUS_CLOSED=' . self :: STATUS_CLOSED . ' we have qty = ' . $order -> receptions [ $lineid ] . ', so we can t close order' ;
2018-10-03 12:22:41 +02:00
dol_syslog ( $text );
break ;
}
}
2021-02-26 20:53:03 +01:00
if ( $receptions_match_order ) {
2018-10-03 12:22:41 +02:00
dol_syslog ( " Qty for the " . count ( $order -> lines ) . " lines of order have same value for receptions with status Reception::STATUS_CLOSED= " . self :: STATUS_CLOSED . ', so we close order' );
2018-10-09 11:33:41 +02:00
$order -> Livraison ( $user , dol_now (), 'tot' , 'Reception ' . $this -> ref );
2018-10-03 12:22:41 +02:00
}
}
2019-11-13 18:32:11 +01:00
$this -> statut = self :: STATUS_CLOSED ;
2023-09-03 21:38:11 +02:00
$this -> status = self :: STATUS_CLOSED ;
2018-10-03 12:22:41 +02:00
// If stock increment is done on closing
FIX|Fix some minor issues on Reception and add a new test for it (#26310)
* reception: reOpen: mirror $this->statut in $this->status
$this->statut is the deprecated variable, $this->status should also get
the correct value.
* reception: setDraft: mirror $this->statut in $this->status
$this->statut is the deprecated variable, $this->status should also get
the correct value.
* reception: add missing $weight field
Fix warning:
Undefined property: Reception::$weight
* societe: add country_id field
* reception: use getDolGlobalInt when suitable
Using empty() implies that the value actually exists on the stdClass at
$conf->global, but it's not always the case. getDolGlobalInt will handle
this smoothly by checking first, which solves warnings like those:
Undefined property: stdClass::$STOCK_CALCULATE_ON_RECEPTION
* ReceptionTest: add new test
The test checks the usual workflow of the Reception class, with, on the
one hand, the common CRUD operations:
- create
- fetch
- update
- delete
And on the other hand, the status handling for Reception:
- valid: STATUS_DRAFT -> STATUS_VALID
- setClosed: STATUS_VALID -> STATUS_CLOSED
- reOpen: STATUS_CLOSED -> STATUS_VALID
- setDraft: STATUS_VALID -> STATUS_DRAFT
The stocks lines are not tested yet, and the error cases, like any other
transition not described above, are not tested either. The permissions
for some of the operations are hardcoded for the test and there is no
failure check when the permission is not set yet.
2023-10-21 16:28:30 +02:00
if ( ! $error && isModEnabled ( 'stock' ) && getDolGlobalInt ( 'STOCK_CALCULATE_ON_RECEPTION_CLOSE' )) {
2018-10-03 12:22:41 +02:00
require_once DOL_DOCUMENT_ROOT . '/product/stock/class/mouvementstock.class.php' ;
$langs -> load ( " agenda " );
// Loop on each product line to add a stock movement
2018-10-18 15:11:43 +02:00
// TODO possibilite de receptionner a partir d'une propale ou autre origine ?
2018-10-03 12:22:41 +02:00
$sql = " SELECT cd.fk_product, cd.subprice, " ;
2019-11-13 18:32:11 +01:00
$sql .= " ed.rowid, ed.qty, ed.fk_entrepot, " ;
2022-06-08 18:27:47 +02:00
$sql .= " ed.eatby, ed.sellby, ed.batch, " ;
$sql .= " ed.cost_price " ;
2019-11-13 18:32:11 +01:00
$sql .= " FROM " . MAIN_DB_PREFIX . " commande_fournisseurdet as cd, " ;
2024-01-15 09:40:59 +01:00
$sql .= " " . MAIN_DB_PREFIX . " receptiondet_batch as ed " ;
2021-08-23 19:33:24 +02:00
$sql .= " WHERE ed.fk_reception = " . (( int ) $this -> id );
2024-03-19 15:49:42 +01:00
$sql .= " AND cd.rowid = ed.fk_elementdet " ;
2018-10-03 12:22:41 +02:00
dol_syslog ( get_class ( $this ) . " ::valid select details " , LOG_DEBUG );
2019-11-13 18:32:11 +01:00
$resql = $this -> db -> query ( $sql );
2018-12-15 13:58:39 +01:00
2021-02-26 20:53:03 +01:00
if ( $resql ) {
2018-10-03 12:22:41 +02:00
$cpt = $this -> db -> num_rows ( $resql );
2021-02-26 20:53:03 +01:00
for ( $i = 0 ; $i < $cpt ; $i ++ ) {
2018-10-03 12:22:41 +02:00
$obj = $this -> db -> fetch_object ( $resql );
2018-12-15 13:58:39 +01:00
2018-10-09 11:33:41 +02:00
$qty = $obj -> qty ;
2018-12-15 13:58:39 +01:00
2021-02-26 20:53:03 +01:00
if ( $qty <= 0 ) {
continue ;
}
2018-10-03 12:22:41 +02:00
dol_syslog ( get_class ( $this ) . " ::valid movement index " . $i . " ed.rowid= " . $obj -> rowid . " edb.rowid= " . $obj -> edbrowid );
$mouvS = new MouvementStock ( $this -> db );
$mouvS -> origin = & $this ;
2022-03-22 13:46:55 +01:00
$mouvS -> setOrigin ( $this -> element , $this -> id );
2018-10-03 12:22:41 +02:00
2021-02-26 20:53:03 +01:00
if ( empty ( $obj -> batch )) {
2018-10-03 12:22:41 +02:00
// line without batch detail
// We decrement stock of product (and sub-products) -> update table llx_product_stock (key of this table is fk_product+fk_entrepot) and add a movement record
2021-11-19 13:46:30 +01:00
$inventorycode = '' ;
2022-06-08 18:27:47 +02:00
$result = $mouvS -> reception ( $user , $obj -> fk_product , $obj -> fk_entrepot , $qty , $obj -> cost_price , $langs -> trans ( " ReceptionClassifyClosedInDolibarr " , $this -> ref ), '' , '' , '' , '' , 0 , $inventorycode );
2018-10-03 12:22:41 +02:00
if ( $result < 0 ) {
2020-10-28 17:49:52 +01:00
$this -> error = $mouvS -> error ;
$this -> errors = $mouvS -> errors ;
2023-12-04 13:53:48 +01:00
$error ++ ;
break ;
2018-10-03 12:22:41 +02:00
}
2020-05-21 15:05:19 +02:00
} else {
2018-10-03 12:22:41 +02:00
// line with batch detail
// We decrement stock of product (and sub-products) -> update table llx_product_stock (key of this table is fk_product+fk_entrepot) and add a movement record
2021-11-19 13:46:30 +01:00
$inventorycode = '' ;
2022-06-08 18:27:47 +02:00
$result = $mouvS -> reception ( $user , $obj -> fk_product , $obj -> fk_entrepot , $qty , $obj -> cost_price , $langs -> trans ( " ReceptionClassifyClosedInDolibarr " , $this -> ref ), $this -> db -> jdate ( $obj -> eatby ), $this -> db -> jdate ( $obj -> sellby ), $obj -> batch , '' , 0 , $inventorycode );
2018-12-15 13:58:39 +01:00
2018-10-03 12:22:41 +02:00
if ( $result < 0 ) {
2020-10-28 17:49:52 +01:00
$this -> error = $mouvS -> error ;
$this -> errors = $mouvS -> errors ;
2023-12-04 13:53:48 +01:00
$error ++ ;
break ;
2018-10-03 12:22:41 +02:00
}
}
}
2020-05-21 15:05:19 +02:00
} else {
2019-11-13 18:32:11 +01:00
$this -> error = $this -> db -> lasterror ();
2018-10-03 12:22:41 +02:00
$error ++ ;
}
}
// Call trigger
2021-02-26 20:53:03 +01:00
if ( ! $error ) {
2020-10-28 17:49:52 +01:00
$result = $this -> call_trigger ( 'RECEPTION_CLOSED' , $user );
if ( $result < 0 ) {
$error ++ ;
}
2018-10-03 12:22:41 +02:00
}
2020-05-21 15:05:19 +02:00
} else {
2018-10-03 12:22:41 +02:00
dol_print_error ( $this -> db );
2020-10-28 17:49:52 +01:00
$error ++ ;
2018-10-03 12:22:41 +02:00
}
2021-02-26 20:53:03 +01:00
if ( ! $error ) {
2020-10-28 17:49:52 +01:00
$this -> db -> commit ();
return 1 ;
2020-05-21 15:05:19 +02:00
} else {
2024-01-11 11:24:21 +01:00
$this -> statut = self :: STATUS_VALIDATED ;
$this -> status = self :: STATUS_VALIDATED ;
2020-10-28 17:49:52 +01:00
$this -> db -> rollback ();
return - 1 ;
2018-10-03 12:22:41 +02:00
}
}
2018-12-15 15:01:49 +01:00
2021-02-09 13:10:11 +01:00
/**
2024-01-12 17:18:52 +01:00
* Classify the reception as invoiced ( used for example by trigger when WORKFLOW_RECEPTION_CLASSIFY_BILLED_INVOICE is on )
2021-02-09 13:10:11 +01:00
*
2023-12-06 15:46:39 +01:00
* @ return int Return integer < 0 if ko , > 0 if ok
2021-02-09 13:10:11 +01:00
*/
public function setBilled ()
{
2020-10-28 17:49:52 +01:00
global $user ;
2019-11-13 18:32:11 +01:00
$error = 0 ;
2018-10-03 12:22:41 +02:00
$this -> db -> begin ();
2018-12-15 13:58:39 +01:00
2023-09-27 11:28:37 +02:00
if ( $this -> statut == Reception :: STATUS_VALIDATED ) {
// do not close if already closed
$this -> setClosed ();
}
2018-10-03 12:22:41 +02:00
2023-09-03 21:38:11 +02:00
$sql = 'UPDATE ' . MAIN_DB_PREFIX . 'reception SET billed=1' ;
2021-08-27 23:36:06 +02:00
$sql .= " WHERE rowid = " . (( int ) $this -> id ) . ' AND fk_statut > 0' ;
2018-10-03 12:22:41 +02:00
2019-11-13 18:32:11 +01:00
$resql = $this -> db -> query ( $sql );
2021-02-26 20:53:03 +01:00
if ( $resql ) {
2019-11-13 18:32:11 +01:00
$this -> billed = 1 ;
2018-10-03 12:22:41 +02:00
// Call trigger
2019-11-13 18:32:11 +01:00
$result = $this -> call_trigger ( 'RECEPTION_BILLED' , $user );
2018-10-03 12:22:41 +02:00
if ( $result < 0 ) {
2023-09-03 21:38:11 +02:00
$this -> billed = 0 ;
2018-10-03 12:22:41 +02:00
$error ++ ;
}
} else {
$error ++ ;
2019-11-13 18:32:11 +01:00
$this -> errors [] = $this -> db -> lasterror ;
2018-10-03 12:22:41 +02:00
}
if ( empty ( $error )) {
$this -> db -> commit ();
return 1 ;
2020-05-21 15:05:19 +02:00
} else {
2018-10-03 12:22:41 +02:00
$this -> db -> rollback ();
return - 1 ;
}
}
/**
* Classify the reception as validated / opened
*
2023-12-06 15:46:39 +01:00
* @ return int Return integer < 0 if ko , > 0 if ok
2018-10-03 12:22:41 +02:00
*/
2020-10-28 17:49:52 +01:00
public function reOpen ()
2018-10-03 12:22:41 +02:00
{
2019-11-13 18:32:11 +01:00
global $conf , $langs , $user ;
2018-10-03 12:22:41 +02:00
2019-11-13 18:32:11 +01:00
$error = 0 ;
2018-10-03 12:22:41 +02:00
$this -> db -> begin ();
2018-10-10 12:19:57 +02:00
$sql = 'UPDATE ' . MAIN_DB_PREFIX . 'reception SET fk_statut=1, billed=0' ;
2021-08-27 23:36:06 +02:00
$sql .= " WHERE rowid = " . (( int ) $this -> id ) . ' AND fk_statut > 0' ;
2018-10-03 12:22:41 +02:00
2019-11-13 18:32:11 +01:00
$resql = $this -> db -> query ( $sql );
2021-02-26 20:53:03 +01:00
if ( $resql ) {
FIX|Fix some minor issues on Reception and add a new test for it (#26310)
* reception: reOpen: mirror $this->statut in $this->status
$this->statut is the deprecated variable, $this->status should also get
the correct value.
* reception: setDraft: mirror $this->statut in $this->status
$this->statut is the deprecated variable, $this->status should also get
the correct value.
* reception: add missing $weight field
Fix warning:
Undefined property: Reception::$weight
* societe: add country_id field
* reception: use getDolGlobalInt when suitable
Using empty() implies that the value actually exists on the stdClass at
$conf->global, but it's not always the case. getDolGlobalInt will handle
this smoothly by checking first, which solves warnings like those:
Undefined property: stdClass::$STOCK_CALCULATE_ON_RECEPTION
* ReceptionTest: add new test
The test checks the usual workflow of the Reception class, with, on the
one hand, the common CRUD operations:
- create
- fetch
- update
- delete
And on the other hand, the status handling for Reception:
- valid: STATUS_DRAFT -> STATUS_VALID
- setClosed: STATUS_VALID -> STATUS_CLOSED
- reOpen: STATUS_CLOSED -> STATUS_VALID
- setDraft: STATUS_VALID -> STATUS_DRAFT
The stocks lines are not tested yet, and the error cases, like any other
transition not described above, are not tested either. The permissions
for some of the operations are hardcoded for the test and there is no
failure check when the permission is not set yet.
2023-10-21 16:28:30 +02:00
$this -> statut = self :: STATUS_VALIDATED ;
$this -> status = self :: STATUS_VALIDATED ;
2019-11-13 18:32:11 +01:00
$this -> billed = 0 ;
2018-10-03 12:22:41 +02:00
// If stock increment is done on closing
FIX|Fix some minor issues on Reception and add a new test for it (#26310)
* reception: reOpen: mirror $this->statut in $this->status
$this->statut is the deprecated variable, $this->status should also get
the correct value.
* reception: setDraft: mirror $this->statut in $this->status
$this->statut is the deprecated variable, $this->status should also get
the correct value.
* reception: add missing $weight field
Fix warning:
Undefined property: Reception::$weight
* societe: add country_id field
* reception: use getDolGlobalInt when suitable
Using empty() implies that the value actually exists on the stdClass at
$conf->global, but it's not always the case. getDolGlobalInt will handle
this smoothly by checking first, which solves warnings like those:
Undefined property: stdClass::$STOCK_CALCULATE_ON_RECEPTION
* ReceptionTest: add new test
The test checks the usual workflow of the Reception class, with, on the
one hand, the common CRUD operations:
- create
- fetch
- update
- delete
And on the other hand, the status handling for Reception:
- valid: STATUS_DRAFT -> STATUS_VALID
- setClosed: STATUS_VALID -> STATUS_CLOSED
- reOpen: STATUS_CLOSED -> STATUS_VALID
- setDraft: STATUS_VALID -> STATUS_DRAFT
The stocks lines are not tested yet, and the error cases, like any other
transition not described above, are not tested either. The permissions
for some of the operations are hardcoded for the test and there is no
failure check when the permission is not set yet.
2023-10-21 16:28:30 +02:00
if ( ! $error && isModEnabled ( 'stock' ) && getDolGlobalInt ( 'STOCK_CALCULATE_ON_RECEPTION_CLOSE' )) {
2018-10-03 12:22:41 +02:00
require_once DOL_DOCUMENT_ROOT . '/product/stock/class/mouvementstock.class.php' ;
2018-10-10 15:33:35 +02:00
$numref = $this -> ref ;
2018-10-03 12:22:41 +02:00
$langs -> load ( " agenda " );
// Loop on each product line to add a stock movement
2018-10-18 15:11:43 +02:00
// TODO possibilite de receptionner a partir d'une propale ou autre origine
2018-10-10 15:33:35 +02:00
$sql = " SELECT ed.fk_product, cd.subprice, " ;
2019-11-13 18:32:11 +01:00
$sql .= " ed.rowid, ed.qty, ed.fk_entrepot, " ;
2022-06-08 18:27:47 +02:00
$sql .= " ed.eatby, ed.sellby, ed.batch, " ;
$sql .= " ed.cost_price " ;
2019-11-13 18:32:11 +01:00
$sql .= " FROM " . MAIN_DB_PREFIX . " commande_fournisseurdet as cd, " ;
2024-01-15 09:40:59 +01:00
$sql .= " " . MAIN_DB_PREFIX . " receptiondet_batch as ed " ;
2021-08-23 19:33:24 +02:00
$sql .= " WHERE ed.fk_reception = " . (( int ) $this -> id );
2024-03-19 15:49:42 +01:00
$sql .= " AND cd.rowid = ed.fk_elementdet " ;
2018-12-15 13:58:39 +01:00
2018-10-03 12:22:41 +02:00
dol_syslog ( get_class ( $this ) . " ::valid select details " , LOG_DEBUG );
2019-11-13 18:32:11 +01:00
$resql = $this -> db -> query ( $sql );
2021-02-26 20:53:03 +01:00
if ( $resql ) {
2018-10-03 12:22:41 +02:00
$cpt = $this -> db -> num_rows ( $resql );
2021-02-26 20:53:03 +01:00
for ( $i = 0 ; $i < $cpt ; $i ++ ) {
2018-10-03 12:22:41 +02:00
$obj = $this -> db -> fetch_object ( $resql );
2018-12-15 13:58:39 +01:00
2018-10-10 15:33:35 +02:00
$qty = $obj -> qty ;
2018-12-15 13:58:39 +01:00
2021-02-26 20:53:03 +01:00
if ( $qty <= 0 ) {
continue ;
}
2018-12-15 13:58:39 +01:00
2018-10-10 15:33:35 +02:00
dol_syslog ( get_class ( $this ) . " ::reopen reception movement index " . $i . " ed.rowid= " . $obj -> rowid );
2018-10-03 12:22:41 +02:00
//var_dump($this->lines[$i]);
$mouvS = new MouvementStock ( $this -> db );
$mouvS -> origin = & $this ;
2022-03-22 13:46:55 +01:00
$mouvS -> setOrigin ( $this -> element , $this -> id );
2018-10-03 12:22:41 +02:00
2021-02-26 20:53:03 +01:00
if ( empty ( $obj -> batch )) {
2018-10-03 12:22:41 +02:00
// line without batch detail
// We decrement stock of product (and sub-products) -> update table llx_product_stock (key of this table is fk_product+fk_entrepot) and add a movement record
2021-11-19 13:46:30 +01:00
$inventorycode = '' ;
2022-06-08 18:27:47 +02:00
$result = $mouvS -> livraison ( $user , $obj -> fk_product , $obj -> fk_entrepot , $qty , $obj -> cost_price , $langs -> trans ( " ReceptionUnClassifyCloseddInDolibarr " , $numref ), '' , '' , '' , '' , 0 , $inventorycode );
2021-11-19 14:01:31 +01:00
2018-10-03 12:22:41 +02:00
if ( $result < 0 ) {
2020-10-28 17:49:52 +01:00
$this -> error = $mouvS -> error ;
$this -> errors = $mouvS -> errors ;
2023-12-04 13:53:48 +01:00
$error ++ ;
break ;
2018-10-03 12:22:41 +02:00
}
2020-05-21 15:05:19 +02:00
} else {
2018-10-03 12:22:41 +02:00
// line with batch detail
// We decrement stock of product (and sub-products) -> update table llx_product_stock (key of this table is fk_product+fk_entrepot) and add a movement record
2021-11-19 13:46:30 +01:00
$inventorycode = '' ;
2022-12-12 10:44:34 +01:00
$result = $mouvS -> livraison ( $user , $obj -> fk_product , $obj -> fk_entrepot , $qty , $obj -> cost_price , $langs -> trans ( " ReceptionUnClassifyCloseddInDolibarr " , $numref ), '' , $this -> db -> jdate ( $obj -> eatby ), $this -> db -> jdate ( $obj -> sellby ), $obj -> batch , $obj -> fk_origin_stock , $inventorycode );
2018-10-03 12:22:41 +02:00
if ( $result < 0 ) {
2020-10-28 17:49:52 +01:00
$this -> error = $mouvS -> error ;
$this -> errors = $mouvS -> errors ;
2023-12-04 13:53:48 +01:00
$error ++ ;
break ;
2018-10-03 12:22:41 +02:00
}
}
}
2020-05-21 15:05:19 +02:00
} else {
2019-11-13 18:32:11 +01:00
$this -> error = $this -> db -> lasterror ();
2018-10-03 12:22:41 +02:00
$error ++ ;
}
}
2021-02-26 20:53:03 +01:00
if ( ! $error ) {
2020-10-28 17:49:52 +01:00
// Call trigger
$result = $this -> call_trigger ( 'RECEPTION_REOPEN' , $user );
if ( $result < 0 ) {
$error ++ ;
}
2021-02-26 20:53:03 +01:00
}
2018-12-15 13:58:39 +01:00
2021-11-19 14:01:31 +01:00
if ( ! $error && $this -> origin == 'order_supplier' ) {
2018-10-11 10:00:07 +02:00
$commande = new CommandeFournisseur ( $this -> db );
$commande -> fetch ( $this -> origin_id );
2021-11-19 14:01:31 +01:00
$result = $commande -> setStatus ( $user , 4 );
if ( $result < 0 ) {
$error ++ ;
$this -> error = $commande -> error ;
$this -> errors = $commande -> errors ;
}
2018-10-11 10:00:07 +02:00
}
2018-10-03 12:22:41 +02:00
} else {
$error ++ ;
2019-11-13 18:32:11 +01:00
$this -> errors [] = $this -> db -> lasterror ();
2018-10-03 12:22:41 +02:00
}
2021-02-26 20:53:03 +01:00
if ( ! $error ) {
2018-10-03 12:22:41 +02:00
$this -> db -> commit ();
return 1 ;
2020-05-21 15:05:19 +02:00
} else {
2018-10-03 12:22:41 +02:00
$this -> db -> rollback ();
return - 1 ;
}
}
2018-12-15 13:58:39 +01:00
2023-12-04 13:53:48 +01:00
/**
* Set draft status
*
* @ param User $user Object user that modify
* @ return int Return integer < 0 if KO , > 0 if OK
*/
2020-10-28 17:49:52 +01:00
public function setDraft ( $user )
{
2018-10-23 14:31:58 +02:00
// phpcs:enable
2020-10-28 17:49:52 +01:00
global $conf , $langs ;
2018-10-03 12:22:41 +02:00
2020-10-28 17:49:52 +01:00
$error = 0 ;
2018-10-03 12:22:41 +02:00
2020-10-28 17:49:52 +01:00
// Protection
2021-02-26 20:53:03 +01:00
if ( $this -> statut <= self :: STATUS_DRAFT ) {
2020-10-28 17:49:52 +01:00
return 0 ;
}
2018-10-03 12:22:41 +02:00
2023-11-27 13:26:44 +01:00
if ( ! (( ! getDolGlobalInt ( 'MAIN_USE_ADVANCED_PERMS' ) && $user -> hasRight ( 'reception' , 'creer' ))
|| ( getDolGlobalInt ( 'MAIN_USE_ADVANCED_PERMS' ) && $user -> hasRight ( 'reception' , 'reception_advance' , 'validate' )))) {
2020-10-28 17:49:52 +01:00
$this -> error = 'Permission denied' ;
return - 1 ;
}
2018-10-03 12:22:41 +02:00
2020-10-28 17:49:52 +01:00
$this -> db -> begin ();
2018-10-03 12:22:41 +02:00
2020-10-28 17:49:52 +01:00
$sql = " UPDATE " . MAIN_DB_PREFIX . " reception " ;
$sql .= " SET fk_statut = " . self :: STATUS_DRAFT ;
2021-08-27 16:33:03 +02:00
$sql .= " WHERE rowid = " . (( int ) $this -> id );
2018-10-03 12:22:41 +02:00
2020-10-28 17:49:52 +01:00
dol_syslog ( __METHOD__ , LOG_DEBUG );
2021-02-26 20:53:03 +01:00
if ( $this -> db -> query ( $sql )) {
2020-10-28 17:49:52 +01:00
// If stock increment is done on closing
FIX|Fix some minor issues on Reception and add a new test for it (#26310)
* reception: reOpen: mirror $this->statut in $this->status
$this->statut is the deprecated variable, $this->status should also get
the correct value.
* reception: setDraft: mirror $this->statut in $this->status
$this->statut is the deprecated variable, $this->status should also get
the correct value.
* reception: add missing $weight field
Fix warning:
Undefined property: Reception::$weight
* societe: add country_id field
* reception: use getDolGlobalInt when suitable
Using empty() implies that the value actually exists on the stdClass at
$conf->global, but it's not always the case. getDolGlobalInt will handle
this smoothly by checking first, which solves warnings like those:
Undefined property: stdClass::$STOCK_CALCULATE_ON_RECEPTION
* ReceptionTest: add new test
The test checks the usual workflow of the Reception class, with, on the
one hand, the common CRUD operations:
- create
- fetch
- update
- delete
And on the other hand, the status handling for Reception:
- valid: STATUS_DRAFT -> STATUS_VALID
- setClosed: STATUS_VALID -> STATUS_CLOSED
- reOpen: STATUS_CLOSED -> STATUS_VALID
- setDraft: STATUS_VALID -> STATUS_DRAFT
The stocks lines are not tested yet, and the error cases, like any other
transition not described above, are not tested either. The permissions
for some of the operations are hardcoded for the test and there is no
failure check when the permission is not set yet.
2023-10-21 16:28:30 +02:00
if ( ! $error && isModEnabled ( 'stock' ) && getDolGlobalInt ( 'STOCK_CALCULATE_ON_RECEPTION' )) {
2018-10-03 12:22:41 +02:00
require_once DOL_DOCUMENT_ROOT . '/product/stock/class/mouvementstock.class.php' ;
$langs -> load ( " agenda " );
// Loop on each product line to add a stock movement
2018-10-18 15:11:43 +02:00
// TODO possibilite de receptionner a partir d'une propale ou autre origine
2018-10-03 12:22:41 +02:00
$sql = " SELECT cd.fk_product, cd.subprice, " ;
2019-11-13 18:32:11 +01:00
$sql .= " ed.rowid, ed.qty, ed.fk_entrepot, " ;
2022-06-08 18:27:47 +02:00
$sql .= " ed.eatby, ed.sellby, ed.batch, " ;
$sql .= " ed.cost_price " ;
2019-11-13 18:32:11 +01:00
$sql .= " FROM " . MAIN_DB_PREFIX . " commande_fournisseurdet as cd, " ;
2024-01-15 09:40:59 +01:00
$sql .= " " . MAIN_DB_PREFIX . " receptiondet_batch as ed " ;
2021-08-23 19:33:24 +02:00
$sql .= " WHERE ed.fk_reception = " . (( int ) $this -> id );
2024-03-19 15:49:42 +01:00
$sql .= " AND cd.rowid = ed.fk_elementdet " ;
2018-10-03 12:22:41 +02:00
dol_syslog ( get_class ( $this ) . " ::valid select details " , LOG_DEBUG );
2019-11-13 18:32:11 +01:00
$resql = $this -> db -> query ( $sql );
2021-02-26 20:53:03 +01:00
if ( $resql ) {
2018-10-03 12:22:41 +02:00
$cpt = $this -> db -> num_rows ( $resql );
2021-02-26 20:53:03 +01:00
for ( $i = 0 ; $i < $cpt ; $i ++ ) {
2018-10-03 12:22:41 +02:00
$obj = $this -> db -> fetch_object ( $resql );
2018-12-15 13:58:39 +01:00
2018-10-09 11:33:41 +02:00
$qty = $obj -> qty ;
2018-12-15 13:58:39 +01:00
2021-02-26 20:53:03 +01:00
if ( $qty <= 0 ) {
continue ;
}
2018-10-03 12:22:41 +02:00
dol_syslog ( get_class ( $this ) . " ::reopen reception movement index " . $i . " ed.rowid= " . $obj -> rowid . " edb.rowid= " . $obj -> edbrowid );
//var_dump($this->lines[$i]);
$mouvS = new MouvementStock ( $this -> db );
$mouvS -> origin = & $this ;
2022-03-22 13:46:55 +01:00
$mouvS -> setOrigin ( $this -> element , $this -> id );
2018-10-03 12:22:41 +02:00
2021-02-26 20:53:03 +01:00
if ( empty ( $obj -> batch )) {
2018-10-03 12:22:41 +02:00
// line without batch detail
// We decrement stock of product (and sub-products) -> update table llx_product_stock (key of this table is fk_product+fk_entrepot) and add a movement record
2021-11-19 13:46:30 +01:00
$inventorycode = '' ;
2022-06-08 18:27:47 +02:00
$result = $mouvS -> livraison ( $user , $obj -> fk_product , $obj -> fk_entrepot , $qty , $obj -> cost_price , $langs -> trans ( " ReceptionBackToDraftInDolibarr " , $this -> ref ), '' , '' , '' , '' , 0 , $inventorycode );
2018-10-03 12:22:41 +02:00
if ( $result < 0 ) {
2020-10-28 17:49:52 +01:00
$this -> error = $mouvS -> error ;
$this -> errors = $mouvS -> errors ;
2018-12-15 16:37:00 +01:00
$error ++ ;
break ;
2018-10-03 12:22:41 +02:00
}
2020-05-21 15:05:19 +02:00
} else {
2018-10-03 12:22:41 +02:00
// line with batch detail
// We decrement stock of product (and sub-products) -> update table llx_product_stock (key of this table is fk_product+fk_entrepot) and add a movement record
2021-11-19 13:46:30 +01:00
$inventorycode = '' ;
2022-12-12 10:39:24 +01:00
$result = $mouvS -> livraison ( $user , $obj -> fk_product , $obj -> fk_entrepot , $qty , $obj -> cost_price , $langs -> trans ( " ReceptionBackToDraftInDolibarr " , $this -> ref ), '' , $this -> db -> jdate ( $obj -> eatby ), $this -> db -> jdate ( $obj -> sellby ), $obj -> batch , 0 , $inventorycode );
2018-10-03 12:22:41 +02:00
if ( $result < 0 ) {
2020-10-28 17:49:52 +01:00
$this -> error = $mouvS -> error ;
$this -> errors = $mouvS -> errors ;
2023-12-04 13:53:48 +01:00
$error ++ ;
break ;
2018-10-03 12:22:41 +02:00
}
}
}
2020-05-21 15:05:19 +02:00
} else {
2019-11-13 18:32:11 +01:00
$this -> error = $this -> db -> lasterror ();
2018-10-03 12:22:41 +02:00
$error ++ ;
}
}
2018-12-15 13:58:39 +01:00
2020-10-28 17:49:52 +01:00
if ( ! $error ) {
// Call trigger
$result = $this -> call_trigger ( 'RECEPTION_UNVALIDATE' , $user );
2021-02-26 20:53:03 +01:00
if ( $result < 0 ) {
$error ++ ;
}
2020-10-28 17:49:52 +01:00
}
2021-02-26 20:53:03 +01:00
if ( $this -> origin == 'order_supplier' ) {
if ( ! empty ( $this -> origin ) && $this -> origin_id > 0 ) {
2018-10-23 09:22:13 +02:00
$this -> fetch_origin ();
2024-03-24 06:12:18 +01:00
if ( $this -> origin_object -> statut == 4 ) { // If order source of reception is "partially received"
2018-12-15 13:58:39 +01:00
// Check if there is no more reception validated.
2024-03-24 06:12:18 +01:00
$this -> origin_object -> fetchObjectLinked ();
2018-10-23 09:22:13 +02:00
$setStatut = 1 ;
2024-03-24 06:12:18 +01:00
if ( ! empty ( $this -> origin_object -> linkedObjects [ 'reception' ])) {
foreach ( $this -> origin_object -> linkedObjects [ 'reception' ] as $rcption ) {
2021-02-26 20:53:03 +01:00
if ( $rcption -> statut > 0 ) {
2018-10-23 09:22:13 +02:00
$setStatut = 0 ;
break ;
}
}
//var_dump($this->$origin->receptions);exit;
2021-02-26 20:53:03 +01:00
if ( $setStatut ) {
2024-03-24 06:12:18 +01:00
$this -> origin_object -> setStatut ( 3 ); // ordered
2018-10-23 09:22:13 +02:00
}
}
}
}
2018-10-03 12:22:41 +02:00
}
2020-10-28 17:49:52 +01:00
if ( ! $error ) {
$this -> statut = self :: STATUS_DRAFT ;
FIX|Fix some minor issues on Reception and add a new test for it (#26310)
* reception: reOpen: mirror $this->statut in $this->status
$this->statut is the deprecated variable, $this->status should also get
the correct value.
* reception: setDraft: mirror $this->statut in $this->status
$this->statut is the deprecated variable, $this->status should also get
the correct value.
* reception: add missing $weight field
Fix warning:
Undefined property: Reception::$weight
* societe: add country_id field
* reception: use getDolGlobalInt when suitable
Using empty() implies that the value actually exists on the stdClass at
$conf->global, but it's not always the case. getDolGlobalInt will handle
this smoothly by checking first, which solves warnings like those:
Undefined property: stdClass::$STOCK_CALCULATE_ON_RECEPTION
* ReceptionTest: add new test
The test checks the usual workflow of the Reception class, with, on the
one hand, the common CRUD operations:
- create
- fetch
- update
- delete
And on the other hand, the status handling for Reception:
- valid: STATUS_DRAFT -> STATUS_VALID
- setClosed: STATUS_VALID -> STATUS_CLOSED
- reOpen: STATUS_CLOSED -> STATUS_VALID
- setDraft: STATUS_VALID -> STATUS_DRAFT
The stocks lines are not tested yet, and the error cases, like any other
transition not described above, are not tested either. The permissions
for some of the operations are hardcoded for the test and there is no
failure check when the permission is not set yet.
2023-10-21 16:28:30 +02:00
$this -> status = self :: STATUS_DRAFT ;
2020-10-28 17:49:52 +01:00
$this -> db -> commit ();
return 1 ;
} else {
$this -> db -> rollback ();
return - 1 ;
}
} else {
$this -> error = $this -> db -> error ();
$this -> db -> rollback ();
return - 1 ;
}
}
2018-10-03 12:22:41 +02:00
/**
* Create a document onto disk according to template module .
*
* @ param string $modele Force the model to using ( '' to not force )
* @ param Translate $outputlangs object lang to use for translations
* @ param int $hidedetails Hide details of lines
* @ param int $hidedesc Hide description
* @ param int $hideref Hide ref
* @ return int 0 if KO , 1 if OK
*/
2019-01-27 15:20:16 +01:00
public function generateDocument ( $modele , $outputlangs , $hidedetails = 0 , $hidedesc = 0 , $hideref = 0 )
2018-10-03 12:22:41 +02:00
{
2019-11-13 18:32:11 +01:00
global $conf , $langs ;
2018-10-03 12:22:41 +02:00
$langs -> load ( " receptions " );
2021-02-26 20:53:03 +01:00
if ( ! dol_strlen ( $modele )) {
2018-10-08 16:54:33 +02:00
$modele = 'squille' ;
2018-10-03 12:22:41 +02:00
2020-09-10 01:49:09 +02:00
if ( $this -> model_pdf ) {
$modele = $this -> model_pdf ;
2023-11-27 11:56:32 +01:00
} elseif ( getDolGlobalString ( 'RECEPTION_ADDON_PDF' )) {
2024-01-05 04:18:53 +01:00
$modele = getDolGlobalString ( 'RECEPTION_ADDON_PDF' );
2018-10-03 12:22:41 +02:00
}
}
$modelpath = " core/modules/reception/doc/ " ;
$this -> fetch_origin ();
2018-12-15 13:58:39 +01:00
2018-10-03 12:22:41 +02:00
return $this -> commonGenerateDocument ( $modelpath , $modele , $outputlangs , $hidedetails , $hidedesc , $hideref );
}
/**
* Function used to replace a thirdparty id with another one .
*
2022-12-28 13:27:13 +01:00
* @ param DoliDB $dbs Database handler , because function is static we name it $dbs not $db to avoid breaking coding test
* @ param int $origin_id Old thirdparty id
* @ param int $dest_id New thirdparty id
* @ return bool
2018-10-03 12:22:41 +02:00
*/
2022-12-28 13:27:13 +01:00
public static function replaceThirdparty ( DoliDB $dbs , $origin_id , $dest_id )
2018-10-03 12:22:41 +02:00
{
2018-12-15 15:43:30 +01:00
$tables = array ( 'reception' );
2018-10-03 12:22:41 +02:00
2022-12-28 13:27:13 +01:00
return CommonObject :: commonReplaceThirdparty ( $dbs , $origin_id , $dest_id , $tables );
2018-10-03 12:22:41 +02:00
}
2021-11-23 22:02:55 +01:00
/**
* Function used to replace a product id with another one .
*
2022-12-28 13:27:13 +01:00
* @ param DoliDB $dbs Database handler , because function is static we name it $dbs not $db to avoid breaking coding test
* @ param int $origin_id Old thirdparty id
* @ param int $dest_id New thirdparty id
* @ return bool
2021-11-23 22:02:55 +01:00
*/
2022-12-28 13:27:13 +01:00
public static function replaceProduct ( DoliDB $dbs , $origin_id , $dest_id )
2021-11-23 22:02:55 +01:00
{
$tables = array (
2024-01-15 09:40:59 +01:00
'receptiondet_batch'
2021-11-23 22:02:55 +01:00
);
2022-12-28 13:27:13 +01:00
return CommonObject :: commonReplaceProduct ( $dbs , $origin_id , $dest_id , $tables );
2021-11-23 22:02:55 +01:00
}
2019-02-03 15:21:21 +01:00
}