2010-04-25 16:17:39 +02:00
< ? php
2022-01-27 02:27:36 +01:00
/* Copyright ( C ) 2002 - 2007 Rodolphe Quiedeville < rodolphe @ quiedeville . org >
* Copyright ( C ) 2004 - 2013 Laurent Destailleur < eldy @ users . sourceforge . net >
* Copyright ( C ) 2004 Sebastien Di Cintio < sdicintio @ ressource - toi . org >
* Copyright ( C ) 2004 Benoit Mortier < benoit . mortier @ opensides . be >
* Copyright ( C ) 2005 Marc Barilley / Ocebo < marc @ ocebo . com >
* Copyright ( C ) 2005 - 2014 Regis Houssin < regis . houssin @ inodbox . com >
* Copyright ( C ) 2006 Andre Cianfarani < acianfa @ free . fr >
* Copyright ( C ) 2007 Franky Van Liedekerke < franky . van . liedekerke @ telenet . be >
* Copyright ( C ) 2010 - 2020 Juanjo Menent < jmenent @ 2 byte . es >
* Copyright ( C ) 2012 - 2014 Christophe Battarel < christophe . battarel @ altairis . fr >
* Copyright ( C ) 2012 - 2015 Marcos García < marcosgdf @ gmail . com >
* Copyright ( C ) 2012 Cédric Salvador < csalvador @ gpcsolutions . fr >
* Copyright ( C ) 2012 - 2014 Raphaël Doursenaud < rdoursenaud @ gpcsolutions . fr >
* Copyright ( C ) 2013 Cedric Gross < c . gross @ kreiz - it . fr >
* Copyright ( C ) 2013 Florian Henry < florian . henry @ open - concept . pro >
2022-03-22 13:46:55 +01:00
* Copyright ( C ) 2016 - 2022 Ferran Marcet < fmarcet @ 2 byte . es >
2022-09-04 04:59:31 +02:00
* Copyright ( C ) 2018 - 2022 Alexandre Spangaro < aspangaro @ open - dsi . fr >
2022-01-27 02:27:36 +01:00
* Copyright ( C ) 2018 Nicolas ZABOURI < info @ inovea - conseil . com >
* Copyright ( C ) 2022 Sylvain Legrand < contact @ infras . fr >
2022-03-10 10:02:57 +01:00
* Copyright ( C ) 2022 Gauthier VERDOL < gauthier . verdol @ atm - consulting . fr >
2013-11-04 16:31:12 +01:00
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 3 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
2019-09-23 21:55:30 +02:00
* along with this program . If not , see < https :// www . gnu . org / licenses />.
2013-11-04 16:31:12 +01:00
*/
2010-04-25 16:17:39 +02:00
/**
2018-07-06 08:07:38 +02:00
* \file htdocs / compta / facture / class / facture . class . php
* \ingroup facture
* \brief File of class to manage invoices
2013-11-04 16:31:12 +01:00
*/
2018-07-06 08:07:38 +02:00
include_once DOL_DOCUMENT_ROOT . '/core/class/commoninvoice.class.php' ;
require_once DOL_DOCUMENT_ROOT . '/core/class/commonobjectline.class.php' ;
require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php' ;
require_once DOL_DOCUMENT_ROOT . '/societe/class/client.class.php' ;
require_once DOL_DOCUMENT_ROOT . '/margin/lib/margins.lib.php' ;
require_once DOL_DOCUMENT_ROOT . '/multicurrency/class/multicurrency.class.php' ;
2022-08-29 11:24:07 +02:00
if ( isModEnabled ( 'accounting' )) {
2021-02-23 21:09:01 +01:00
require_once DOL_DOCUMENT_ROOT . '/core/class/html.formaccounting.class.php' ;
}
2022-08-29 11:24:07 +02:00
if ( isModEnabled ( 'accounting' )) {
2021-02-23 21:09:01 +01:00
require_once DOL_DOCUMENT_ROOT . '/accountancy/class/accountingaccount.class.php' ;
}
2018-03-08 06:52:31 +01:00
2013-04-18 08:40:29 +02:00
/**
2018-07-06 08:07:38 +02:00
* Class to manage invoices
2010-04-25 16:17:39 +02:00
*/
2018-07-06 08:07:38 +02:00
class Facture extends CommonInvoice
2018-07-05 19:00:41 +02:00
{
2018-08-23 17:07:27 +02:00
/**
* @ var string ID to identify managed object
*/
2019-11-08 10:53:31 +01:00
public $element = 'facture' ;
2018-09-02 21:08:57 +02:00
2018-08-22 18:34:50 +02:00
/**
* @ var string Name of table without prefix where object is stored
*/
2019-11-08 10:53:31 +01:00
public $table_element = 'facture' ;
2018-09-02 21:08:57 +02:00
2018-09-02 11:08:41 +02:00
/**
2020-12-05 23:53:55 +01:00
* @ var string Name of subtable line
2018-09-02 11:08:41 +02:00
*/
2018-07-06 08:07:38 +02:00
public $table_element_line = 'facturedet' ;
2018-09-01 15:13:59 +02:00
/**
2020-12-05 23:53:55 +01:00
* @ var string Fieldname with ID of parent key if this field has a parent
2018-09-01 15:13:59 +02:00
*/
2018-07-06 08:07:38 +02:00
public $fk_element = 'fk_facture' ;
2018-09-01 15:13:59 +02:00
2018-09-05 10:31:12 +02:00
/**
2020-11-29 15:16:53 +01:00
* @ var string String with name of icon for myobject .
2018-09-05 10:31:12 +02:00
*/
2019-11-08 10:53:31 +01:00
public $picto = 'bill' ;
2018-09-02 11:08:41 +02:00
2018-07-06 08:07:38 +02:00
/**
* 0 = No test on entity , 1 = Test with field entity , 2 = Test with link by societe
* @ var int
*/
public $ismultientitymanaged = 1 ;
2018-09-02 11:08:41 +02:00
2018-07-06 08:07:38 +02:00
/**
* 0 = Default , 1 = View may be restricted to sales representative only if no permission to see all or to company of external user if external user
* @ var integer
*/
public $restrictiononfksoc = 1 ;
/**
* { @ inheritdoc }
*/
2018-12-02 14:31:45 +01:00
protected $table_ref_field = 'ref' ;
2018-07-06 08:07:38 +02:00
2021-03-08 09:14:23 +01:00
/**
* @ var int 1 if status is draft
* @ deprecated
*/
public $brouillon ;
2020-10-31 13:27:29 +01:00
/**
* @ var int thirdparty ID
*/
2018-07-06 08:07:38 +02:00
public $socid ;
public $author ;
2018-10-09 15:38:42 +02:00
/**
2020-09-08 21:27:28 +02:00
* @ var int ID
*/
2018-07-06 08:07:38 +02:00
public $fk_user_author ;
2018-10-09 15:38:42 +02:00
/**
2020-09-08 21:27:28 +02:00
* @ var int ID
*/
2018-07-06 08:07:38 +02:00
public $fk_user_valid ;
2018-10-09 15:38:42 +02:00
2022-06-27 10:45:04 +02:00
/**
* @ var int ID
*/
public $fk_user_modif ;
2019-11-08 10:53:31 +01:00
public $date ; // Date invoice
2018-07-06 08:07:38 +02:00
public $datem ;
2020-10-31 13:27:29 +01:00
2020-11-11 18:08:40 +01:00
/**
* @ var int Date expected for delivery
* @ deprecated
2022-09-21 09:42:44 +02:00
* @ see delivery_date
2020-11-11 18:08:40 +01:00
*/
2022-09-21 09:42:44 +02:00
public $date_livraison ;
2020-11-11 18:08:40 +01:00
2022-09-21 09:42:44 +02:00
/**
* @ var int Date expected for delivery
*/
2020-11-11 18:08:40 +01:00
public $delivery_date ; // Date expected of shipment (date starting shipment, not the reception that occurs some days after)
2022-09-21 09:42:44 +02:00
/**
* @ var string customer ref
* @ deprecated
* @ see ref_customer
*/
public $ref_client ;
2020-10-31 13:27:29 +01:00
/**
* @ var string customer ref
*/
2022-09-07 12:45:43 +02:00
public $ref_customer ;
2020-03-06 14:38:06 +01:00
/**
* @ var int Ref Int
* @ deprecated
*/
2022-09-21 09:42:44 +02:00
public $ref_int ;
2020-03-06 14:38:06 +01:00
2018-07-06 08:07:38 +02:00
//Check constants for types
public $type = self :: TYPE_STANDARD ;
2021-12-19 20:43:24 +01:00
// Warning: Do not set default value into property defintion. it must stay null.
// For example to avoid to have substition done when object is generic and not yet defined.
2018-07-06 08:07:38 +02:00
public $remise_absolue ;
public $remise_percent ;
2021-12-19 20:43:24 +01:00
public $total_ht ;
public $total_tva ;
public $total_localtax1 ;
public $total_localtax2 ;
public $total_ttc ;
2018-07-06 08:07:38 +02:00
public $revenuestamp ;
2021-04-06 09:15:34 +02:00
/**
2022-07-05 20:59:42 +02:00
* ! Closing after partial payment : discount_vat , badcustomer or badsupplier , bankcharge , other
2021-04-06 09:15:34 +02:00
* ! Closing when no payment : replaced , abandoned
* @ var string Close code
*/
2018-07-06 08:07:38 +02:00
public $close_code ;
2021-04-06 09:15:34 +02:00
/**
* ! Comment if paid without full payment
* @ var string Close note
*/
2018-07-06 08:07:38 +02:00
public $close_note ;
2020-11-06 11:52:48 +01:00
/**
* 1 if invoice paid COMPLETELY , 0 otherwise ( do not use it anymore , use statut and close_code )
*/
2018-07-06 08:07:38 +02:00
public $paye ;
2020-11-06 11:52:48 +01:00
2018-10-07 13:59:40 +02:00
//! key of module source when invoice generated from a dedicated module ('cashdesk', 'takepos', ...)
public $module_source ;
2018-10-08 22:28:30 +02:00
//! key of pos source ('0', '1', ...)
public $pos_source ;
2018-10-07 13:59:40 +02:00
//! id of template invoice when generated from a template invoice
public $fk_fac_rec_source ;
2018-07-06 08:07:38 +02:00
//! id of source invoice if replacement invoice or credit note
public $fk_facture_source ;
2019-11-08 10:53:31 +01:00
public $linked_objects = array ();
2021-03-08 09:16:33 +01:00
2018-07-06 08:07:38 +02:00
public $date_lim_reglement ;
2019-11-08 10:53:31 +01:00
public $cond_reglement_code ; // Code in llx_c_paiement
public $mode_reglement_code ; // Code in llx_c_paiement
2018-10-09 15:38:42 +02:00
/**
2020-09-08 21:27:28 +02:00
* @ var int ID Field to store bank id to use when payment mode is withdraw
*/
2018-10-09 15:38:42 +02:00
public $fk_bank ;
2018-09-02 11:08:41 +02:00
2018-07-06 08:07:38 +02:00
/**
* @ var FactureLigne []
*/
2019-11-08 10:53:31 +01:00
public $lines = array ();
2018-09-02 11:08:41 +02:00
2018-07-06 08:07:38 +02:00
public $line ;
2019-11-08 10:53:31 +01:00
public $extraparams = array ();
2018-07-06 08:07:38 +02:00
public $fac_rec ;
2020-12-13 13:34:21 +01:00
public $date_pointoftax ;
2018-07-06 08:07:38 +02:00
// Multicurrency
2018-10-09 15:38:42 +02:00
/**
2020-09-08 21:27:28 +02:00
* @ var int ID
*/
2018-07-06 08:07:38 +02:00
public $fk_multicurrency ;
2018-10-09 15:38:42 +02:00
2018-07-06 08:07:38 +02:00
public $multicurrency_code ;
public $multicurrency_tx ;
public $multicurrency_total_ht ;
public $multicurrency_total_tva ;
public $multicurrency_total_ttc ;
/**
* @ var int Situation cycle reference number
*/
public $situation_cycle_ref ;
/**
* @ var int Situation counter inside the cycle
*/
public $situation_counter ;
/**
* @ var int Final situation flag
*/
public $situation_final ;
/**
* @ var array Table of previous situations
*/
2019-11-08 10:53:31 +01:00
public $tab_previous_situation_invoice = array ();
2018-07-06 08:07:38 +02:00
/**
* @ var array Table of next situations
*/
2019-11-08 10:53:31 +01:00
public $tab_next_situation_invoice = array ();
2018-07-06 08:07:38 +02:00
public $oldcopy ;
2016-07-08 21:28:21 +02:00
2019-06-26 09:43:43 +02:00
/**
* @ var double percentage of retainage
*/
2018-08-08 17:36:39 +02:00
public $retained_warranty ;
2019-09-03 16:23:39 +02:00
2019-06-26 09:43:43 +02:00
/**
* @ var int timestamp of date limit of retainage
*/
2018-08-08 17:36:39 +02:00
public $retained_warranty_date_limit ;
2019-09-03 16:23:39 +02:00
2019-06-26 09:43:43 +02:00
/**
* @ var int Code in llx_c_paiement
*/
2018-08-10 15:06:00 +02:00
public $retained_warranty_fk_cond_reglement ;
2016-07-08 21:28:21 +02:00
2020-01-29 22:38:14 +01:00
/**
* 'type' if the field format ( 'integer' , 'integer:ObjectClass:PathToClass[:AddCreateButtonOrNot[:Filter]]' , 'varchar(x)' , 'double(24,8)' , 'real' , 'price' , 'text' , 'html' , 'date' , 'datetime' , 'timestamp' , 'duration' , 'mail' , 'phone' , 'url' , 'password' )
* Note : Filter can be a string like " (t.ref:like:'SO-%') or (t.date_creation:<:'20160101') or (t.nature:is:NULL) "
* 'label' the translation key .
* 'enabled' is a condition when the field must be managed .
* 'position' is the sort order of field .
* 'notnull' is set to 1 if not null in database . Set to - 1 if we must set data to null if empty ( '' or 0 ) .
* 'visible' says if field is visible in list ( Examples : 0 = Not visible , 1 = Visible on list and create / update / view forms , 2 = Visible on list only , 3 = Visible on create / update / view form only ( not list ), 4 = Visible on list and update / view form only ( not create ) . 5 = Visible on list and view only ( not create / not update ) . Using a negative value means field is not shown by default on list but can be selected for viewing )
* 'noteditable' says if field is not editable ( 1 or 0 )
* 'default' is a default value for creation ( can still be overwrote by the Setup of Default Values if field is editable in creation form ) . Note : If default is set to '(PROV)' and field is 'ref' , the default value will be set to '(PROVid)' where id is rowid when a new record is created .
* 'index' if we want an index in database .
* 'foreignkey' => 'tablename.field' if the field is a foreign key ( it is recommanded to name the field fk_ ... ) .
* 'searchall' is 1 if we want to search in this field when making a search from the quick search button .
* 'isameasure' must be set to 1 if you want to have a total on list for this field . Field type must be summable like integer or double ( 24 , 8 ) .
* 'css' is the CSS style to use on field . For example : 'maxwidth200'
* 'help' is a string visible as a tooltip on field
* 'showoncombobox' if value of the field must be visible into the label of the combobox that list record
* 'disabled' is 1 if we want to have the field locked by a 'disabled' attribute . In most cases , this is never set into the definition of $fields into class , but is set dynamically by some part of code .
2021-04-29 12:10:55 +02:00
* 'arrayofkeyval' to set list of value if type is a list of predefined values . For example : array ( " 0 " => " Draft " , " 1 " => " Active " , " -1 " => " Cancel " )
2020-01-29 22:38:14 +01:00
* 'comment' is not used . You can store here any text of your choice . It is not used by application .
*
* Note : To have value dynamic , you can set value to 0 in definition and edit the value on the fly into the constructor .
*/
// BEGIN MODULEBUILDER PROPERTIES
/**
* @ var array Array with all fields and their property . Do not use it as a static var . It may be modified by constructor .
*/
2020-02-13 12:36:05 +01:00
public $fields = array (
2021-03-28 19:15:59 +02:00
'rowid' => array ( 'type' => 'integer' , 'label' => 'TechnicalID' , 'enabled' => 1 , 'visible' =>- 1 , 'notnull' => 1 , 'position' => 1 ),
'ref' => array ( 'type' => 'varchar(30)' , 'label' => 'Ref' , 'enabled' => 1 , 'visible' => 1 , 'notnull' => 1 , 'showoncombobox' => 1 , 'position' => 5 ),
2020-01-29 22:38:14 +01:00
'entity' => array ( 'type' => 'integer' , 'label' => 'Entity' , 'default' => 1 , 'enabled' => 1 , 'visible' =>- 2 , 'notnull' => 1 , 'position' => 20 , 'index' => 1 ),
2021-08-20 21:42:43 +02:00
'ref_client' => array ( 'type' => 'varchar(255)' , 'label' => 'RefCustomer' , 'enabled' => 1 , 'visible' =>- 1 , 'position' => 10 ),
2021-03-28 19:15:59 +02:00
'ref_ext' => array ( 'type' => 'varchar(255)' , 'label' => 'Ref ext' , 'enabled' => 1 , 'visible' => 0 , 'position' => 12 ),
//'ref_int' =>array('type'=>'varchar(255)', 'label'=>'Ref int', 'enabled'=>1, 'visible'=>0, 'position'=>30), // deprecated
'type' => array ( 'type' => 'smallint(6)' , 'label' => 'Type' , 'enabled' => 1 , 'visible' =>- 1 , 'notnull' => 1 , 'position' => 15 ),
2020-03-08 19:25:00 +01:00
//'increment' =>array('type'=>'varchar(10)', 'label'=>'Increment', 'enabled'=>1, 'visible'=>-1, 'position'=>45),
2020-01-29 22:38:14 +01:00
'fk_soc' => array ( 'type' => 'integer:Societe:societe/class/societe.class.php' , 'label' => 'ThirdParty' , 'enabled' => 1 , 'visible' =>- 1 , 'notnull' => 1 , 'position' => 50 ),
2021-03-31 18:39:59 +02:00
'datef' => array ( 'type' => 'date' , 'label' => 'DateInvoice' , 'enabled' => 1 , 'visible' => 1 , 'position' => 20 ),
2021-03-28 19:15:59 +02:00
'date_valid' => array ( 'type' => 'date' , 'label' => 'DateValidation' , 'enabled' => 1 , 'visible' =>- 1 , 'position' => 22 ),
2021-05-18 18:18:00 +02:00
'date_lim_reglement' => array ( 'type' => 'date' , 'label' => 'DateDue' , 'enabled' => 1 , 'visible' => 1 , 'position' => 25 ),
2021-03-28 19:15:59 +02:00
'date_closing' => array ( 'type' => 'datetime' , 'label' => 'Date closing' , 'enabled' => 1 , 'visible' =>- 1 , 'position' => 30 ),
2020-01-31 15:12:17 +01:00
'paye' => array ( 'type' => 'smallint(6)' , 'label' => 'InvoicePaidCompletely' , 'enabled' => 1 , 'visible' =>- 1 , 'notnull' => 1 , 'position' => 80 ),
//'amount' =>array('type'=>'double(24,8)', 'label'=>'Amount', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>85),
2020-03-08 19:25:00 +01:00
'remise_percent' => array ( 'type' => 'double' , 'label' => 'RelativeDiscount' , 'enabled' => 1 , 'visible' =>- 1 , 'position' => 90 ),
2021-03-28 19:15:59 +02:00
'remise_absolue' => array ( 'type' => 'double' , 'label' => 'CustomerRelativeDiscount' , 'enabled' => 1 , 'visible' =>- 1 , 'position' => 91 ),
2020-03-08 19:25:00 +01:00
//'remise' =>array('type'=>'double', 'label'=>'Remise', 'enabled'=>1, 'visible'=>-1, 'position'=>100),
2021-03-28 19:15:59 +02:00
'close_code' => array ( 'type' => 'varchar(16)' , 'label' => 'EarlyClosingReason' , 'enabled' => 1 , 'visible' =>- 1 , 'position' => 92 ),
'close_note' => array ( 'type' => 'varchar(128)' , 'label' => 'EarlyClosingComment' , 'enabled' => 1 , 'visible' =>- 1 , 'position' => 93 ),
2021-05-18 18:18:00 +02:00
'total_ht' => array ( 'type' => 'double(24,8)' , 'label' => 'AmountHT' , 'enabled' => 1 , 'visible' => 1 , 'position' => 95 , 'isameasure' => 1 ),
2021-03-29 20:35:35 +02:00
'total_tva' => array ( 'type' => 'double(24,8)' , 'label' => 'AmountVAT' , 'enabled' => 1 , 'visible' =>- 1 , 'position' => 100 , 'isameasure' => 1 ),
2021-03-28 19:15:59 +02:00
'localtax1' => array ( 'type' => 'double(24,8)' , 'label' => 'LT1' , 'enabled' => 1 , 'visible' =>- 1 , 'position' => 110 , 'isameasure' => 1 ),
'localtax2' => array ( 'type' => 'double(24,8)' , 'label' => 'LT2' , 'enabled' => 1 , 'visible' =>- 1 , 'position' => 120 , 'isameasure' => 1 ),
'revenuestamp' => array ( 'type' => 'double(24,8)' , 'label' => 'RevenueStamp' , 'enabled' => 1 , 'visible' =>- 1 , 'position' => 115 , 'isameasure' => 1 ),
'total_ttc' => array ( 'type' => 'double(24,8)' , 'label' => 'AmountTTC' , 'enabled' => 1 , 'visible' => 1 , 'position' => 130 , 'isameasure' => 1 ),
'fk_user_author' => array ( 'type' => 'integer:User:user/class/user.class.php' , 'label' => 'UserAuthor' , 'enabled' => 1 , 'visible' =>- 1 , 'position' => 165 ),
'fk_user_modif' => array ( 'type' => 'integer:User:user/class/user.class.php' , 'label' => 'UserModif' , 'enabled' => 1 , 'visible' =>- 2 , 'notnull' =>- 1 , 'position' => 166 ),
'fk_user_valid' => array ( 'type' => 'integer:User:user/class/user.class.php' , 'label' => 'UserValidation' , 'enabled' => 1 , 'visible' =>- 1 , 'position' => 167 ),
'fk_user_closing' => array ( 'type' => 'integer:User:user/class/user.class.php' , 'label' => 'UserClosing' , 'enabled' => 1 , 'visible' =>- 1 , 'position' => 168 ),
2020-01-31 15:12:17 +01:00
'fk_facture_source' => array ( 'type' => 'integer' , 'label' => 'SourceInvoice' , 'enabled' => 1 , 'visible' =>- 1 , 'position' => 170 ),
'fk_projet' => array ( 'type' => 'integer:Project:projet/class/project.class.php:1:fk_statut=1' , 'label' => 'Project' , 'enabled' => 1 , 'visible' =>- 1 , 'position' => 175 ),
2020-01-29 22:38:14 +01:00
'fk_account' => array ( 'type' => 'integer' , 'label' => 'Fk account' , 'enabled' => 1 , 'visible' =>- 1 , 'position' => 180 ),
2020-01-31 15:12:17 +01:00
'fk_currency' => array ( 'type' => 'varchar(3)' , 'label' => 'CurrencyCode' , 'enabled' => 1 , 'visible' =>- 1 , 'position' => 185 ),
'fk_cond_reglement' => array ( 'type' => 'integer' , 'label' => 'PaymentTerm' , 'enabled' => 1 , 'visible' =>- 1 , 'notnull' => 1 , 'position' => 190 ),
'fk_mode_reglement' => array ( 'type' => 'integer' , 'label' => 'PaymentMode' , 'enabled' => 1 , 'visible' =>- 1 , 'position' => 195 ),
2022-09-06 05:30:35 +02:00
'note_private' => array ( 'type' => 'text' , 'label' => 'NotePrivate' , 'enabled' => 1 , 'visible' => 0 , 'position' => 205 ),
'note_public' => array ( 'type' => 'text' , 'label' => 'NotePublic' , 'enabled' => 1 , 'visible' => 0 , 'position' => 210 ),
2020-01-29 22:38:14 +01:00
'model_pdf' => array ( 'type' => 'varchar(255)' , 'label' => 'Model pdf' , 'enabled' => 1 , 'visible' => 0 , 'position' => 215 ),
'extraparams' => array ( 'type' => 'varchar(255)' , 'label' => 'Extraparams' , 'enabled' => 1 , 'visible' =>- 1 , 'position' => 225 ),
2020-01-31 15:12:17 +01:00
'situation_cycle_ref' => array ( 'type' => 'smallint(6)' , 'label' => 'Situation cycle ref' , 'enabled' => '$conf->global->INVOICE_USE_SITUATION' , 'visible' =>- 1 , 'position' => 230 ),
'situation_counter' => array ( 'type' => 'smallint(6)' , 'label' => 'Situation counter' , 'enabled' => '$conf->global->INVOICE_USE_SITUATION' , 'visible' =>- 1 , 'position' => 235 ),
'situation_final' => array ( 'type' => 'smallint(6)' , 'label' => 'Situation final' , 'enabled' => 'empty($conf->global->INVOICE_USE_SITUATION) ? 0 : 1' , 'visible' =>- 1 , 'position' => 240 ),
2020-02-19 11:54:55 +01:00
'retained_warranty' => array ( 'type' => 'double' , 'label' => 'Retained warranty' , 'enabled' => '$conf->global->INVOICE_USE_RETAINED_WARRANTY' , 'visible' =>- 1 , 'position' => 245 ),
'retained_warranty_date_limit' => array ( 'type' => 'date' , 'label' => 'Retained warranty date limit' , 'enabled' => '$conf->global->INVOICE_USE_RETAINED_WARRANTY' , 'visible' =>- 1 , 'position' => 250 ),
'retained_warranty_fk_cond_reglement' => array ( 'type' => 'integer' , 'label' => 'Retained warranty fk cond reglement' , 'enabled' => '$conf->global->INVOICE_USE_RETAINED_WARRANTY' , 'visible' =>- 1 , 'position' => 255 ),
2020-03-08 19:25:00 +01:00
'fk_incoterms' => array ( 'type' => 'integer' , 'label' => 'IncotermCode' , 'enabled' => '$conf->incoterm->enabled' , 'visible' =>- 1 , 'position' => 260 ),
'location_incoterms' => array ( 'type' => 'varchar(255)' , 'label' => 'IncotermLabel' , 'enabled' => '$conf->incoterm->enabled' , 'visible' =>- 1 , 'position' => 265 ),
2020-01-31 15:12:17 +01:00
'date_pointoftax' => array ( 'type' => 'date' , 'label' => 'DatePointOfTax' , 'enabled' => '$conf->global->INVOICE_POINTOFTAX_DATE' , 'visible' =>- 1 , 'position' => 270 ),
'fk_multicurrency' => array ( 'type' => 'integer' , 'label' => 'MulticurrencyID' , 'enabled' => '$conf->multicurrency->enabled' , 'visible' =>- 1 , 'position' => 275 ),
2021-03-28 19:15:59 +02:00
'multicurrency_code' => array ( 'type' => 'varchar(255)' , 'label' => 'Currency' , 'enabled' => '$conf->multicurrency->enabled' , 'visible' =>- 1 , 'position' => 280 ),
'multicurrency_tx' => array ( 'type' => 'double(24,8)' , 'label' => 'CurrencyRate' , 'enabled' => '$conf->multicurrency->enabled' , 'visible' =>- 1 , 'position' => 285 , 'isameasure' => 1 ),
2020-03-08 20:10:31 +01:00
'multicurrency_total_ht' => array ( 'type' => 'double(24,8)' , 'label' => 'MulticurrencyAmountHT' , 'enabled' => '$conf->multicurrency->enabled' , 'visible' =>- 1 , 'position' => 290 , 'isameasure' => 1 ),
2021-08-24 14:27:18 +02:00
'multicurrency_total_tva' => array ( 'type' => 'double(24,8)' , 'label' => 'MulticurrencyAmountVAT' , 'enabled' => '$conf->multicurrency->enabled' , 'visible' =>- 1 , 'position' => 291 , 'isameasure' => 1 ),
'multicurrency_total_ttc' => array ( 'type' => 'double(24,8)' , 'label' => 'MulticurrencyAmountTTC' , 'enabled' => '$conf->multicurrency->enabled' , 'visible' =>- 1 , 'position' => 292 , 'isameasure' => 1 ),
2020-01-31 15:12:17 +01:00
'fk_fac_rec_source' => array ( 'type' => 'integer' , 'label' => 'RecurringInvoiceSource' , 'enabled' => 1 , 'visible' =>- 1 , 'position' => 305 ),
2020-03-08 19:25:00 +01:00
'last_main_doc' => array ( 'type' => 'varchar(255)' , 'label' => 'LastMainDoc' , 'enabled' => 1 , 'visible' =>- 1 , 'position' => 310 ),
2020-01-31 15:12:17 +01:00
'module_source' => array ( 'type' => 'varchar(32)' , 'label' => 'POSModule' , 'enabled' => 1 , 'visible' =>- 1 , 'position' => 315 ),
'pos_source' => array ( 'type' => 'varchar(32)' , 'label' => 'POSTerminal' , 'enabled' => 1 , 'visible' =>- 1 , 'position' => 320 ),
2021-03-28 19:15:59 +02:00
'datec' => array ( 'type' => 'datetime' , 'label' => 'DateCreation' , 'enabled' => 1 , 'visible' =>- 1 , 'position' => 500 ),
'tms' => array ( 'type' => 'timestamp' , 'label' => 'DateModificationShort' , 'enabled' => 1 , 'visible' =>- 1 , 'notnull' => 1 , 'position' => 500 ),
2020-03-08 19:25:00 +01:00
'import_key' => array ( 'type' => 'varchar(14)' , 'label' => 'ImportId' , 'enabled' => 1 , 'visible' =>- 2 , 'position' => 900 ),
2021-05-25 21:21:09 +02:00
'fk_statut' => array ( 'type' => 'smallint(6)' , 'label' => 'Status' , 'enabled' => 1 , 'visible' => 1 , 'notnull' => 1 , 'position' => 1000 , 'arrayofkeyval' => array ( 0 => 'Draft' , 1 => 'Validated' , 2 => 'Paid' , 3 => 'Abandonned' )),
2020-01-29 22:38:14 +01:00
);
// END MODULEBUILDER PROPERTIES
2020-09-08 21:27:28 +02:00
/**
* Standard invoice
*/
const TYPE_STANDARD = 0 ;
2014-02-25 00:46:04 +01:00
2020-09-08 21:27:28 +02:00
/**
* Replacement invoice
*/
const TYPE_REPLACEMENT = 1 ;
2014-02-25 00:46:04 +01:00
2020-09-08 21:27:28 +02:00
/**
* Credit note invoice
*/
const TYPE_CREDIT_NOTE = 2 ;
2014-02-25 00:46:04 +01:00
2020-09-08 21:27:28 +02:00
/**
* Deposit invoice
*/
const TYPE_DEPOSIT = 3 ;
2014-02-25 00:46:04 +01:00
2020-09-08 21:27:28 +02:00
/**
* Proforma invoice ( should not be used . a proforma is an order )
*/
const TYPE_PROFORMA = 4 ;
2013-04-18 08:40:29 +02:00
2018-07-06 08:07:38 +02:00
/**
* Situation invoice
*/
const TYPE_SITUATION = 5 ;
/**
2018-10-04 09:33:30 +02:00
* Draft status
2018-07-06 08:07:38 +02:00
*/
const STATUS_DRAFT = 0 ;
/**
* Validated ( need to be paid )
*/
const STATUS_VALIDATED = 1 ;
/**
* Classified paid .
* If paid partially , $this -> close_code can be :
* - CLOSECODE_DISCOUNTVAT
* - CLOSECODE_BADDEBT
2018-09-06 14:33:22 +02:00
* If paid completely , this -> close_code will be null
2018-07-06 08:07:38 +02:00
*/
const STATUS_CLOSED = 2 ;
/**
* Classified abandoned and no payment done .
* $this -> close_code can be :
* - CLOSECODE_BADDEBT
* - CLOSECODE_ABANDONED
* - CLOSECODE_REPLACED
*/
const STATUS_ABANDONED = 3 ;
2019-11-08 10:53:31 +01:00
const CLOSECODE_DISCOUNTVAT = 'discount_vat' ; // Abandonned remain - escompte
2022-07-05 20:59:42 +02:00
const CLOSECODE_BADDEBT = 'badcustomer' ; // Abandonned remain - bad customer
const CLOSECODE_BANKCHARGE = 'bankcharge' ; // Abandonned remain - bank charge
const CLOSECODE_OTHER = 'other' ; // Abandonned remain - other
2019-11-08 10:53:31 +01:00
const CLOSECODE_ABANDONED = 'abandon' ; // Abandonned - other
const CLOSECODE_REPLACED = 'replaced' ; // Closed after doing a replacement invoice
2018-07-06 08:07:38 +02:00
2020-01-29 22:38:14 +01:00
2018-07-06 08:07:38 +02:00
/**
* Constructor
*
* @ param DoliDB $db Database handler
*/
2022-05-18 11:00:43 +02:00
public function __construct ( DoliDB $db )
2018-07-06 08:07:38 +02:00
{
$this -> db = $db ;
}
/**
* Create invoice in database .
* Note : this -> ref can be set or empty . If empty , we will use " (PROV999) "
* Note : this -> fac_rec must be set to create invoice from a recurring invoice
*
* @ param User $user Object user that create
* @ param int $notrigger 1 = Does not execute triggers , 0 otherwise
2019-03-19 12:08:55 +01:00
* @ param int $forceduedate If set , do not recalculate due date from payment condition but force it with value
2018-07-06 08:07:38 +02:00
* @ return int < 0 if KO , > 0 if OK
*/
2020-09-08 21:27:28 +02:00
public function create ( User $user , $notrigger = 0 , $forceduedate = 0 )
2018-07-06 08:07:38 +02:00
{
2019-11-08 10:53:31 +01:00
global $langs , $conf , $mysoc , $hookmanager ;
$error = 0 ;
2018-07-06 08:07:38 +02:00
// Clean parameters
2021-02-23 21:09:01 +01:00
if ( empty ( $this -> type )) {
$this -> type = self :: TYPE_STANDARD ;
}
2019-11-08 10:53:31 +01:00
$this -> ref_client = trim ( $this -> ref_client );
$this -> note = ( isset ( $this -> note ) ? trim ( $this -> note ) : trim ( $this -> note_private )); // deprecated
$this -> note_private = ( isset ( $this -> note_private ) ? trim ( $this -> note_private ) : trim ( $this -> note_private ));
$this -> note_public = trim ( $this -> note_public );
2021-02-23 21:09:01 +01:00
if ( ! $this -> cond_reglement_id ) {
$this -> cond_reglement_id = 0 ;
}
if ( ! $this -> mode_reglement_id ) {
$this -> mode_reglement_id = 0 ;
}
2018-07-06 08:07:38 +02:00
$this -> brouillon = 1 ;
2021-03-08 09:14:23 +01:00
$this -> status = self :: STATUS_DRAFT ;
$this -> statut = self :: STATUS_DRAFT ;
2018-07-06 08:07:38 +02:00
2021-12-01 15:26:40 +01:00
if ( ! empty ( $this -> multicurrency_code )) {
// Multicurrency (test on $this->multicurrency_tx because we should take the default rate of multicurrency_code only if not using original rate)
if ( empty ( $this -> multicurrency_tx )) {
// If original rate is not set, we take a default value from date
list ( $this -> fk_multicurrency , $this -> multicurrency_tx ) = MultiCurrency :: getIdAndTxFromCode ( $this -> db , $this -> multicurrency_code , $this -> date );
} else {
// original rate multicurrency_tx and multicurrency_code are set, we use them
$this -> fk_multicurrency = MultiCurrency :: getIdFromCode ( $this -> db , $this -> multicurrency_code );
}
2021-02-23 21:09:01 +01:00
} else {
2021-12-01 15:26:40 +01:00
$this -> fk_multicurrency = 0 ;
2021-02-23 21:09:01 +01:00
}
if ( empty ( $this -> fk_multicurrency )) {
2018-07-06 08:07:38 +02:00
$this -> multicurrency_code = $conf -> currency ;
$this -> fk_multicurrency = 0 ;
$this -> multicurrency_tx = 1 ;
}
dol_syslog ( get_class ( $this ) . " ::create user= " . $user -> id . " date= " . $this -> date );
// Check parameters
2021-02-23 21:09:01 +01:00
if ( empty ( $this -> date )) {
2019-11-08 10:53:31 +01:00
$this -> error = " Try to create an invoice with an empty parameter (date) " ;
2018-07-06 08:07:38 +02:00
dol_syslog ( get_class ( $this ) . " ::create " . $this -> error , LOG_ERR );
return - 3 ;
}
$soc = new Societe ( $this -> db );
2019-11-08 10:53:31 +01:00
$result = $soc -> fetch ( $this -> socid );
2021-02-23 21:09:01 +01:00
if ( $result < 0 ) {
2019-11-08 10:53:31 +01:00
$this -> error = " Failed to fetch company: " . $soc -> error ;
2018-07-06 08:07:38 +02:00
dol_syslog ( get_class ( $this ) . " ::create " . $this -> error , LOG_ERR );
return - 2 ;
}
2019-11-08 10:53:31 +01:00
$now = dol_now ();
2018-07-06 08:07:38 +02:00
$this -> db -> begin ();
2019-11-08 10:53:31 +01:00
$originaldatewhen = null ;
$nextdatewhen = null ;
$previousdaynextdatewhen = null ;
2018-07-06 08:07:38 +02:00
2020-10-04 19:09:25 +02:00
// Create invoice from a template recurring invoice
2021-02-23 21:09:01 +01:00
if ( $this -> fac_rec > 0 ) {
2020-09-08 21:27:28 +02:00
$this -> fk_fac_rec_source = $this -> fac_rec ;
2018-07-06 08:07:38 +02:00
require_once DOL_DOCUMENT_ROOT . '/compta/facture/class/facture-rec.class.php' ;
$_facrec = new FactureRec ( $this -> db );
2019-11-08 10:53:31 +01:00
$result = $_facrec -> fetch ( $this -> fac_rec );
$result = $_facrec -> fetchObjectLinked ( null , '' , null , '' , 'OR' , 1 , 'sourcetype' , 0 ); // This load $_facrec->linkedObjectsIds
2018-07-06 08:07:38 +02:00
// Define some dates
$originaldatewhen = $_facrec -> date_when ;
2022-05-03 16:29:57 +02:00
$nextdatewhen = null ; $previousdaynextdatewhen = null ;
if ( $originaldatewhen ) {
$nextdatewhen = dol_time_plus_duree ( $originaldatewhen , $_facrec -> frequency , $_facrec -> unit_frequency );
$previousdaynextdatewhen = dol_time_plus_duree ( $nextdatewhen , - 1 , 'd' );
}
2018-07-06 08:07:38 +02:00
2021-02-23 21:09:01 +01:00
if ( ! empty ( $_facrec -> frequency )) { // Invoice are created on same thirdparty than template when there is a recurrence, but not necessarly when there is no recurrence.
2019-11-08 10:53:31 +01:00
$this -> socid = $_facrec -> socid ;
2019-11-05 15:46:48 +01:00
}
2018-07-06 08:07:38 +02:00
$this -> entity = $_facrec -> entity ; // Invoice created in same entity than template
// Fields coming from GUI (priority on template). TODO Value of template should be used as default value on GUI so we can use here always value from GUI
2019-01-27 11:55:16 +01:00
$this -> fk_project = GETPOST ( 'projectid' , 'int' ) > 0 ? (( int ) GETPOST ( 'projectid' , 'int' )) : $_facrec -> fk_project ;
2022-01-19 15:20:10 +01:00
$this -> note_public = GETPOSTISSET ( 'note_public' ) ? GETPOST ( 'note_public' , 'restricthtml' ) : $_facrec -> note_public ;
$this -> note_private = GETPOSTISSET ( 'note_private' ) ? GETPOST ( 'note_private' , 'restricthtml' ) : $_facrec -> note_private ;
$this -> model_pdf = GETPOSTISSET ( 'model' ) ? GETPOST ( 'model' , 'alpha' ) : $_facrec -> model_pdf ;
2019-01-27 11:55:16 +01:00
$this -> cond_reglement_id = GETPOST ( 'cond_reglement_id' , 'int' ) > 0 ? (( int ) GETPOST ( 'cond_reglement_id' , 'int' )) : $_facrec -> cond_reglement_id ;
$this -> mode_reglement_id = GETPOST ( 'mode_reglement_id' , 'int' ) > 0 ? (( int ) GETPOST ( 'mode_reglement_id' , 'int' )) : $_facrec -> mode_reglement_id ;
2018-07-06 08:07:38 +02:00
$this -> fk_account = GETPOST ( 'fk_account' ) > 0 ? (( int ) GETPOST ( 'fk_account' )) : $_facrec -> fk_account ;
// Set here to have this defined for substitution into notes, should be recalculated after adding lines to get same result
$this -> total_ht = $_facrec -> total_ht ;
$this -> total_ttc = $_facrec -> total_ttc ;
// Fields always coming from template
$this -> remise_absolue = $_facrec -> remise_absolue ;
$this -> remise_percent = $_facrec -> remise_percent ;
2019-11-08 10:53:31 +01:00
$this -> fk_incoterms = $_facrec -> fk_incoterms ;
$this -> location_incoterms = $_facrec -> location_incoterms ;
2018-07-06 08:07:38 +02:00
// Clean parameters
2021-02-23 21:09:01 +01:00
if ( ! $this -> type ) {
$this -> type = self :: TYPE_STANDARD ;
}
2019-11-08 10:53:31 +01:00
$this -> ref_client = trim ( $this -> ref_client );
$this -> note_public = trim ( $this -> note_public );
$this -> note_private = trim ( $this -> note_private );
2020-09-08 21:27:28 +02:00
$this -> note_private = dol_concatdesc ( $this -> note_private , $langs -> trans ( " GeneratedFromRecurringInvoice " , $_facrec -> ref ));
2018-07-06 08:07:38 +02:00
2020-09-08 21:27:28 +02:00
$this -> array_options = $_facrec -> array_options ;
2018-07-06 08:07:38 +02:00
2021-02-23 21:09:01 +01:00
if ( ! $this -> mode_reglement_id ) {
$this -> mode_reglement_id = 0 ;
}
2018-07-06 08:07:38 +02:00
$this -> brouillon = 1 ;
2021-03-08 09:14:23 +01:00
$this -> status = self :: STATUS_DRAFT ;
$this -> statut = self :: STATUS_DRAFT ;
2018-07-06 08:07:38 +02:00
$this -> linked_objects = $_facrec -> linkedObjectsIds ;
2019-06-05 08:08:31 +02:00
// We do not add link to template invoice or next invoice will be linked to all generated invoices
//$this->linked_objects['facturerec'][0] = $this->fac_rec;
2018-07-06 08:07:38 +02:00
$forceduedate = $this -> calculate_date_lim_reglement ();
// For recurring invoices, update date and number of last generation of recurring template invoice, before inserting new invoice
2021-02-23 21:09:01 +01:00
if ( $_facrec -> frequency > 0 ) {
2020-09-08 21:27:28 +02:00
dol_syslog ( " This is a recurring invoice so we set date_last_gen and next date_when " );
2021-02-23 21:09:01 +01:00
if ( empty ( $_facrec -> date_when )) {
$_facrec -> date_when = $now ;
}
2020-09-08 21:27:28 +02:00
$next_date = $_facrec -> getNextDate (); // Calculate next date
$result = $_facrec -> setValueFrom ( 'date_last_gen' , $now , '' , null , 'date' , '' , $user , '' );
//$_facrec->setValueFrom('nb_gen_done', $_facrec->nb_gen_done + 1); // Not required, +1 already included into setNextDate when second param is 1.
$result = $_facrec -> setNextDate ( $next_date , 1 );
2018-07-06 08:07:38 +02:00
}
// Define lang of customer
$outputlangs = $langs ;
2019-11-08 10:53:31 +01:00
$newlang = '' ;
2018-07-06 08:07:38 +02:00
2021-02-23 21:09:01 +01:00
if ( $conf -> global -> MAIN_MULTILANGS && empty ( $newlang ) && isset ( $this -> thirdparty -> default_lang )) {
$newlang = $this -> thirdparty -> default_lang ; // for proposal, order, invoice, ...
}
if ( $conf -> global -> MAIN_MULTILANGS && empty ( $newlang ) && isset ( $this -> default_lang )) {
$newlang = $this -> default_lang ; // for thirdparty
}
if ( ! empty ( $newlang )) {
2020-09-08 21:27:28 +02:00
$outputlangs = new Translate ( " " , $conf );
$outputlangs -> setDefaultLang ( $newlang );
2018-07-06 08:07:38 +02:00
}
// Array of possible substitutions (See also file mailing-send.php that should manage same substitutions)
2019-11-08 10:53:31 +01:00
$substitutionarray = getCommonSubstitutionArray ( $outputlangs , 0 , null , $this );
2018-07-06 08:07:38 +02:00
$substitutionarray [ '__INVOICE_PREVIOUS_MONTH__' ] = dol_print_date ( dol_time_plus_duree ( $this -> date , - 1 , 'm' ), '%m' );
$substitutionarray [ '__INVOICE_MONTH__' ] = dol_print_date ( $this -> date , '%m' );
$substitutionarray [ '__INVOICE_NEXT_MONTH__' ] = dol_print_date ( dol_time_plus_duree ( $this -> date , 1 , 'm' ), '%m' );
$substitutionarray [ '__INVOICE_PREVIOUS_MONTH_TEXT__' ] = dol_print_date ( dol_time_plus_duree ( $this -> date , - 1 , 'm' ), '%B' );
$substitutionarray [ '__INVOICE_MONTH_TEXT__' ] = dol_print_date ( $this -> date , '%B' );
$substitutionarray [ '__INVOICE_NEXT_MONTH_TEXT__' ] = dol_print_date ( dol_time_plus_duree ( $this -> date , 1 , 'm' ), '%B' );
$substitutionarray [ '__INVOICE_PREVIOUS_YEAR__' ] = dol_print_date ( dol_time_plus_duree ( $this -> date , - 1 , 'y' ), '%Y' );
$substitutionarray [ '__INVOICE_YEAR__' ] = dol_print_date ( $this -> date , '%Y' );
$substitutionarray [ '__INVOICE_NEXT_YEAR__' ] = dol_print_date ( dol_time_plus_duree ( $this -> date , 1 , 'y' ), '%Y' );
2020-01-23 20:59:18 +01:00
// Only for template invoice
2022-05-03 16:29:57 +02:00
$substitutionarray [ '__INVOICE_DATE_NEXT_INVOICE_BEFORE_GEN__' ] = ( isset ( $originaldatewhen ) ? dol_print_date ( $originaldatewhen , 'dayhour' ) : '' );
$substitutionarray [ '__INVOICE_DATE_NEXT_INVOICE_AFTER_GEN__' ] = ( isset ( $nextdatewhen ) ? dol_print_date ( $nextdatewhen , 'dayhour' ) : '' );
$substitutionarray [ '__INVOICE_PREVIOUS_DATE_NEXT_INVOICE_AFTER_GEN__' ] = ( isset ( $previousdaynextdatewhen ) ? dol_print_date ( $previousdaynextdatewhen , 'dayhour' ) : '' );
2020-01-23 20:59:18 +01:00
$substitutionarray [ '__INVOICE_COUNTER_CURRENT__' ] = $_facrec -> nb_gen_done ;
$substitutionarray [ '__INVOICE_COUNTER_MAX__' ] = $_facrec -> nb_gen_max ;
2018-07-06 08:07:38 +02:00
//var_dump($substitutionarray);exit;
complete_substitutions_array ( $substitutionarray , $outputlangs );
2019-11-08 10:53:31 +01:00
$this -> note_public = make_substitutions ( $this -> note_public , $substitutionarray );
$this -> note_private = make_substitutions ( $this -> note_private , $substitutionarray );
2018-07-06 08:07:38 +02:00
}
// Define due date if not already defined
2020-09-08 21:27:28 +02:00
if ( empty ( $forceduedate )) {
$duedate = $this -> calculate_date_lim_reglement ();
/* if ( $duedate < 0 ) { Regression , a date can be negative if before 1970.
2021-02-23 21:09:01 +01:00
dol_syslog ( __METHOD__ . ' Error in calculate_date_lim_reglement. We got ' . $duedate , LOG_ERR );
return - 1 ;
} */
2020-09-08 21:27:28 +02:00
$this -> date_lim_reglement = $duedate ;
} else {
$this -> date_lim_reglement = $forceduedate ;
}
2018-07-06 08:07:38 +02:00
// Insert into database
2019-11-08 10:53:31 +01:00
$socid = $this -> socid ;
2018-07-06 08:07:38 +02:00
$sql = " INSERT INTO " . MAIN_DB_PREFIX . " facture ( " ;
2019-11-08 10:53:31 +01:00
$sql .= " ref " ;
$sql .= " , entity " ;
$sql .= " , ref_ext " ;
$sql .= " , type " ;
$sql .= " , fk_soc " ;
$sql .= " , datec " ;
$sql .= " , remise_absolue " ;
$sql .= " , remise_percent " ;
$sql .= " , datef " ;
$sql .= " , date_pointoftax " ;
$sql .= " , note_private " ;
$sql .= " , note_public " ;
$sql .= " , ref_client, ref_int " ;
2020-09-08 21:27:28 +02:00
$sql .= " , fk_account " ;
2019-11-08 10:53:31 +01:00
$sql .= " , module_source, pos_source, fk_fac_rec_source, fk_facture_source, fk_user_author, fk_projet " ;
$sql .= " , fk_cond_reglement, fk_mode_reglement, date_lim_reglement, model_pdf " ;
$sql .= " , situation_cycle_ref, situation_counter, situation_final " ;
$sql .= " , fk_incoterms, location_incoterms " ;
2020-09-08 21:27:28 +02:00
$sql .= " , fk_multicurrency " ;
$sql .= " , multicurrency_code " ;
$sql .= " , multicurrency_tx " ;
$sql .= " , retained_warranty " ;
$sql .= " , retained_warranty_date_limit " ;
$sql .= " , retained_warranty_fk_cond_reglement " ;
2019-11-08 10:53:31 +01:00
$sql .= " ) " ;
$sql .= " VALUES ( " ;
$sql .= " '(PROV)' " ;
$sql .= " , " . setEntity ( $this );
$sql .= " , " . ( $this -> ref_ext ? " ' " . $this -> db -> escape ( $this -> ref_ext ) . " ' " : " null " );
$sql .= " , ' " . $this -> db -> escape ( $this -> type ) . " ' " ;
2020-09-19 23:30:29 +02:00
$sql .= " , " . (( int ) $socid );
2019-11-08 10:53:31 +01:00
$sql .= " , ' " . $this -> db -> idate ( $now ) . " ' " ;
$sql .= " , " . ( $this -> remise_absolue > 0 ? $this -> remise_absolue : 'NULL' );
$sql .= " , " . ( $this -> remise_percent > 0 ? $this -> remise_percent : 'NULL' );
$sql .= " , ' " . $this -> db -> idate ( $this -> date ) . " ' " ;
2020-11-09 15:18:56 +01:00
$sql .= " , " . ( empty ( $this -> date_pointoftax ) ? " null " : " ' " . $this -> db -> idate ( $this -> date_pointoftax ) . " ' " );
2019-11-08 10:53:31 +01:00
$sql .= " , " . ( $this -> note_private ? " ' " . $this -> db -> escape ( $this -> note_private ) . " ' " : " null " );
$sql .= " , " . ( $this -> note_public ? " ' " . $this -> db -> escape ( $this -> note_public ) . " ' " : " null " );
$sql .= " , " . ( $this -> ref_client ? " ' " . $this -> db -> escape ( $this -> ref_client ) . " ' " : " null " );
$sql .= " , " . ( $this -> ref_int ? " ' " . $this -> db -> escape ( $this -> ref_int ) . " ' " : " null " );
$sql .= " , " . ( $this -> fk_account > 0 ? $this -> fk_account : 'NULL' );
$sql .= " , " . ( $this -> module_source ? " ' " . $this -> db -> escape ( $this -> module_source ) . " ' " : " null " );
$sql .= " , " . ( $this -> pos_source != '' ? " ' " . $this -> db -> escape ( $this -> pos_source ) . " ' " : " null " );
$sql .= " , " . ( $this -> fk_fac_rec_source ? " ' " . $this -> db -> escape ( $this -> fk_fac_rec_source ) . " ' " : " null " );
$sql .= " , " . ( $this -> fk_facture_source ? " ' " . $this -> db -> escape ( $this -> fk_facture_source ) . " ' " : " null " );
2020-09-19 23:30:29 +02:00
$sql .= " , " . ( $user -> id > 0 ? ( int ) $user -> id : " null " );
2019-11-08 10:53:31 +01:00
$sql .= " , " . ( $this -> fk_project ? $this -> fk_project : " null " );
2021-09-03 18:00:28 +02:00
$sql .= " , " . (( int ) $this -> cond_reglement_id );
$sql .= " , " . (( int ) $this -> mode_reglement_id );
2020-11-08 00:18:41 +01:00
$sql .= " , ' " . $this -> db -> idate ( $this -> date_lim_reglement ) . " ' " ;
2020-12-13 13:34:21 +01:00
$sql .= " , " . ( isset ( $this -> model_pdf ) ? " ' " . $this -> db -> escape ( $this -> model_pdf ) . " ' " : " null " );
2019-11-08 10:53:31 +01:00
$sql .= " , " . ( $this -> situation_cycle_ref ? " ' " . $this -> db -> escape ( $this -> situation_cycle_ref ) . " ' " : " null " );
$sql .= " , " . ( $this -> situation_counter ? " ' " . $this -> db -> escape ( $this -> situation_counter ) . " ' " : " null " );
$sql .= " , " . ( $this -> situation_final ? $this -> situation_final : 0 );
$sql .= " , " . ( int ) $this -> fk_incoterms ;
2020-09-08 21:27:28 +02:00
$sql .= " , ' " . $this -> db -> escape ( $this -> location_incoterms ) . " ' " ;
2019-11-08 10:53:31 +01:00
$sql .= " , " . ( int ) $this -> fk_multicurrency ;
$sql .= " , ' " . $this -> db -> escape ( $this -> multicurrency_code ) . " ' " ;
$sql .= " , " . ( double ) $this -> multicurrency_tx ;
$sql .= " , " . ( empty ( $this -> retained_warranty ) ? " 0 " : $this -> db -> escape ( $this -> retained_warranty ));
$sql .= " , " . ( ! empty ( $this -> retained_warranty_date_limit ) ? " ' " . $this -> db -> idate ( $this -> retained_warranty_date_limit ) . " ' " : 'NULL' );
$sql .= " , " . ( int ) $this -> retained_warranty_fk_cond_reglement ;
$sql .= " ) " ;
$resql = $this -> db -> query ( $sql );
2021-02-23 21:09:01 +01:00
if ( $resql ) {
2018-07-06 08:07:38 +02:00
$this -> id = $this -> db -> last_insert_id ( MAIN_DB_PREFIX . 'facture' );
// Update ref with new one
2019-11-08 10:53:31 +01:00
$this -> ref = '(PROV' . $this -> id . ')' ;
2021-03-14 12:20:23 +01:00
$sql = 'UPDATE ' . MAIN_DB_PREFIX . " facture SET ref=' " . $this -> db -> escape ( $this -> ref ) . " ' WHERE rowid= " . (( int ) $this -> id );
2018-07-06 08:07:38 +02:00
2019-11-08 10:53:31 +01:00
$resql = $this -> db -> query ( $sql );
2021-02-23 21:09:01 +01:00
if ( ! $resql ) {
$error ++ ;
}
2018-07-06 08:07:38 +02:00
2021-02-23 21:09:01 +01:00
if ( ! empty ( $this -> linkedObjectsIds ) && empty ( $this -> linked_objects )) { // To use new linkedObjectsIds instead of old linked_objects
2019-11-08 10:53:31 +01:00
$this -> linked_objects = $this -> linkedObjectsIds ; // TODO Replace linked_objects with linkedObjectsIds
2018-07-06 08:07:38 +02:00
}
// Add object linked
2021-02-23 21:09:01 +01:00
if ( ! $error && $this -> id && ! empty ( $this -> linked_objects ) && is_array ( $this -> linked_objects )) {
foreach ( $this -> linked_objects as $origin => $tmp_origin_id ) {
if ( is_array ( $tmp_origin_id )) { // New behaviour, if linked_object can have several links per type, so is something like array('contract'=>array(id1, id2, ...))
foreach ( $tmp_origin_id as $origin_id ) {
2020-09-08 21:27:28 +02:00
$ret = $this -> add_object_linked ( $origin , $origin_id );
2021-02-23 21:09:01 +01:00
if ( ! $ret ) {
2020-09-08 21:27:28 +02:00
$this -> error = $this -> db -> lasterror ();
$error ++ ;
}
}
} else // Old behaviour, if linked_object has only one link per type, so is something like array('contract'=>id1))
{
$origin_id = $tmp_origin_id ;
$ret = $this -> add_object_linked ( $origin , $origin_id );
2021-02-23 21:09:01 +01:00
if ( ! $ret ) {
2020-09-08 21:27:28 +02:00
$this -> error = $this -> db -> lasterror ();
$error ++ ;
}
}
2018-07-06 08:07:38 +02:00
}
}
// Propagate contacts
2021-02-23 21:09:01 +01:00
if ( ! $error && $this -> id && ! empty ( $conf -> global -> MAIN_PROPAGATE_CONTACTS_FROM_ORIGIN ) && ! empty ( $this -> origin ) && ! empty ( $this -> origin_id )) { // Get contact from origin object
2018-07-06 08:07:38 +02:00
$originforcontact = $this -> origin ;
$originidforcontact = $this -> origin_id ;
2021-02-23 21:09:01 +01:00
if ( $originforcontact == 'shipping' ) { // shipment and order share the same contacts. If creating from shipment we take data of order
2020-09-08 21:27:28 +02:00
require_once DOL_DOCUMENT_ROOT . '/expedition/class/expedition.class.php' ;
$exp = new Expedition ( $this -> db );
$exp -> fetch ( $this -> origin_id );
$exp -> fetchObjectLinked ( null , '' , null , '' , 'OR' , 1 , 'sourcetype' , 0 );
2021-02-23 21:09:01 +01:00
if ( count ( $exp -> linkedObjectsIds [ 'commande' ]) > 0 ) {
foreach ( $exp -> linkedObjectsIds [ 'commande' ] as $key => $value ) {
2020-09-08 21:27:28 +02:00
$originforcontact = 'commande' ;
2021-02-23 21:09:01 +01:00
if ( is_object ( $value )) {
$originidforcontact = $value -> id ;
} else {
$originidforcontact = $value ;
}
2020-09-08 21:27:28 +02:00
break ; // We take first one
}
}
2018-07-06 08:07:38 +02:00
}
$sqlcontact = " SELECT ctc.code, ctc.source, ec.fk_socpeople FROM " . MAIN_DB_PREFIX . " element_contact as ec, " . MAIN_DB_PREFIX . " c_type_contact as ctc " ;
2021-03-30 17:53:25 +02:00
$sqlcontact .= " WHERE element_id = " . (( int ) $originidforcontact ) . " AND ec.fk_c_type_contact = ctc.rowid AND ctc.element = ' " . $this -> db -> escape ( $originforcontact ) . " ' " ;
2018-07-06 08:07:38 +02:00
$resqlcontact = $this -> db -> query ( $sqlcontact );
2021-02-23 21:09:01 +01:00
if ( $resqlcontact ) {
while ( $objcontact = $this -> db -> fetch_object ( $resqlcontact )) {
2020-09-08 21:27:28 +02:00
//print $objcontact->code.'-'.$objcontact->source.'-'.$objcontact->fk_socpeople."\n";
$this -> add_contact ( $objcontact -> fk_socpeople , $objcontact -> code , $objcontact -> source ); // May failed because of duplicate key or because code of contact type does not exists for new object
}
2021-02-23 21:09:01 +01:00
} else {
dol_print_error ( $resqlcontact );
}
2018-07-06 08:07:38 +02:00
}
/*
* Insert lines of invoices , if not from template invoice , into database
*/
2021-02-23 21:09:01 +01:00
if ( ! $error && empty ( $this -> fac_rec ) && count ( $this -> lines ) && is_object ( $this -> lines [ 0 ])) { // If this->lines is array of InvoiceLines (preferred mode)
2018-07-06 08:07:38 +02:00
$fk_parent_line = 0 ;
dol_syslog ( " There is " . count ( $this -> lines ) . " lines that are invoice lines objects " );
2021-02-23 21:09:01 +01:00
foreach ( $this -> lines as $i => $val ) {
2019-11-08 10:53:31 +01:00
$newinvoiceline = $this -> lines [ $i ];
2022-02-15 12:14:48 +01:00
$newinvoiceline -> context = $this -> context ;
2019-11-08 10:53:31 +01:00
$newinvoiceline -> fk_facture = $this -> id ;
2018-07-06 08:07:38 +02:00
$newinvoiceline -> origin = $this -> lines [ $i ] -> element ;
$newinvoiceline -> origin_id = $this -> lines [ $i ] -> id ;
// Auto set date of service ?
2021-02-23 21:09:01 +01:00
if ( $this -> lines [ $i ] -> date_start_fill == 1 && $originaldatewhen ) { // $originaldatewhen is defined when generating from recurring invoice only
2018-07-06 08:07:38 +02:00
$newinvoiceline -> date_start = $originaldatewhen ;
}
2021-02-23 21:09:01 +01:00
if ( $this -> lines [ $i ] -> date_end_fill == 1 && $previousdaynextdatewhen ) { // $previousdaynextdatewhen is defined when generating from recurring invoice only
2018-07-06 08:07:38 +02:00
$newinvoiceline -> date_end = $previousdaynextdatewhen ;
}
2021-02-23 21:09:01 +01:00
if ( $result >= 0 ) {
2018-07-06 08:07:38 +02:00
// Reset fk_parent_line for no child products and special product
if (( $newinvoiceline -> product_type != 9 && empty ( $newinvoiceline -> fk_parent_line )) || $newinvoiceline -> product_type == 9 ) {
$fk_parent_line = 0 ;
}
2022-04-04 10:32:17 +02:00
// Complete vat rate with code
$vatrate = $newinvoiceline -> tva_tx ;
if ( $newinvoiceline -> vat_src_code && ! preg_match ( '/\(.*\)/' , $vatrate )) $vatrate .= ' (' . $newinvoiceline -> vat_src_code . ')' ;
2019-11-08 10:53:31 +01:00
$newinvoiceline -> fk_parent_line = $fk_parent_line ;
2018-07-06 08:07:38 +02:00
2019-11-08 10:53:31 +01:00
if ( $this -> type === Facture :: TYPE_REPLACEMENT && $newinvoiceline -> fk_remise_except ) {
2020-09-08 21:27:28 +02:00
$discount = new DiscountAbsolute ( $this -> db );
$discount -> fetch ( $newinvoiceline -> fk_remise_except );
2018-07-05 11:52:41 +02:00
2020-09-08 21:27:28 +02:00
$discountId = $soc -> set_remise_except ( $discount -> amount_ht , $user , $discount -> description , $discount -> tva_tx );
$newinvoiceline -> fk_remise_except = $discountId ;
}
2018-07-05 11:52:41 +02:00
2022-04-04 10:32:17 +02:00
$result = $this -> addline (
$newinvoiceline -> desc ,
$newinvoiceline -> subprice ,
$newinvoiceline -> qty ,
$vatrate ,
$newinvoiceline -> localtax1_tx ,
$newinvoiceline -> localtax2_tx ,
$newinvoiceline -> fk_product ,
$newinvoiceline -> remise_percent ,
$newinvoiceline -> date_start ,
$newinvoiceline -> date_end ,
$newinvoiceline -> fk_code_ventilation ,
$newinvoiceline -> info_bits ,
$newinvoiceline -> fk_remise_except ,
'HT' ,
0 ,
$newinvoiceline -> product_type ,
$newinvoiceline -> rang ,
$newinvoiceline -> special_code ,
$newinvoiceline -> element ,
$newinvoiceline -> id ,
$fk_parent_line ,
$newinvoiceline -> fk_fournprice ,
$newinvoiceline -> pa_ht ,
$newinvoiceline -> label ,
$newinvoiceline -> array_options ,
$newinvoiceline -> situation_percent ,
$newinvoiceline -> fk_prev_id ,
$newinvoiceline -> fk_unit ,
2022-05-03 14:18:48 +02:00
$newinvoiceline -> multicurrency_subprice ,
$newinvoiceline -> ref_ext ,
1
2022-04-04 10:32:17 +02:00
);
2018-07-06 08:07:38 +02:00
// Defined the new fk_parent_line
2022-09-13 15:12:31 +02:00
if ( $result > 0 && $newinvoiceline -> product_type == 9 ) {
2018-07-06 08:07:38 +02:00
$fk_parent_line = $result ;
}
}
2021-02-23 21:09:01 +01:00
if ( $result < 0 ) {
2019-11-08 10:53:31 +01:00
$this -> error = $newinvoiceline -> error ;
2021-02-08 20:44:40 +01:00
$this -> errors = $newinvoiceline -> errors ;
2018-07-06 08:07:38 +02:00
$error ++ ;
break ;
}
}
2021-02-23 21:09:01 +01:00
} elseif ( ! $error && empty ( $this -> fac_rec )) { // If this->lines is an array of invoice line arrays
2018-07-06 08:07:38 +02:00
$fk_parent_line = 0 ;
dol_syslog ( " There is " . count ( $this -> lines ) . " lines that are array lines " );
2021-02-23 21:09:01 +01:00
foreach ( $this -> lines as $i => $val ) {
2020-09-08 21:27:28 +02:00
$line = $this -> lines [ $i ];
2018-07-06 08:07:38 +02:00
2020-09-08 21:27:28 +02:00
// Test and convert into object this->lines[$i]. When coming from REST API, we may still have an array
//if (! is_object($line)) $line=json_decode(json_encode($line), false); // convert recursively array into object.
2021-02-23 21:09:01 +01:00
if ( ! is_object ( $line )) {
$line = ( object ) $line ;
}
2018-07-06 08:07:38 +02:00
2021-02-23 21:09:01 +01:00
if ( $result >= 0 ) {
2018-07-06 08:07:38 +02:00
// Reset fk_parent_line for no child products and special product
if (( $line -> product_type != 9 && empty ( $line -> fk_parent_line )) || $line -> product_type == 9 ) {
$fk_parent_line = 0 ;
}
// Complete vat rate with code
$vatrate = $line -> tva_tx ;
2021-02-23 21:09:01 +01:00
if ( $line -> vat_src_code && ! preg_match ( '/\(.*\)/' , $vatrate )) {
$vatrate .= ' (' . $line -> vat_src_code . ')' ;
}
2018-07-06 08:07:38 +02:00
2020-04-23 18:55:10 +02:00
if ( ! empty ( $conf -> global -> MAIN_CREATEFROM_KEEP_LINE_ORIGIN_INFORMATION )) {
$originid = $line -> origin_id ;
$origintype = $line -> origin ;
2020-03-12 09:44:43 +01:00
} else {
2020-04-23 18:55:10 +02:00
$originid = $line -> id ;
$origintype = $this -> element ;
2020-03-12 09:44:43 +01:00
}
2020-09-04 19:33:58 +02:00
2020-09-04 19:32:42 +02:00
// init ref_ext
if ( empty ( $line -> ref_ext )) {
$line -> ref_ext = '' ;
}
2020-03-12 09:44:43 +01:00
2020-09-08 21:27:28 +02:00
$result = $this -> addline (
2018-07-06 08:07:38 +02:00
$line -> desc ,
$line -> subprice ,
$line -> qty ,
$vatrate ,
$line -> localtax1_tx ,
$line -> localtax2_tx ,
$line -> fk_product ,
$line -> remise_percent ,
$line -> date_start ,
$line -> date_end ,
$line -> fk_code_ventilation ,
$line -> info_bits ,
$line -> fk_remise_except ,
'HT' ,
0 ,
$line -> product_type ,
$line -> rang ,
$line -> special_code ,
2020-09-08 21:27:28 +02:00
$origintype ,
$originid ,
2018-07-06 08:07:38 +02:00
$fk_parent_line ,
$line -> fk_fournprice ,
$line -> pa_ht ,
$line -> label ,
$line -> array_options ,
$line -> situation_percent ,
$line -> fk_prev_id ,
$line -> fk_unit ,
2020-12-16 10:55:33 +01:00
$line -> multicurrency_subprice ,
2022-05-03 14:18:48 +02:00
$line -> ref_ext ,
1
2018-07-06 08:07:38 +02:00
);
2021-02-23 21:09:01 +01:00
if ( $result < 0 ) {
2019-11-08 10:53:31 +01:00
$this -> error = $this -> db -> lasterror ();
2018-07-06 08:07:38 +02:00
dol_print_error ( $this -> db );
$this -> db -> rollback ();
return - 1 ;
}
// Defined the new fk_parent_line
if ( $result > 0 && $line -> product_type == 9 ) {
$fk_parent_line = $result ;
}
}
}
}
/*
2019-03-06 21:39:09 +01:00
* Insert lines of template invoices
2018-07-06 08:07:38 +02:00
*/
2021-02-23 21:09:01 +01:00
if ( ! $error && $this -> fac_rec > 0 ) {
foreach ( $_facrec -> lines as $i => $val ) {
if ( $_facrec -> lines [ $i ] -> fk_product ) {
2018-07-06 08:07:38 +02:00
$prod = new Product ( $this -> db );
2019-11-08 10:53:31 +01:00
$res = $prod -> fetch ( $_facrec -> lines [ $i ] -> fk_product );
2018-07-06 08:07:38 +02:00
}
// For line from template invoice, we use data from template invoice
/*
$tva_tx = get_default_tva ( $mysoc , $soc , $prod -> id );
$tva_npr = get_default_npr ( $mysoc , $soc , $prod -> id );
if ( empty ( $tva_tx )) $tva_npr = 0 ;
$localtax1_tx = get_localtax ( $tva_tx , 1 , $soc , $mysoc , $tva_npr );
$localtax2_tx = get_localtax ( $tva_tx , 2 , $soc , $mysoc , $tva_npr );
*/
$tva_tx = $_facrec -> lines [ $i ] -> tva_tx . ( $_facrec -> lines [ $i ] -> vat_src_code ? '(' . $_facrec -> lines [ $i ] -> vat_src_code . ')' : '' );
$tva_npr = $_facrec -> lines [ $i ] -> info_bits ;
2021-02-23 21:09:01 +01:00
if ( empty ( $tva_tx )) {
$tva_npr = 0 ;
}
2018-07-06 08:07:38 +02:00
$localtax1_tx = $_facrec -> lines [ $i ] -> localtax1_tx ;
$localtax2_tx = $_facrec -> lines [ $i ] -> localtax2_tx ;
2021-03-03 23:55:28 +01:00
$fk_product_fournisseur_price = empty ( $_facrec -> lines [ $i ] -> fk_product_fournisseur_price ) ? null : $_facrec -> lines [ $i ] -> fk_product_fournisseur_price ;
2019-11-08 10:53:31 +01:00
$buyprice = empty ( $_facrec -> lines [ $i ] -> buyprice ) ? 0 : $_facrec -> lines [ $i ] -> buyprice ;
2021-03-03 23:55:28 +01:00
2019-03-06 21:39:09 +01:00
// If buyprice not defined from template invoice, we try to guess the best value
2021-02-23 21:09:01 +01:00
if ( ! $buyprice && $_facrec -> lines [ $i ] -> fk_product > 0 ) {
2020-09-08 21:27:28 +02:00
require_once DOL_DOCUMENT_ROOT . '/fourn/class/fournisseur.product.class.php' ;
$producttmp = new ProductFournisseur ( $this -> db );
$producttmp -> fetch ( $_facrec -> lines [ $i ] -> fk_product );
// If margin module defined on costprice, we try the costprice
// If not defined or if module margin defined and pmp and stock module enabled, we try pmp price
// else we get the best supplier price
2021-02-23 21:09:01 +01:00
if ( $conf -> global -> MARGIN_TYPE == 'costprice' && ! empty ( $producttmp -> cost_price )) {
$buyprice = $producttmp -> cost_price ;
} elseif ( ! empty ( $conf -> stock -> enabled ) && ( $conf -> global -> MARGIN_TYPE == 'costprice' || $conf -> global -> MARGIN_TYPE == 'pmp' ) && ! empty ( $producttmp -> pmp )) {
$buyprice = $producttmp -> pmp ;
} else {
if ( $producttmp -> find_min_price_product_fournisseur ( $_facrec -> lines [ $i ] -> fk_product ) > 0 ) {
if ( $producttmp -> product_fourn_price_id > 0 ) {
2020-09-08 21:27:28 +02:00
$buyprice = price2num ( $producttmp -> fourn_unitprice * ( 1 - $producttmp -> fourn_remise_percent / 100 ) + $producttmp -> fourn_remise , 'MU' );
}
}
}
}
2019-03-06 21:39:09 +01:00
2018-07-06 08:07:38 +02:00
$result_insert = $this -> addline (
$_facrec -> lines [ $i ] -> desc ,
$_facrec -> lines [ $i ] -> subprice ,
$_facrec -> lines [ $i ] -> qty ,
$tva_tx ,
$localtax1_tx ,
$localtax2_tx ,
$_facrec -> lines [ $i ] -> fk_product ,
$_facrec -> lines [ $i ] -> remise_percent ,
2019-11-08 10:53:31 +01:00
( $_facrec -> lines [ $i ] -> date_start_fill == 1 && $originaldatewhen ) ? $originaldatewhen : '' ,
( $_facrec -> lines [ $i ] -> date_end_fill == 1 && $previousdaynextdatewhen ) ? $previousdaynextdatewhen : '' ,
2018-07-06 08:07:38 +02:00
0 ,
$tva_npr ,
'' ,
'HT' ,
0 ,
$_facrec -> lines [ $i ] -> product_type ,
$_facrec -> lines [ $i ] -> rang ,
$_facrec -> lines [ $i ] -> special_code ,
'' ,
0 ,
0 ,
2020-09-08 21:27:28 +02:00
$fk_product_fournisseur_price ,
2019-03-06 21:39:09 +01:00
$buyprice ,
2018-07-06 08:07:38 +02:00
$_facrec -> lines [ $i ] -> label ,
2019-11-08 10:53:31 +01:00
empty ( $_facrec -> lines [ $i ] -> array_options ) ? null : $_facrec -> lines [ $i ] -> array_options ,
2018-07-06 08:07:38 +02:00
$_facrec -> lines [ $i ] -> situation_percent ,
'' ,
$_facrec -> lines [ $i ] -> fk_unit ,
2022-05-03 14:18:48 +02:00
$_facrec -> lines [ $i ] -> multicurrency_subprice ,
$_facrec -> lines [ $i ] -> ref_ext ,
1
2018-07-06 08:07:38 +02:00
);
2021-02-23 21:09:01 +01:00
if ( $result_insert < 0 ) {
2018-07-06 08:07:38 +02:00
$error ++ ;
2019-11-08 10:53:31 +01:00
$this -> error = $this -> db -> error ();
2018-07-06 08:07:38 +02:00
break ;
}
}
}
2021-02-23 21:09:01 +01:00
if ( ! $error ) {
2022-05-03 14:18:48 +02:00
$result = $this -> update_price ( 1 , 'auto' , 0 , $mysoc );
2021-02-23 21:09:01 +01:00
if ( $result > 0 ) {
2019-11-08 10:53:31 +01:00
$action = 'create' ;
2018-07-06 08:07:38 +02:00
// Actions on extra fields
2021-02-23 21:09:01 +01:00
if ( ! $error ) {
2020-09-08 21:27:28 +02:00
$result = $this -> insertExtraFields ();
2021-02-23 21:09:01 +01:00
if ( $result < 0 ) {
$error ++ ;
}
2018-07-06 08:07:38 +02:00
}
2021-02-23 21:09:01 +01:00
if ( ! $error && ! $notrigger ) {
2020-09-08 21:27:28 +02:00
// Call trigger
$result = $this -> call_trigger ( 'BILL_CREATE' , $user );
2021-02-23 21:09:01 +01:00
if ( $result < 0 ) {
$error ++ ;
}
2020-09-08 21:27:28 +02:00
// End call triggers
}
2018-07-06 08:07:38 +02:00
2021-02-23 21:09:01 +01:00
if ( ! $error ) {
2018-07-06 08:07:38 +02:00
$this -> db -> commit ();
return $this -> id ;
2020-05-21 15:05:19 +02:00
} else {
2018-07-06 08:07:38 +02:00
$this -> db -> rollback ();
return - 4 ;
}
2020-05-21 15:05:19 +02:00
} else {
2019-11-08 10:53:31 +01:00
$this -> error = $langs -> trans ( 'FailedToUpdatePrice' );
2018-07-06 08:07:38 +02:00
$this -> db -> rollback ();
return - 3 ;
}
2020-05-21 15:05:19 +02:00
} else {
2018-07-06 08:07:38 +02:00
dol_syslog ( get_class ( $this ) . " ::create error " . $this -> error , LOG_ERR );
$this -> db -> rollback ();
return - 2 ;
}
2020-05-21 15:05:19 +02:00
} else {
2019-11-08 10:53:31 +01:00
$this -> error = $this -> db -> error ();
2018-07-06 08:07:38 +02:00
$this -> db -> rollback ();
return - 1 ;
}
}
/**
* Create a new invoice in database from current invoice
*
* @ param User $user Object user that ask creation
* @ param int $invertdetail Reverse sign of amounts for lines
* @ return int < 0 if KO , > 0 if OK
*/
2020-09-08 21:27:28 +02:00
public function createFromCurrent ( User $user , $invertdetail = 0 )
2018-07-06 08:07:38 +02:00
{
global $conf ;
2021-11-15 04:26:14 +01:00
// Source invoice load
2019-11-08 10:53:31 +01:00
$facture = new Facture ( $this -> db );
2018-07-06 08:07:38 +02:00
2020-10-23 20:08:35 +02:00
// Retrieve all extrafield
2018-07-06 08:07:38 +02:00
// fetch optionals attributes and labels
$this -> fetch_optionals ();
2020-09-08 21:27:28 +02:00
if ( ! empty ( $this -> array_options )) {
$facture -> array_options = $this -> array_options ;
}
2013-04-18 08:40:29 +02:00
2020-09-08 21:27:28 +02:00
foreach ( $this -> lines as & $line ) {
$line -> fetch_optionals (); //fetch extrafields
}
2013-04-18 08:40:29 +02:00
2018-07-06 08:07:38 +02:00
$facture -> fk_facture_source = $this -> fk_facture_source ;
$facture -> type = $this -> type ;
$facture -> socid = $this -> socid ;
$facture -> date = $this -> date ;
$facture -> date_pointoftax = $this -> date_pointoftax ;
$facture -> note_public = $this -> note_public ;
$facture -> note_private = $this -> note_private ;
$facture -> ref_client = $this -> ref_client ;
2021-02-08 18:30:09 +01:00
$facture -> modelpdf = $this -> model_pdf ; // deprecated
$facture -> model_pdf = $this -> model_pdf ;
2018-07-06 08:07:38 +02:00
$facture -> fk_project = $this -> fk_project ;
$facture -> cond_reglement_id = $this -> cond_reglement_id ;
$facture -> mode_reglement_id = $this -> mode_reglement_id ;
$facture -> remise_absolue = $this -> remise_absolue ;
$facture -> remise_percent = $this -> remise_percent ;
2019-06-03 11:37:04 +02:00
$facture -> origin = $this -> origin ;
$facture -> origin_id = $this -> origin_id ;
2018-07-06 08:07:38 +02:00
2019-11-08 10:53:31 +01:00
$facture -> lines = $this -> lines ; // Array of lines of invoice
2018-07-06 08:07:38 +02:00
$facture -> situation_counter = $this -> situation_counter ;
2019-11-08 10:53:31 +01:00
$facture -> situation_cycle_ref = $this -> situation_cycle_ref ;
$facture -> situation_final = $this -> situation_final ;
2018-07-06 08:07:38 +02:00
2020-09-08 21:27:28 +02:00
$facture -> retained_warranty = $this -> retained_warranty ;
$facture -> retained_warranty_fk_cond_reglement = $this -> retained_warranty_fk_cond_reglement ;
$facture -> retained_warranty_date_limit = $this -> retained_warranty_date_limit ;
2020-03-18 10:30:15 +01:00
2020-12-13 13:34:21 +01:00
$facture -> fk_user_author = $user -> id ;
2020-03-18 10:30:15 +01:00
2018-07-06 08:07:38 +02:00
// Loop on each line of new invoice
2021-02-23 21:09:01 +01:00
foreach ( $facture -> lines as $i => $tmpline ) {
2018-07-06 08:07:38 +02:00
$facture -> lines [ $i ] -> fk_prev_id = $this -> lines [ $i ] -> rowid ;
2021-02-23 21:09:01 +01:00
if ( $invertdetail ) {
2018-07-06 08:07:38 +02:00
$facture -> lines [ $i ] -> subprice = - $facture -> lines [ $i ] -> subprice ;
$facture -> lines [ $i ] -> total_ht = - $facture -> lines [ $i ] -> total_ht ;
$facture -> lines [ $i ] -> total_tva = - $facture -> lines [ $i ] -> total_tva ;
$facture -> lines [ $i ] -> total_localtax1 = - $facture -> lines [ $i ] -> total_localtax1 ;
$facture -> lines [ $i ] -> total_localtax2 = - $facture -> lines [ $i ] -> total_localtax2 ;
$facture -> lines [ $i ] -> total_ttc = - $facture -> lines [ $i ] -> total_ttc ;
2020-09-04 19:32:42 +02:00
$facture -> lines [ $i ] -> ref_ext = '' ;
2018-07-06 08:07:38 +02:00
}
}
dol_syslog ( get_class ( $this ) . " ::createFromCurrent invertdetail= " . $invertdetail . " socid= " . $this -> socid . " nboflines= " . count ( $facture -> lines ));
$facid = $facture -> create ( $user );
2021-02-23 21:09:01 +01:00
if ( $facid <= 0 ) {
2019-11-08 10:53:31 +01:00
$this -> error = $facture -> error ;
$this -> errors = $facture -> errors ;
2021-02-23 21:09:01 +01:00
} elseif ( $this -> type == self :: TYPE_SITUATION && ! empty ( $conf -> global -> INVOICE_USE_SITUATION )) {
2019-11-14 12:09:32 +01:00
$this -> fetchObjectLinked ( '' , '' , $this -> id , 'facture' );
2018-07-06 08:07:38 +02:00
2021-02-23 21:09:01 +01:00
foreach ( $this -> linkedObjectsIds as $typeObject => $Tfk_object ) {
foreach ( $Tfk_object as $fk_object ) {
2018-07-06 08:07:38 +02:00
$facture -> add_object_linked ( $typeObject , $fk_object );
}
}
$facture -> add_object_linked ( 'facture' , $this -> fk_facture_source );
}
return $facid ;
}
/**
2019-04-12 12:12:08 +02:00
* Load an object from its id and create a new one in database
2018-07-06 08:07:38 +02:00
*
2020-09-08 21:27:28 +02:00
* @ param User $user User that clone
2019-04-12 12:12:08 +02:00
* @ param int $fromid Id of object to clone
* @ return int New id of clone
2018-07-06 08:07:38 +02:00
*/
2019-04-12 12:12:08 +02:00
public function createFromClone ( User $user , $fromid = 0 )
2018-07-06 08:07:38 +02:00
{
2019-11-12 10:13:22 +01:00
global $conf , $hookmanager ;
2018-07-06 08:07:38 +02:00
2019-11-08 10:53:31 +01:00
$error = 0 ;
2018-07-06 08:07:38 +02:00
2019-11-08 10:53:31 +01:00
$object = new Facture ( $this -> db );
2018-07-06 08:07:38 +02:00
2019-04-12 12:12:08 +02:00
$this -> db -> begin ();
2018-07-06 08:07:38 +02:00
2019-04-12 12:12:08 +02:00
$object -> fetch ( $fromid );
2018-07-06 08:07:38 +02:00
2022-01-27 02:27:36 +01:00
// Load source object
$objFrom = clone $object ;
2018-07-06 08:07:38 +02:00
// Change socid if needed
2021-02-23 21:09:01 +01:00
if ( ! empty ( $this -> socid ) && $this -> socid != $object -> socid ) {
2018-07-06 08:07:38 +02:00
$objsoc = new Societe ( $this -> db );
2021-02-23 21:09:01 +01:00
if ( $objsoc -> fetch ( $this -> socid ) > 0 ) {
2020-09-08 21:27:28 +02:00
$object -> socid = $objsoc -> id ;
$object -> cond_reglement_id = ( ! empty ( $objsoc -> cond_reglement_id ) ? $objsoc -> cond_reglement_id : 0 );
$object -> mode_reglement_id = ( ! empty ( $objsoc -> mode_reglement_id ) ? $objsoc -> mode_reglement_id : 0 );
$object -> fk_project = '' ;
$object -> fk_delivery_address = '' ;
2018-07-06 08:07:38 +02:00
}
// TODO Change product price if multi-prices
}
2019-11-08 10:53:31 +01:00
$object -> id = 0 ;
$object -> statut = self :: STATUS_DRAFT ;
2021-02-03 20:42:30 +01:00
$object -> status = self :: STATUS_DRAFT ;
2018-07-06 08:07:38 +02:00
// Clear fields
2019-04-12 12:12:08 +02:00
$object -> date = ( empty ( $this -> date ) ? dol_now () : $this -> date );
2021-06-14 15:37:02 +02:00
$object -> user_author = $user -> id ; // deprecated
$object -> user_valid = null ; // deprecated
2020-12-13 13:34:21 +01:00
$object -> fk_user_author = $user -> id ;
$object -> fk_user_valid = null ;
2019-04-12 12:12:08 +02:00
$object -> fk_facture_source = 0 ;
$object -> date_creation = '' ;
$object -> date_modification = '' ;
$object -> date_validation = '' ;
$object -> ref_client = '' ;
$object -> close_code = '' ;
$object -> close_note = '' ;
2019-11-12 10:13:22 +01:00
if ( $conf -> global -> MAIN_DONT_KEEP_NOTE_ON_CLONING == 1 ) {
$object -> note_private = '' ;
$object -> note_public = '' ;
}
2018-07-06 08:07:38 +02:00
// Loop on each line of new invoice
2021-02-23 21:09:01 +01:00
foreach ( $object -> lines as $i => $line ) {
if (( $object -> lines [ $i ] -> info_bits & 0x02 ) == 0x02 ) { // We do not clone line of discounts
2020-09-08 21:27:28 +02:00
unset ( $object -> lines [ $i ]);
2021-03-02 12:37:24 +01:00
continue ;
2020-05-07 22:09:55 +02:00
}
2021-01-28 09:59:13 +01:00
// Bloc to update dates of service (month by month only if previously filled and similare to start and end of month)
2020-05-07 22:09:55 +02:00
// If it's a service with start and end dates
2021-01-28 09:59:13 +01:00
if ( ! empty ( $conf -> global -> INVOICE_AUTO_NEXT_MONTH_ON_LINES ) && ! empty ( $line -> date_start ) && ! empty ( $line -> date_end )) {
2020-05-07 22:09:55 +02:00
// Get the dates
$start = dol_getdate ( $line -> date_start );
$end = dol_getdate ( $line -> date_end );
2020-05-07 22:11:59 +02:00
2020-05-07 22:09:55 +02:00
// Get the first and last day of the month
$first = dol_get_first_day ( $start [ 'year' ], $start [ 'mon' ]);
2021-01-28 09:59:13 +01:00
$last = dol_get_last_day ( $end [ 'year' ], $end [ 'mon' ]);
2020-05-07 22:09:55 +02:00
2021-01-28 09:59:13 +01:00
//print dol_print_date(dol_mktime(0, 0, 0, $start['mon'], $start['mday'], $start['year'], 'gmt'), 'dayhour').' '.dol_print_date($first, 'dayhour').'<br>';
//print dol_mktime(23, 59, 59, $end['mon'], $end['mday'], $end['year'], 'gmt').' '.$last.'<br>';exit;
// If start date is first date of month and end date is last date of month
if ( dol_mktime ( 0 , 0 , 0 , $start [ 'mon' ], $start [ 'mday' ], $start [ 'year' ], 'gmt' ) == $first
&& dol_mktime ( 23 , 59 , 59 , $end [ 'mon' ], $end [ 'mday' ], $end [ 'year' ], 'gmt' ) == $last ) {
2020-05-07 22:09:55 +02:00
$nextMonth = dol_get_next_month ( $end [ 'mon' ], $end [ 'year' ]);
2020-05-07 22:11:59 +02:00
$newFirst = dol_get_first_day ( $nextMonth [ 'year' ], $nextMonth [ 'month' ]);
$newLast = dol_get_last_day ( $nextMonth [ 'year' ], $nextMonth [ 'month' ]);
2020-05-07 22:09:55 +02:00
$object -> lines [ $i ] -> date_start = $newFirst ;
$object -> lines [ $i ] -> date_end = $newLast ;
}
2018-07-06 08:07:38 +02:00
}
2020-09-04 19:33:58 +02:00
2021-06-14 15:37:02 +02:00
$object -> lines [ $i ] -> ref_ext = '' ; // Do not clone ref_ext
2018-07-06 08:07:38 +02:00
}
// Create clone
2019-04-12 12:12:08 +02:00
$object -> context [ 'createfromclone' ] = 'createfromclone' ;
2019-11-08 10:53:31 +01:00
$result = $object -> create ( $user );
2021-02-23 21:09:01 +01:00
if ( $result < 0 ) {
$error ++ ;
2021-06-25 16:40:39 +02:00
$this -> error = $object -> error ;
$this -> errors = $object -> errors ;
2021-02-23 21:09:01 +01:00
} else {
2018-07-06 08:07:38 +02:00
// copy internal contacts
2022-01-27 02:27:36 +01:00
if ( $object -> copy_linked_contact ( $objFrom , 'internal' ) < 0 ) {
2018-07-06 08:07:38 +02:00
$error ++ ;
2021-06-25 16:40:39 +02:00
$this -> error = $object -> error ;
$this -> errors = $object -> errors ;
2022-01-27 02:27:36 +01:00
} elseif ( $object -> socid == $objFrom -> socid ) {
2021-02-23 21:09:01 +01:00
// copy external contacts if same company
2022-01-27 02:27:36 +01:00
if ( $object -> copy_linked_contact ( $objFrom , 'external' ) < 0 ) {
2018-07-06 08:07:38 +02:00
$error ++ ;
2021-06-25 16:40:39 +02:00
$this -> error = $object -> error ;
$this -> errors = $object -> errors ;
2021-02-23 21:09:01 +01:00
}
2018-07-06 08:07:38 +02:00
}
}
2021-02-23 21:09:01 +01:00
if ( ! $error ) {
2018-07-06 08:07:38 +02:00
// Hook of thirdparty module
2021-02-23 21:09:01 +01:00
if ( is_object ( $hookmanager )) {
2022-01-27 02:27:36 +01:00
$parameters = array ( 'objFrom' => $objFrom );
2019-11-08 10:53:31 +01:00
$action = '' ;
$reshook = $hookmanager -> executeHooks ( 'createFrom' , $parameters , $object , $action ); // Note that $action and $object may have been modified by some hooks
2021-02-23 21:09:01 +01:00
if ( $reshook < 0 ) {
2023-01-18 09:53:28 +01:00
$this -> errors += $hookmanager -> errors ;
$this -> error = $hookmanager -> error ;
2021-02-23 21:09:01 +01:00
$error ++ ;
}
2018-07-06 08:07:38 +02:00
}
}
2019-04-12 12:12:08 +02:00
unset ( $object -> context [ 'createfromclone' ]);
2018-07-06 08:07:38 +02:00
// End
2021-02-23 21:09:01 +01:00
if ( ! $error ) {
2018-07-06 08:07:38 +02:00
$this -> db -> commit ();
2019-04-12 12:12:08 +02:00
return $object -> id ;
2020-05-21 15:05:19 +02:00
} else {
2018-07-06 08:07:38 +02:00
$this -> db -> rollback ();
return - 1 ;
}
}
/**
* Load an object from an order and create a new invoice into database
*
* @ param Object $object Object source
* @ param User $user Object user
* @ return int < 0 if KO , 0 if nothing done , 1 if OK
*/
2020-09-08 21:27:28 +02:00
public function createFromOrder ( $object , User $user )
2018-07-06 08:07:38 +02:00
{
2019-03-18 20:09:09 +01:00
global $conf , $hookmanager ;
2018-07-06 08:07:38 +02:00
2019-11-08 10:53:31 +01:00
$error = 0 ;
2018-07-06 08:07:38 +02:00
// Closed order
$this -> date = dol_now ();
$this -> source = 0 ;
2019-11-08 10:53:31 +01:00
$num = count ( $object -> lines );
2021-02-23 21:09:01 +01:00
for ( $i = 0 ; $i < $num ; $i ++ ) {
2018-07-06 08:07:38 +02:00
$line = new FactureLigne ( $this -> db );
2019-11-08 10:53:31 +01:00
$line -> libelle = $object -> lines [ $i ] -> libelle ; // deprecated
2018-07-06 08:07:38 +02:00
$line -> label = $object -> lines [ $i ] -> label ;
$line -> desc = $object -> lines [ $i ] -> desc ;
$line -> subprice = $object -> lines [ $i ] -> subprice ;
$line -> total_ht = $object -> lines [ $i ] -> total_ht ;
$line -> total_tva = $object -> lines [ $i ] -> total_tva ;
$line -> total_localtax1 = $object -> lines [ $i ] -> total_localtax1 ;
$line -> total_localtax2 = $object -> lines [ $i ] -> total_localtax2 ;
$line -> total_ttc = $object -> lines [ $i ] -> total_ttc ;
2019-11-08 10:53:31 +01:00
$line -> vat_src_code = $object -> lines [ $i ] -> vat_src_code ;
$line -> tva_tx = $object -> lines [ $i ] -> tva_tx ;
2018-07-06 08:07:38 +02:00
$line -> localtax1_tx = $object -> lines [ $i ] -> localtax1_tx ;
$line -> localtax2_tx = $object -> lines [ $i ] -> localtax2_tx ;
2019-11-08 10:53:31 +01:00
$line -> qty = $object -> lines [ $i ] -> qty ;
$line -> fk_remise_except = $object -> lines [ $i ] -> fk_remise_except ;
$line -> remise_percent = $object -> lines [ $i ] -> remise_percent ;
$line -> fk_product = $object -> lines [ $i ] -> fk_product ;
$line -> info_bits = $object -> lines [ $i ] -> info_bits ;
2018-07-06 08:07:38 +02:00
$line -> product_type = $object -> lines [ $i ] -> product_type ;
2019-11-08 10:53:31 +01:00
$line -> rang = $object -> lines [ $i ] -> rang ;
2018-07-06 08:07:38 +02:00
$line -> special_code = $object -> lines [ $i ] -> special_code ;
2019-11-08 10:53:31 +01:00
$line -> fk_parent_line = $object -> lines [ $i ] -> fk_parent_line ;
$line -> fk_unit = $object -> lines [ $i ] -> fk_unit ;
$line -> date_start = $object -> lines [ $i ] -> date_start ;
$line -> date_end = $object -> lines [ $i ] -> date_end ;
2018-07-06 08:07:38 +02:00
2020-02-20 15:11:31 +01:00
// Multicurrency
$line -> fk_multicurrency = $object -> lines [ $i ] -> fk_multicurrency ;
$line -> multicurrency_code = $object -> lines [ $i ] -> multicurrency_code ;
$line -> multicurrency_subprice = $object -> lines [ $i ] -> multicurrency_subprice ;
$line -> multicurrency_total_ht = $object -> lines [ $i ] -> multicurrency_total_ht ;
$line -> multicurrency_total_tva = $object -> lines [ $i ] -> multicurrency_total_tva ;
$line -> multicurrency_total_ttc = $object -> lines [ $i ] -> multicurrency_total_ttc ;
2019-11-08 10:53:31 +01:00
$line -> fk_fournprice = $object -> lines [ $i ] -> fk_fournprice ;
2018-07-06 08:07:38 +02:00
$marginInfos = getMarginInfos ( $object -> lines [ $i ] -> subprice , $object -> lines [ $i ] -> remise_percent , $object -> lines [ $i ] -> tva_tx , $object -> lines [ $i ] -> localtax1_tx , $object -> lines [ $i ] -> localtax2_tx , $object -> lines [ $i ] -> fk_fournprice , $object -> lines [ $i ] -> pa_ht );
$line -> pa_ht = $marginInfos [ 0 ];
2013-04-18 08:40:29 +02:00
2020-09-08 21:27:28 +02:00
// get extrafields from original line
2018-07-06 08:07:38 +02:00
$object -> lines [ $i ] -> fetch_optionals ();
2020-12-13 13:34:21 +01:00
foreach ( $object -> lines [ $i ] -> array_options as $options_key => $value ) {
2018-07-06 08:07:38 +02:00
$line -> array_options [ $options_key ] = $value ;
2020-12-13 13:34:21 +01:00
}
2018-07-06 08:07:38 +02:00
$this -> lines [ $i ] = $line ;
}
$this -> socid = $object -> socid ;
$this -> fk_project = $object -> fk_project ;
2020-02-20 15:11:31 +01:00
$this -> fk_account = $object -> fk_account ;
2018-07-06 08:07:38 +02:00
$this -> cond_reglement_id = $object -> cond_reglement_id ;
$this -> mode_reglement_id = $object -> mode_reglement_id ;
$this -> availability_id = $object -> availability_id ;
$this -> demand_reason_id = $object -> demand_reason_id ;
2020-11-16 12:20:18 +01:00
$this -> delivery_date = ( empty ( $object -> delivery_date ) ? $object -> date_livraison : $object -> delivery_date );
2020-12-01 02:41:19 +01:00
$this -> date_livraison = $object -> delivery_date ; // deprecated
2020-01-30 01:48:28 +01:00
$this -> fk_delivery_address = $object -> fk_delivery_address ; // deprecated
2020-06-25 12:17:47 +02:00
$this -> contact_id = $object -> contact_id ;
2018-07-06 08:07:38 +02:00
$this -> ref_client = $object -> ref_client ;
2019-03-18 20:09:09 +01:00
2021-02-23 21:09:01 +01:00
if ( empty ( $conf -> global -> MAIN_DISABLE_PROPAGATE_NOTES_FROM_ORIGIN )) {
2020-09-08 21:27:28 +02:00
$this -> note_private = $object -> note_private ;
$this -> note_public = $object -> note_public ;
2019-03-18 20:09:09 +01:00
}
2018-07-06 08:07:38 +02:00
2020-09-08 21:27:28 +02:00
$this -> module_source = $object -> module_source ;
2019-11-08 10:53:31 +01:00
$this -> pos_source = $object -> pos_source ;
2019-02-23 16:03:40 +01:00
2019-11-08 10:53:31 +01:00
$this -> origin = $object -> element ;
$this -> origin_id = $object -> id ;
2013-04-18 08:40:29 +02:00
2020-12-13 13:34:21 +01:00
$this -> fk_user_author = $user -> id ;
2020-09-08 21:27:28 +02:00
// get extrafields from original line
2020-03-27 16:02:58 +01:00
$object -> fetch_optionals ();
2021-02-23 21:09:01 +01:00
foreach ( $object -> array_options as $options_key => $value ) {
2018-07-06 08:07:38 +02:00
$this -> array_options [ $options_key ] = $value ;
2021-02-23 21:09:01 +01:00
}
2018-07-06 08:07:38 +02:00
// Possibility to add external linked objects with hooks
$this -> linked_objects [ $this -> origin ] = $this -> origin_id ;
2021-02-23 21:09:01 +01:00
if ( ! empty ( $object -> other_linked_objects ) && is_array ( $object -> other_linked_objects )) {
2018-07-06 08:07:38 +02:00
$this -> linked_objects = array_merge ( $this -> linked_objects , $object -> other_linked_objects );
}
$ret = $this -> create ( $user );
2020-12-13 13:34:21 +01:00
if ( $ret > 0 ) {
2018-07-06 08:07:38 +02:00
// Actions hooked (by external module)
$hookmanager -> initHooks ( array ( 'invoicedao' ));
2019-11-08 10:53:31 +01:00
$parameters = array ( 'objFrom' => $object );
$action = '' ;
$reshook = $hookmanager -> executeHooks ( 'createFrom' , $parameters , $this , $action ); // Note that $action and $object may have been modified by some hooks
2021-02-23 21:09:01 +01:00
if ( $reshook < 0 ) {
2023-01-18 09:53:28 +01:00
$this -> errors += $hookmanager -> errors ;
$this -> error = $hookmanager -> error ;
2021-02-23 21:09:01 +01:00
$error ++ ;
}
2018-07-06 08:07:38 +02:00
2021-02-23 21:09:01 +01:00
if ( ! $error ) {
2018-07-06 08:07:38 +02:00
return 1 ;
2021-02-23 21:09:01 +01:00
} else {
return - 1 ;
}
} else {
return - 1 ;
}
2018-07-06 08:07:38 +02:00
}
2021-09-30 12:41:07 +02:00
/**
2021-10-05 12:53:04 +02:00
* Creates a deposit from a proposal or an order by grouping lines by VAT rates
*
* @ param Propal | Commande $origin The original proposal or order
* @ param int $date Invoice date
* @ param int $payment_terms_id Invoice payment terms
* @ param User $user Object user
* @ param int $notrigger 1 = Does not execute triggers , 0 = execute triggers
* @ param bool $autoValidateDeposit Whether to aumatically validate the deposit created
* @ param array $overrideFields Array of fields to force values
* @ return Facture | null The deposit created , or null if error ( populates $origin -> error in this case )
2021-09-30 12:41:07 +02:00
*/
2021-10-05 12:53:04 +02:00
static public function createDepositFromOrigin ( CommonObject $origin , $date , $payment_terms_id , User $user , $notrigger = 0 , $autoValidateDeposit = false , $overrideFields = array ())
2021-09-30 12:41:07 +02:00
{
global $conf , $langs , $hookmanager , $action ;
if ( ! in_array ( $origin -> element , array ( 'propal' , 'commande' ))) {
2021-10-05 13:00:25 +02:00
$origin -> error = 'ErrorCanOnlyAutomaticallyGenerateADepositFromProposalOrOrder' ;
2021-09-30 12:41:07 +02:00
return null ;
}
2021-10-04 18:09:24 +02:00
if ( empty ( $date )) {
$origin -> error = $langs -> trans ( 'ErrorFieldRequired' , $langs -> transnoentities ( 'DateInvoice' ));
return null ;
}
2021-09-30 12:41:07 +02:00
2021-10-04 18:09:24 +02:00
require_once DOL_DOCUMENT_ROOT . '/core/lib/date.lib.php' ;
2021-09-30 12:41:07 +02:00
2021-10-04 18:09:24 +02:00
if ( $date > ( dol_get_last_hour ( dol_now ( 'tzuserrel' )) + ( empty ( $conf -> global -> INVOICE_MAX_FUTURE_DELAY ) ? 0 : $conf -> global -> INVOICE_MAX_FUTURE_DELAY ))) {
2021-09-30 12:41:07 +02:00
$origin -> error = 'ErrorDateIsInFuture' ;
return null ;
}
2021-10-05 12:53:04 +02:00
if ( $payment_terms_id <= 0 ) {
2021-09-30 12:41:07 +02:00
$origin -> error = $langs -> trans ( 'ErrorFieldRequired' , $langs -> transnoentities ( 'PaymentConditionsShort' ));
return null ;
}
2022-05-09 15:57:10 +02:00
$payment_conditions_deposit_percent = getDictionaryValue ( 'c_payment_term' , 'deposit_percent' , $origin -> cond_reglement_id );
2021-09-30 12:41:07 +02:00
if ( empty ( $payment_conditions_deposit_percent )) {
$origin -> error = 'ErrorPaymentConditionsNotEligibleToDepositCreation' ;
return null ;
}
if ( empty ( $origin -> deposit_percent )) {
$origin -> error = $langs -> trans ( 'ErrorFieldRequired' , $langs -> transnoentities ( 'DepositPercent' ));
return null ;
}
$deposit = new self ( $origin -> db );
$deposit -> socid = $origin -> socid ;
$deposit -> type = self :: TYPE_DEPOSIT ;
$deposit -> fk_project = $origin -> fk_project ;
$deposit -> ref_client = $origin -> ref_client ;
2021-10-04 18:09:24 +02:00
$deposit -> date = $date ;
$deposit -> mode_reglement_id = $origin -> mode_reglement_id ;
2021-10-05 12:53:04 +02:00
$deposit -> cond_reglement_id = $payment_terms_id ;
2021-09-30 12:41:07 +02:00
$deposit -> availability_id = $origin -> availability_id ;
$deposit -> demand_reason_id = $origin -> demand_reason_id ;
$deposit -> fk_account = $origin -> fk_account ;
$deposit -> fk_incoterms = $origin -> fk_incoterms ;
$deposit -> location_incoterms = $origin -> location_incoterms ;
$deposit -> fk_multicurrency = $origin -> fk_multicurrency ;
$deposit -> multicurrency_code = $origin -> multicurrency_code ;
$deposit -> multicurrency_tx = $origin -> multicurrency_tx ;
$deposit -> module_source = $origin -> module_source ;
$deposit -> pos_source = $origin -> pos_source ;
$deposit -> model_pdf = 'crabe' ;
$modelByTypeConfName = 'FACTURE_ADDON_PDF_' . $deposit -> type ;
if ( ! empty ( $conf -> global -> $modelByTypeConfName )) {
$deposit -> model_pdf = $conf -> global -> $modelByTypeConfName ;
} elseif ( ! empty ( $conf -> global -> FACTURE_ADDON_PDF )) {
$deposit -> model_pdf = $conf -> global -> FACTURE_ADDON_PDF ;
}
if ( empty ( $conf -> global -> MAIN_DISABLE_PROPAGATE_NOTES_FROM_ORIGIN )) {
$deposit -> note_private = $origin -> note_private ;
$deposit -> note_public = $origin -> note_public ;
}
$deposit -> origin = $origin -> element ;
$deposit -> origin_id = $origin -> id ;
$origin -> fetch_optionals ();
foreach ( $origin -> array_options as $extrakey => $value ) {
$deposit -> array_options [ $extrakey ] = $value ;
}
$deposit -> linked_objects [ $deposit -> origin ] = $deposit -> origin_id ;
2021-10-04 18:09:24 +02:00
foreach ( $overrideFields as $key => $value ) {
$deposit -> $key = $value ;
}
2021-09-30 12:41:07 +02:00
$deposit -> context [ 'createdepositfromorigin' ] = 'createdepositfromorigin' ;
$origin -> db -> begin ();
// Facture::create() also imports contact from origin
$createReturn = $deposit -> create ( $user , $notrigger );
if ( $createReturn <= 0 ) {
$origin -> db -> rollback ();
$origin -> error = $deposit -> error ;
$origin -> errors = $deposit -> errors ;
return null ;
}
$amount_ttc_diff = 0 ;
$amountdeposit = array ();
2021-10-05 12:37:29 +02:00
$descriptions = array ();
2021-09-30 12:41:07 +02:00
if ( ! empty ( $conf -> global -> MAIN_DEPOSIT_MULTI_TVA )) {
$amount = $origin -> total_ttc * ( $origin -> deposit_percent / 100 );
$TTotalByTva = array ();
foreach ( $origin -> lines as & $line ) {
if ( ! empty ( $line -> special_code )) {
continue ;
}
$TTotalByTva [ $line -> tva_tx ] += $line -> total_ttc ;
2021-10-05 12:37:29 +02:00
$descriptions [ $line -> tva_tx ] .= '<li>' . ( ! empty ( $line -> product_ref ) ? $line -> product_ref . ' - ' : '' );
$descriptions [ $line -> tva_tx ] .= ( ! empty ( $line -> product_label ) ? $line -> product_label . ' - ' : '' );
$descriptions [ $line -> tva_tx ] .= $langs -> trans ( 'Qty' ) . ' : ' . $line -> qty ;
$descriptions [ $line -> tva_tx ] .= ' - ' . $langs -> trans ( 'TotalHT' ) . ' : ' . price ( $line -> total_ht ) . '</li>' ;
2021-09-30 12:41:07 +02:00
}
foreach ( $TTotalByTva as $tva => & $total ) {
$coef = $total / $origin -> total_ttc ; // Calc coef
$am = $amount * $coef ;
$amount_ttc_diff += $am ;
$amountdeposit [ $tva ] += $am / ( 1 + $tva / 100 ); // Convert into HT for the addline
}
} else {
$totalamount = 0 ;
$lines = $origin -> lines ;
$numlines = count ( $lines );
for ( $i = 0 ; $i < $numlines ; $i ++ ) {
if ( empty ( $lines [ $i ] -> qty )) {
continue ; // We discard qty=0, it is an option
}
if ( ! empty ( $lines [ $i ] -> special_code )) {
continue ; // We discard special_code (frais port, ecotaxe, option, ...)
}
$totalamount += $lines [ $i ] -> total_ht ; // Fixme : is it not for the customer ? Shouldn't we take total_ttc ?
$tva_tx = $lines [ $i ] -> tva_tx ;
$amountdeposit [ $tva_tx ] += ( $lines [ $i ] -> total_ht * $origin -> deposit_percent ) / 100 ;
2021-10-05 12:37:29 +02:00
$descriptions [ $tva_tx ] .= '<li>' . ( ! empty ( $lines [ $i ] -> product_ref ) ? $lines [ $i ] -> product_ref . ' - ' : '' );
$descriptions [ $tva_tx ] .= ( ! empty ( $lines [ $i ] -> product_label ) ? $lines [ $i ] -> product_label . ' - ' : '' );
$descriptions [ $tva_tx ] .= $langs -> trans ( 'Qty' ) . ' : ' . $lines [ $i ] -> qty ;
$descriptions [ $tva_tx ] .= ' - ' . $langs -> trans ( 'TotalHT' ) . ' : ' . price ( $lines [ $i ] -> total_ht ) . '</li>' ;
2021-09-30 12:41:07 +02:00
}
if ( $totalamount == 0 ) {
$amountdeposit [ 0 ] = 0 ;
}
$amount_ttc_diff = $amountdeposit [ 0 ];
}
foreach ( $amountdeposit as $tva => $amount ) {
if ( empty ( $amount )) {
continue ;
}
$descline = '(DEPOSIT) (' . $origin -> deposit_percent . '%) - ' . $origin -> ref ;
2021-10-05 12:37:29 +02:00
// Hidden conf
2021-10-05 12:53:04 +02:00
if ( ! empty ( $conf -> global -> INVOICE_DEPOSIT_VARIABLE_MODE_DETAIL_LINES_IN_DESCRIPTION ) && ! empty ( $descriptions [ $tva ])) {
2021-10-05 12:37:29 +02:00
$descline .= '<ul>' . $descriptions [ $tva ] . '</ul>' ;
}
2021-09-30 12:41:07 +02:00
$addlineResult = $deposit -> addline (
$descline ,
$amount , // subprice
1 , // quantity
$tva , // vat rate
0 , // localtax1_tx
0 , // localtax2_tx
( empty ( $conf -> global -> INVOICE_PRODUCTID_DEPOSIT ) ? 0 : $conf -> global -> INVOICE_PRODUCTID_DEPOSIT ), // fk_product
0 , // remise_percent
0 , // date_start
0 , // date_end
0 ,
2022-05-18 12:40:44 +02:00
0 , // info_bits
2021-09-30 12:41:07 +02:00
0 ,
'HT' ,
0 ,
0 , // product_type
1 ,
2022-05-18 12:40:44 +02:00
0 , // special_code
2021-09-30 12:41:07 +02:00
$deposit -> origin ,
0 ,
0 ,
0 ,
0
//,$langs->trans('Deposit') //Deprecated
);
if ( $addlineResult < 0 ) {
$origin -> db -> rollback ();
$origin -> error = $deposit -> error ;
$origin -> errors = $deposit -> errors ;
return null ;
}
}
$diff = $deposit -> total_ttc - $amount_ttc_diff ;
if ( ! empty ( $conf -> global -> MAIN_DEPOSIT_MULTI_TVA ) && $diff != 0 ) {
$deposit -> fetch_lines ();
$subprice_diff = $deposit -> lines [ 0 ] -> subprice - $diff / ( 1 + $deposit -> lines [ 0 ] -> tva_tx / 100 );
$updatelineResult = $deposit -> updateline (
$deposit -> lines [ 0 ] -> id ,
$deposit -> lines [ 0 ] -> desc ,
$subprice_diff ,
$deposit -> lines [ 0 ] -> qty ,
$deposit -> lines [ 0 ] -> remise_percent ,
$deposit -> lines [ 0 ] -> date_start ,
$deposit -> lines [ 0 ] -> date_end ,
$deposit -> lines [ 0 ] -> tva_tx ,
0 ,
0 ,
'HT' ,
$deposit -> lines [ 0 ] -> info_bits ,
$deposit -> lines [ 0 ] -> product_type ,
0 ,
0 ,
0 ,
$deposit -> lines [ 0 ] -> pa_ht ,
$deposit -> lines [ 0 ] -> label ,
0 ,
array (),
100
);
if ( $updatelineResult < 0 ) {
$origin -> db -> rollback ();
$origin -> error = $deposit -> error ;
$origin -> errors = $deposit -> errors ;
return null ;
}
}
if ( ! is_object ( $hookmanager )) {
require_once DOL_DOCUMENT_ROOT . '/core/class/hookmanager.class.php' ;
$hookmanager = new HookManager ( $origin -> db );
}
$hookmanager -> initHooks ( array ( 'invoicedao' ));
$parameters = array ( 'objFrom' => $origin );
$reshook = $hookmanager -> executeHooks ( 'createFrom' , $parameters , $deposit , $action ); // Note that $action and $object may have been
// modified by hook
if ( $reshook < 0 ) {
$origin -> db -> rollback ();
$origin -> error = $hookmanager -> error ;
$origin -> errors = $hookmanager -> errors ;
return null ;
}
if ( ! empty ( $autoValidateDeposit )) {
$validateReturn = $deposit -> validate ( $user , '' , 0 , $notrigger );
if ( $validateReturn < 0 ) {
$origin -> db -> rollback ();
$origin -> error = $deposit -> error ;
$origin -> errors = $deposit -> errors ;
return null ;
}
}
2021-10-04 15:07:27 +02:00
unset ( $deposit -> context [ 'createdepositfromorigin' ]);
2021-09-30 12:41:07 +02:00
$origin -> db -> commit ();
return $deposit ;
}
2018-07-06 08:07:38 +02:00
/**
* Return clicable link of object ( with eventually picto )
*
* @ param int $withpicto Add picto into link
* @ param string $option Where point the link
* @ param int $max Maxlength of ref
* @ param int $short 1 = Return just URL
* @ param string $moretitle Add more text to title tooltip
2020-09-08 21:27:28 +02:00
* @ param int $notooltip 1 = Disable tooltip
* @ param int $addlinktonotes 1 = Add link to notes
* @ param int $save_lastsearch_value - 1 = Auto , 0 = No save of lastsearch_values when clicking , 1 = Save lastsearch_values whenclicking
* @ param string $target Target of link ( '' , '_self' , '_blank' , '_parent' , '_backoffice' , ... )
2018-07-06 08:07:38 +02:00
* @ return string String with URL
*/
2020-09-08 21:27:28 +02:00
public function getNomUrl ( $withpicto = 0 , $option = '' , $max = 0 , $short = 0 , $moretitle = '' , $notooltip = 0 , $addlinktonotes = 0 , $save_lastsearch_value = - 1 , $target = '' )
2018-07-06 08:07:38 +02:00
{
2019-10-14 16:00:03 +02:00
global $langs , $conf , $user , $mysoc ;
2013-04-18 08:40:29 +02:00
2021-02-23 21:09:01 +01:00
if ( ! empty ( $conf -> dol_no_mouse_hover )) {
$notooltip = 1 ; // Force disable tooltips
}
2015-02-26 13:19:19 +01:00
2019-11-08 10:53:31 +01:00
$result = '' ;
2013-05-01 20:40:29 +02:00
2021-02-23 21:09:01 +01:00
if ( $option == 'withdraw' ) {
$url = DOL_URL_ROOT . '/compta/facture/prelevement.php?facid=' . $this -> id ;
} else {
$url = DOL_URL_ROOT . '/compta/facture/card.php?facid=' . $this -> id ;
}
2018-07-05 11:52:41 +02:00
2021-02-23 21:09:01 +01:00
if ( ! $user -> rights -> facture -> lire ) {
2020-09-08 21:27:28 +02:00
$option = 'nolink' ;
2021-02-23 21:09:01 +01:00
}
2018-07-05 11:52:41 +02:00
2021-02-23 21:09:01 +01:00
if ( $option !== 'nolink' ) {
2018-07-06 08:07:38 +02:00
// Add param to save lastsearch_values or not
2019-11-08 10:53:31 +01:00
$add_save_lastsearch_values = ( $save_lastsearch_value == 1 ? 1 : 0 );
2021-02-23 21:09:01 +01:00
if ( $save_lastsearch_value == - 1 && preg_match ( '/list\.php/' , $_SERVER [ " PHP_SELF " ])) {
$add_save_lastsearch_values = 1 ;
}
if ( $add_save_lastsearch_values ) {
$url .= '&save_lastsearch_values=1' ;
}
2018-07-06 08:07:38 +02:00
}
2018-07-05 11:52:41 +02:00
2021-02-23 21:09:01 +01:00
if ( $short ) {
return $url ;
}
2018-09-04 11:23:28 +02:00
2019-11-08 10:53:31 +01:00
$picto = $this -> picto ;
2021-02-23 21:09:01 +01:00
if ( $this -> type == self :: TYPE_REPLACEMENT ) {
$picto .= 'r' ; // Replacement invoice
}
if ( $this -> type == self :: TYPE_CREDIT_NOTE ) {
$picto .= 'a' ; // Credit note
}
if ( $this -> type == self :: TYPE_DEPOSIT ) {
$picto .= 'd' ; // Deposit invoice
}
2020-09-08 21:27:28 +02:00
$label = '' ;
if ( $user -> rights -> facture -> lire ) {
2020-11-29 15:16:53 +01:00
$label = img_picto ( '' , $picto ) . ' <u class="paddingrightonly">' . $langs -> trans ( " Invoice " ) . '</u>' ;
2021-02-23 21:09:01 +01:00
if ( $this -> type == self :: TYPE_REPLACEMENT ) {
$label = img_picto ( '' , $picto ) . ' <u class="paddingrightonly">' . $langs -> transnoentitiesnoconv ( " ReplacementInvoice " ) . '</u>' ;
}
if ( $this -> type == self :: TYPE_CREDIT_NOTE ) {
$label = img_picto ( '' , $picto ) . ' <u class="paddingrightonly">' . $langs -> transnoentitiesnoconv ( " CreditNote " ) . '</u>' ;
}
if ( $this -> type == self :: TYPE_DEPOSIT ) {
$label = img_picto ( '' , $picto ) . ' <u class="paddingrightonly">' . $langs -> transnoentitiesnoconv ( " Deposit " ) . '</u>' ;
}
if ( $this -> type == self :: TYPE_SITUATION ) {
$label = img_picto ( '' , $picto ) . ' <u class="paddingrightonly">' . $langs -> transnoentitiesnoconv ( " InvoiceSituation " ) . '</u>' ;
}
2020-11-02 11:41:07 +01:00
if ( isset ( $this -> statut ) && isset ( $this -> alreadypaid )) {
$label .= ' ' . $this -> getLibStatut ( 5 , $this -> alreadypaid );
}
2021-02-23 21:09:01 +01:00
if ( ! empty ( $this -> ref )) {
2020-09-08 21:27:28 +02:00
$label .= '<br><b>' . $langs -> trans ( 'Ref' ) . ':</b> ' . $this -> ref ;
2021-02-23 21:09:01 +01:00
}
if ( ! empty ( $this -> ref_client )) {
2020-09-08 21:27:28 +02:00
$label .= '<br><b>' . $langs -> trans ( 'RefCustomer' ) . ':</b> ' . $this -> ref_client ;
2021-02-23 21:09:01 +01:00
}
if ( ! empty ( $this -> date )) {
$label .= '<br><b>' . $langs -> trans ( 'Date' ) . ':</b> ' . dol_print_date ( $this -> date , 'day' );
}
if ( ! empty ( $this -> total_ht )) {
2020-09-08 21:27:28 +02:00
$label .= '<br><b>' . $langs -> trans ( 'AmountHT' ) . ':</b> ' . price ( $this -> total_ht , 0 , $langs , 0 , - 1 , - 1 , $conf -> currency );
2021-02-23 21:09:01 +01:00
}
if ( ! empty ( $this -> total_tva )) {
2020-09-08 21:27:28 +02:00
$label .= '<br><b>' . $langs -> trans ( 'AmountVAT' ) . ':</b> ' . price ( $this -> total_tva , 0 , $langs , 0 , - 1 , - 1 , $conf -> currency );
2021-02-23 21:09:01 +01:00
}
if ( ! empty ( $this -> total_localtax1 ) && $this -> total_localtax1 != 0 ) { // We keep test != 0 because $this->total_localtax1 can be '0.00000000'
2020-09-08 21:27:28 +02:00
$label .= '<br><b>' . $langs -> transcountry ( 'AmountLT1' , $mysoc -> country_code ) . ':</b> ' . price ( $this -> total_localtax1 , 0 , $langs , 0 , - 1 , - 1 , $conf -> currency );
2021-02-23 21:09:01 +01:00
}
if ( ! empty ( $this -> total_localtax2 ) && $this -> total_localtax2 != 0 ) {
2020-09-08 21:27:28 +02:00
$label .= '<br><b>' . $langs -> transcountry ( 'AmountLT2' , $mysoc -> country_code ) . ':</b> ' . price ( $this -> total_localtax2 , 0 , $langs , 0 , - 1 , - 1 , $conf -> currency );
2021-02-23 21:09:01 +01:00
}
if ( ! empty ( $this -> total_ttc )) {
2020-09-08 21:27:28 +02:00
$label .= '<br><b>' . $langs -> trans ( 'AmountTTC' ) . ':</b> ' . price ( $this -> total_ttc , 0 , $langs , 0 , - 1 , - 1 , $conf -> currency );
2021-02-23 21:09:01 +01:00
}
if ( $moretitle ) {
$label .= ' - ' . $moretitle ;
}
2020-09-08 21:27:28 +02:00
}
2018-07-05 11:52:41 +02:00
2019-11-08 10:53:31 +01:00
$linkclose = ( $target ? ' target="' . $target . '"' : '' );
2021-02-23 21:09:01 +01:00
if ( empty ( $notooltip ) && $user -> rights -> facture -> lire ) {
if ( ! empty ( $conf -> global -> MAIN_OPTIMIZEFORTEXTBROWSER )) {
2020-09-08 21:27:28 +02:00
$label = $langs -> trans ( " Invoice " );
$linkclose .= ' alt="' . dol_escape_htmltag ( $label , 1 ) . '"' ;
}
$linkclose .= ' title="' . dol_escape_htmltag ( $label , 1 ) . '"' ;
$linkclose .= ' class="classfortooltip"' ;
2018-07-06 08:07:38 +02:00
}
2020-09-08 21:27:28 +02:00
$linkstart = '<a href="' . $url . '"' ;
$linkstart .= $linkclose . '>' ;
2019-11-08 10:53:31 +01:00
$linkend = '</a>' ;
2018-07-05 11:52:41 +02:00
2020-09-08 21:27:28 +02:00
if ( $option == 'nolink' ) {
$linkstart = '' ;
$linkend = '' ;
}
2018-07-05 11:52:41 +02:00
2018-07-06 08:07:38 +02:00
$result .= $linkstart ;
2021-02-23 21:09:01 +01:00
if ( $withpicto ) {
$result .= img_object (( $notooltip ? '' : $label ), $picto , ( $notooltip ? (( $withpicto != 2 ) ? 'class="paddingright"' : '' ) : 'class="' . (( $withpicto != 2 ) ? 'paddingright ' : '' ) . 'classfortooltip"' ), 0 , 0 , $notooltip ? 0 : 1 );
}
if ( $withpicto != 2 ) {
$result .= ( $max ? dol_trunc ( $this -> ref , $max ) : $this -> ref );
}
2018-07-06 08:07:38 +02:00
$result .= $linkend ;
2021-02-23 21:09:01 +01:00
if ( $addlinktonotes ) {
2020-09-08 21:27:28 +02:00
$txttoshow = ( $user -> socid > 0 ? $this -> note_public : $this -> note_private );
2021-02-23 21:09:01 +01:00
if ( $txttoshow ) {
2020-09-08 21:27:28 +02:00
//$notetoshow = $langs->trans("ViewPrivateNote").':<br>'.dol_string_nohtmltag($txttoshow, 1);
$notetoshow = $langs -> trans ( " ViewPrivateNote " ) . ':<br>' . $txttoshow ;
$result .= ' <span class="note inline-block">' ;
$result .= '<a href="' . DOL_URL_ROOT . '/compta/facture/note.php?id=' . $this -> id . '" class="classfortooltip" title="' . dol_escape_htmltag ( $notetoshow , 1 , 1 ) . '">' ;
$result .= img_picto ( '' , 'note' );
$result .= '</a>' ;
//$result.=img_picto($langs->trans("ViewNote"),'object_generic');
//$result.='</a>';
$result .= '</span>' ;
}
2018-07-06 08:07:38 +02:00
}
2021-03-18 11:16:49 +01:00
global $action , $hookmanager ;
2021-03-18 10:43:26 +01:00
$hookmanager -> initHooks ( array ( 'invoicedao' ));
2021-11-22 19:57:26 +01:00
$parameters = array ( 'id' => $this -> id , 'getnomurl' => & $result , 'notooltip' => $notooltip , 'addlinktonotes' => $addlinktonotes , 'save_lastsearch_value' => $save_lastsearch_value , 'target' => $target );
2021-03-18 10:43:26 +01:00
$reshook = $hookmanager -> executeHooks ( 'getNomUrl' , $parameters , $this , $action ); // Note that $action and $object may have been modified by some hooks
2021-10-25 22:07:31 +02:00
if ( $reshook > 0 ) {
$result = $hookmanager -> resPrint ;
} else {
$result .= $hookmanager -> resPrint ;
}
2021-03-18 10:43:26 +01:00
2018-07-06 08:07:38 +02:00
return $result ;
}
/**
2020-02-10 00:22:53 +01:00
* Get object from database . Get also lines .
2018-07-06 08:07:38 +02:00
*
2020-03-06 14:38:06 +01:00
* @ param int $rowid Id of object to load
* @ param string $ref Reference of invoice
* @ param string $ref_ext External reference of invoice
* @ param int $notused Not used
2021-03-18 20:27:36 +01:00
* @ param bool $fetch_situation Load also the previous and next situation invoice into $tab_previous_situation_invoice and $tab_next_situation_invoice
2020-03-06 14:38:06 +01:00
* @ return int > 0 if OK , < 0 if KO , 0 if not found
2018-07-06 08:07:38 +02:00
*/
2020-03-06 14:38:06 +01:00
public function fetch ( $rowid , $ref = '' , $ref_ext = '' , $notused = '' , $fetch_situation = false )
2018-07-06 08:07:38 +02:00
{
2021-02-23 21:09:01 +01:00
if ( empty ( $rowid ) && empty ( $ref ) && empty ( $ref_ext )) {
return - 1 ;
}
2018-07-06 08:07:38 +02:00
2020-01-31 15:12:17 +01:00
$sql = 'SELECT f.rowid,f.entity,f.ref,f.ref_client,f.ref_ext,f.ref_int,f.type,f.fk_soc' ;
2021-02-22 05:58:46 +01:00
$sql .= ', f.total_tva, f.localtax1, f.localtax2, f.total_ht, f.total_ttc, f.revenuestamp' ;
2019-11-08 10:53:31 +01:00
$sql .= ', f.remise_percent, f.remise_absolue, f.remise' ;
$sql .= ', f.datef as df, f.date_pointoftax' ;
$sql .= ', f.date_lim_reglement as dlr' ;
$sql .= ', f.datec as datec' ;
$sql .= ', f.date_valid as datev' ;
$sql .= ', f.tms as datem' ;
2022-06-27 10:45:04 +02:00
$sql .= ', f.note_private, f.note_public, f.fk_statut, f.paye, f.close_code, f.close_note, f.fk_user_author, f.fk_user_valid, f.fk_user_modif, f.model_pdf, f.last_main_doc' ;
2019-11-08 10:53:31 +01:00
$sql .= ', f.fk_facture_source, f.fk_fac_rec_source' ;
$sql .= ', f.fk_mode_reglement, f.fk_cond_reglement, f.fk_projet as fk_project, f.extraparams' ;
$sql .= ', f.situation_cycle_ref, f.situation_counter, f.situation_final' ;
$sql .= ', f.fk_account' ;
$sql .= " , f.fk_multicurrency, f.multicurrency_code, f.multicurrency_tx, f.multicurrency_total_ht, f.multicurrency_total_tva, f.multicurrency_total_ttc " ;
$sql .= ', p.code as mode_reglement_code, p.libelle as mode_reglement_libelle' ;
$sql .= ', c.code as cond_reglement_code, c.libelle as cond_reglement_libelle, c.libelle_facture as cond_reglement_libelle_doc' ;
2020-09-08 21:27:28 +02:00
$sql .= ', f.fk_incoterms, f.location_incoterms' ;
$sql .= ', f.module_source, f.pos_source' ;
$sql .= " , i.libelle as label_incoterms " ;
$sql .= " , f.retained_warranty as retained_warranty, f.retained_warranty_date_limit as retained_warranty_date_limit, f.retained_warranty_fk_cond_reglement as retained_warranty_fk_cond_reglement " ;
2019-11-08 10:53:31 +01:00
$sql .= ' FROM ' . MAIN_DB_PREFIX . 'facture as f' ;
$sql .= ' LEFT JOIN ' . MAIN_DB_PREFIX . 'c_payment_term as c ON f.fk_cond_reglement = c.rowid' ;
$sql .= ' LEFT JOIN ' . MAIN_DB_PREFIX . 'c_paiement as p ON f.fk_mode_reglement = p.id' ;
$sql .= ' LEFT JOIN ' . MAIN_DB_PREFIX . 'c_incoterms as i ON f.fk_incoterms = i.rowid' ;
2021-02-23 21:09:01 +01:00
if ( $rowid ) {
2021-04-24 20:18:11 +02:00
$sql .= " WHERE f.rowid= " . (( int ) $rowid );
2021-02-23 21:09:01 +01:00
} else {
2022-01-09 21:08:06 +01:00
$sql .= ' WHERE f.entity IN (' . getEntity ( 'invoice' ) . ')' ; // Don't use entity if you use rowid
2021-02-23 21:09:01 +01:00
if ( $ref ) {
$sql .= " AND f.ref=' " . $this -> db -> escape ( $ref ) . " ' " ;
}
if ( $ref_ext ) {
$sql .= " AND f.ref_ext=' " . $this -> db -> escape ( $ref_ext ) . " ' " ;
}
if ( $notused ) {
$sql .= " AND f.ref_int=' " . $this -> db -> escape ( $notused ) . " ' " ; // deprecated
}
2019-12-16 22:30:16 +01:00
}
2018-07-06 08:07:38 +02:00
dol_syslog ( get_class ( $this ) . " ::fetch " , LOG_DEBUG );
2021-08-24 08:20:40 +02:00
$resql = $this -> db -> query ( $sql );
if ( $resql ) {
if ( $this -> db -> num_rows ( $resql )) {
$obj = $this -> db -> fetch_object ( $resql );
2018-07-06 08:07:38 +02:00
2019-11-08 10:53:31 +01:00
$this -> id = $obj -> rowid ;
$this -> entity = $obj -> entity ;
2018-07-06 08:07:38 +02:00
2022-09-04 04:59:31 +02:00
$this -> ref = $obj -> ref ;
$this -> ref_client = $obj -> ref_client ;
$this -> ref_customer = $obj -> ref_client ;
2018-07-06 08:07:38 +02:00
$this -> ref_ext = $obj -> ref_ext ;
$this -> type = $obj -> type ;
$this -> date = $this -> db -> jdate ( $obj -> df );
$this -> date_pointoftax = $this -> db -> jdate ( $obj -> date_pointoftax );
2019-11-08 10:53:31 +01:00
$this -> date_creation = $this -> db -> jdate ( $obj -> datec );
2018-07-06 08:07:38 +02:00
$this -> date_validation = $this -> db -> jdate ( $obj -> datev );
2019-11-08 10:53:31 +01:00
$this -> date_modification = $this -> db -> jdate ( $obj -> datem );
$this -> datem = $this -> db -> jdate ( $obj -> datem );
2018-07-06 08:07:38 +02:00
$this -> remise_percent = $obj -> remise_percent ;
$this -> remise_absolue = $obj -> remise_absolue ;
2021-02-22 05:58:46 +01:00
$this -> total_ht = $obj -> total_ht ;
$this -> total_tva = $obj -> total_tva ;
2018-07-06 08:07:38 +02:00
$this -> total_localtax1 = $obj -> localtax1 ;
$this -> total_localtax2 = $obj -> localtax2 ;
$this -> total_ttc = $obj -> total_ttc ;
2019-11-08 10:53:31 +01:00
$this -> revenuestamp = $obj -> revenuestamp ;
2020-02-13 12:36:05 +01:00
$this -> paye = $obj -> paye ;
2018-07-06 08:07:38 +02:00
$this -> close_code = $obj -> close_code ;
$this -> close_note = $obj -> close_note ;
2020-02-10 00:22:53 +01:00
$this -> socid = $obj -> fk_soc ;
2020-02-13 12:36:05 +01:00
$this -> thirdparty = null ; // Clear if another value was already set by fetch_thirdparty
2020-02-10 00:22:53 +01:00
$this -> fk_project = $obj -> fk_project ;
2020-02-13 12:36:05 +01:00
$this -> project = null ; // Clear if another value was already set by fetch_projet
2020-02-10 00:22:53 +01:00
2019-11-08 10:53:31 +01:00
$this -> statut = $obj -> fk_statut ;
2021-02-02 16:12:03 +01:00
$this -> status = $obj -> fk_statut ;
2019-11-08 10:53:31 +01:00
$this -> date_lim_reglement = $this -> db -> jdate ( $obj -> dlr );
2018-07-06 08:07:38 +02:00
$this -> mode_reglement_id = $obj -> fk_mode_reglement ;
$this -> mode_reglement_code = $obj -> mode_reglement_code ;
$this -> mode_reglement = $obj -> mode_reglement_libelle ;
$this -> cond_reglement_id = $obj -> fk_cond_reglement ;
$this -> cond_reglement_code = $obj -> cond_reglement_code ;
$this -> cond_reglement = $obj -> cond_reglement_libelle ;
2019-11-08 10:53:31 +01:00
$this -> cond_reglement_doc = $obj -> cond_reglement_libelle_doc ;
$this -> fk_account = ( $obj -> fk_account > 0 ) ? $obj -> fk_account : null ;
2018-07-06 08:07:38 +02:00
$this -> fk_facture_source = $obj -> fk_facture_source ;
2019-06-05 08:08:31 +02:00
$this -> fk_fac_rec_source = $obj -> fk_fac_rec_source ;
2019-11-08 10:53:31 +01:00
$this -> note = $obj -> note_private ; // deprecated
$this -> note_private = $obj -> note_private ;
2018-07-06 08:07:38 +02:00
$this -> note_public = $obj -> note_public ;
2021-06-14 15:37:02 +02:00
$this -> user_author = $obj -> fk_user_author ; // deprecated
$this -> user_valid = $obj -> fk_user_valid ; // deprecated
2022-06-27 10:45:04 +02:00
$this -> user_modification = $obj -> fk_user_modif ; // deprecated
$this -> fk_user_author = $obj -> fk_user_author ;
2020-12-13 13:34:21 +01:00
$this -> fk_user_valid = $obj -> fk_user_valid ;
2022-06-27 10:45:04 +02:00
$this -> fk_user_modif = $obj -> fk_user_modif ;
2020-08-18 14:48:38 +02:00
$this -> model_pdf = $obj -> model_pdf ;
2020-10-31 14:32:18 +01:00
$this -> modelpdf = $obj -> model_pdf ; // deprecated
2019-11-08 10:53:31 +01:00
$this -> last_main_doc = $obj -> last_main_doc ;
2018-07-06 08:07:38 +02:00
$this -> situation_cycle_ref = $obj -> situation_cycle_ref ;
$this -> situation_counter = $obj -> situation_counter ;
$this -> situation_final = $obj -> situation_final ;
2018-08-10 15:06:00 +02:00
$this -> retained_warranty = $obj -> retained_warranty ;
$this -> retained_warranty_date_limit = $this -> db -> jdate ( $obj -> retained_warranty_date_limit );
$this -> retained_warranty_fk_cond_reglement = $obj -> retained_warranty_fk_cond_reglement ;
2019-09-03 16:23:39 +02:00
2019-11-08 10:53:31 +01:00
$this -> extraparams = ( array ) json_decode ( $obj -> extraparams , true );
2018-07-06 08:07:38 +02:00
//Incoterms
2019-02-20 12:35:13 +01:00
$this -> fk_incoterms = $obj -> fk_incoterms ;
$this -> location_incoterms = $obj -> location_incoterms ;
2019-11-08 10:53:31 +01:00
$this -> label_incoterms = $obj -> label_incoterms ;
2019-02-23 16:03:40 +01:00
2021-02-23 21:09:01 +01:00
$this -> module_source = $obj -> module_source ;
2019-11-08 10:53:31 +01:00
$this -> pos_source = $obj -> pos_source ;
2018-07-06 08:07:38 +02:00
// Multicurrency
$this -> fk_multicurrency = $obj -> fk_multicurrency ;
2019-11-08 10:53:31 +01:00
$this -> multicurrency_code = $obj -> multicurrency_code ;
2018-07-06 08:07:38 +02:00
$this -> multicurrency_tx = $obj -> multicurrency_tx ;
2019-11-08 10:53:31 +01:00
$this -> multicurrency_total_ht = $obj -> multicurrency_total_ht ;
2018-07-06 08:07:38 +02:00
$this -> multicurrency_total_tva = $obj -> multicurrency_total_tva ;
$this -> multicurrency_total_ttc = $obj -> multicurrency_total_ttc ;
2021-02-23 21:09:01 +01:00
if (( $this -> type == self :: TYPE_SITUATION || ( $this -> type == self :: TYPE_CREDIT_NOTE && $this -> situation_cycle_ref > 0 )) && $fetch_situation ) {
2018-07-06 08:07:38 +02:00
$this -> fetchPreviousNextSituationInvoice ();
}
2021-03-08 09:14:23 +01:00
if ( $this -> status == self :: STATUS_DRAFT ) {
2021-02-23 21:09:01 +01:00
$this -> brouillon = 1 ;
}
2018-07-06 08:07:38 +02:00
2020-10-23 20:08:35 +02:00
// Retrieve all extrafield
2018-07-06 08:07:38 +02:00
// fetch optionals attributes and labels
$this -> fetch_optionals ();
2020-02-10 00:22:53 +01:00
// Lines
2019-11-08 10:53:31 +01:00
$this -> lines = array ();
2018-07-06 08:07:38 +02:00
2019-11-08 10:53:31 +01:00
$result = $this -> fetch_lines ();
2021-02-23 21:09:01 +01:00
if ( $result < 0 ) {
2019-11-08 10:53:31 +01:00
$this -> error = $this -> db -> error ();
2018-07-06 08:07:38 +02:00
return - 3 ;
}
2021-08-24 08:20:40 +02:00
$this -> db -> free ( $resql );
2018-07-06 08:07:38 +02:00
return 1 ;
2020-05-21 15:05:19 +02:00
} else {
2019-11-08 10:53:31 +01:00
$this -> error = 'Invoice with id=' . $rowid . ' or ref=' . $ref . ' or ref_ext=' . $ref_ext . ' not found' ;
2021-08-28 20:14:23 +02:00
2021-08-31 20:18:28 +02:00
dol_syslog ( __METHOD__ . $this -> error , LOG_WARNING );
2018-07-06 08:07:38 +02:00
return 0 ;
}
2020-05-21 15:05:19 +02:00
} else {
2021-08-24 08:20:40 +02:00
$this -> error = $this -> db -> lasterror ();
2018-07-06 08:07:38 +02:00
return - 1 ;
}
}
2020-09-08 21:27:28 +02:00
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2018-07-06 08:07:38 +02:00
/**
* Load all detailed lines into this -> lines
*
2019-06-25 18:14:56 +02:00
* @ param int $only_product Return only physical products
* @ param int $loadalsotranslation Return translation for products
*
2018-07-06 08:07:38 +02:00
* @ return int 1 if OK , < 0 if KO
*/
2019-06-25 15:46:12 +02:00
public function fetch_lines ( $only_product = 0 , $loadalsotranslation = 0 )
2018-07-06 08:07:38 +02:00
{
2020-09-08 21:27:28 +02:00
// phpcs:enable
2022-03-28 13:50:47 +02:00
global $langs , $conf ;
2019-11-08 10:53:31 +01:00
$this -> lines = array ();
2018-07-06 08:07:38 +02:00
$sql = 'SELECT l.rowid, l.fk_facture, l.fk_product, l.fk_parent_line, l.label as custom_label, l.description, l.product_type, l.price, l.qty, l.vat_src_code, l.tva_tx,' ;
2020-09-04 19:32:42 +02:00
$sql .= ' l.localtax1_tx, l.localtax2_tx, l.localtax1_type, l.localtax2_type, l.remise_percent, l.fk_remise_except, l.subprice, l.ref_ext,' ;
2020-03-23 15:02:15 +01:00
$sql .= ' l.situation_percent, l.fk_prev_id,' ;
2019-11-08 10:53:31 +01:00
$sql .= ' l.rang, l.special_code,' ;
$sql .= ' l.date_start as date_start, l.date_end as date_end,' ;
$sql .= ' l.info_bits, l.total_ht, l.total_tva, l.total_localtax1, l.total_localtax2, l.total_ttc, l.fk_code_ventilation, l.fk_product_fournisseur_price as fk_fournprice, l.buy_price_ht as pa_ht,' ;
$sql .= ' l.fk_unit,' ;
$sql .= ' l.fk_multicurrency, l.multicurrency_code, l.multicurrency_subprice, l.multicurrency_total_ht, l.multicurrency_total_tva, l.multicurrency_total_ttc,' ;
$sql .= ' p.ref as product_ref, p.fk_product_type as fk_product_type, p.label as product_label, p.description as product_desc' ;
$sql .= ' FROM ' . MAIN_DB_PREFIX . 'facturedet as l' ;
$sql .= ' LEFT JOIN ' . MAIN_DB_PREFIX . 'product as p ON l.fk_product = p.rowid' ;
2021-08-27 23:36:06 +02:00
$sql .= ' WHERE l.fk_facture = ' . (( int ) $this -> id );
2019-11-08 10:53:31 +01:00
$sql .= ' ORDER BY l.rang, l.rowid' ;
2018-07-06 08:07:38 +02:00
dol_syslog ( get_class ( $this ) . '::fetch_lines' , LOG_DEBUG );
$result = $this -> db -> query ( $sql );
2021-02-23 21:09:01 +01:00
if ( $result ) {
2018-07-06 08:07:38 +02:00
$num = $this -> db -> num_rows ( $result );
$i = 0 ;
2021-02-23 21:09:01 +01:00
while ( $i < $num ) {
2018-07-06 08:07:38 +02:00
$objp = $this -> db -> fetch_object ( $result );
$line = new FactureLigne ( $this -> db );
$line -> id = $objp -> rowid ;
2019-11-08 10:53:31 +01:00
$line -> rowid = $objp -> rowid ; // deprecated
2018-07-06 08:07:38 +02:00
$line -> fk_facture = $objp -> fk_facture ;
2019-11-08 10:53:31 +01:00
$line -> label = $objp -> custom_label ; // deprecated
$line -> desc = $objp -> description ; // Description line
$line -> description = $objp -> description ; // Description line
$line -> product_type = $objp -> product_type ; // Type of line
$line -> ref = $objp -> product_ref ; // Ref product
$line -> product_ref = $objp -> product_ref ; // Ref product
$line -> libelle = $objp -> product_label ; // deprecated
$line -> product_label = $objp -> product_label ; // Label product
$line -> product_desc = $objp -> product_desc ; // Description product
$line -> fk_product_type = $objp -> fk_product_type ; // Type of product
2018-07-06 08:07:38 +02:00
$line -> qty = $objp -> qty ;
$line -> subprice = $objp -> subprice ;
2020-09-04 19:32:42 +02:00
$line -> ref_ext = $objp -> ref_ext ; // line external ref
2018-07-06 08:07:38 +02:00
2020-09-08 21:27:28 +02:00
$line -> vat_src_code = $objp -> vat_src_code ;
2018-07-06 08:07:38 +02:00
$line -> tva_tx = $objp -> tva_tx ;
$line -> localtax1_tx = $objp -> localtax1_tx ;
$line -> localtax2_tx = $objp -> localtax2_tx ;
$line -> localtax1_type = $objp -> localtax1_type ;
$line -> localtax2_type = $objp -> localtax2_type ;
$line -> remise_percent = $objp -> remise_percent ;
$line -> fk_remise_except = $objp -> fk_remise_except ;
$line -> fk_product = $objp -> fk_product ;
$line -> date_start = $this -> db -> jdate ( $objp -> date_start );
$line -> date_end = $this -> db -> jdate ( $objp -> date_end );
$line -> date_start = $this -> db -> jdate ( $objp -> date_start );
$line -> date_end = $this -> db -> jdate ( $objp -> date_end );
$line -> info_bits = $objp -> info_bits ;
$line -> total_ht = $objp -> total_ht ;
$line -> total_tva = $objp -> total_tva ;
$line -> total_localtax1 = $objp -> total_localtax1 ;
$line -> total_localtax2 = $objp -> total_localtax2 ;
$line -> total_ttc = $objp -> total_ttc ;
$line -> code_ventilation = $objp -> fk_code_ventilation ;
2019-11-08 10:53:31 +01:00
$line -> fk_fournprice = $objp -> fk_fournprice ;
$marginInfos = getMarginInfos ( $objp -> subprice , $objp -> remise_percent , $objp -> tva_tx , $objp -> localtax1_tx , $objp -> localtax2_tx , $line -> fk_fournprice , $objp -> pa_ht );
$line -> pa_ht = $marginInfos [ 0 ];
2018-07-06 08:07:38 +02:00
$line -> marge_tx = $marginInfos [ 1 ];
$line -> marque_tx = $marginInfos [ 2 ];
2019-11-08 10:53:31 +01:00
$line -> rang = $objp -> rang ;
$line -> special_code = $objp -> special_code ;
$line -> fk_parent_line = $objp -> fk_parent_line ;
$line -> situation_percent = $objp -> situation_percent ;
2020-01-30 01:48:28 +01:00
$line -> fk_prev_id = $objp -> fk_prev_id ;
2019-11-08 10:53:31 +01:00
$line -> fk_unit = $objp -> fk_unit ;
2018-07-06 08:07:38 +02:00
// Accountancy
2019-11-08 10:53:31 +01:00
$line -> fk_accounting_account = $objp -> fk_code_ventilation ;
2018-07-06 08:07:38 +02:00
// Multicurrency
2019-11-08 10:53:31 +01:00
$line -> fk_multicurrency = $objp -> fk_multicurrency ;
$line -> multicurrency_code = $objp -> multicurrency_code ;
2018-07-06 08:07:38 +02:00
$line -> multicurrency_subprice = $objp -> multicurrency_subprice ;
$line -> multicurrency_total_ht = $objp -> multicurrency_total_ht ;
$line -> multicurrency_total_tva = $objp -> multicurrency_total_tva ;
$line -> multicurrency_total_ttc = $objp -> multicurrency_total_ttc ;
2020-09-08 21:27:28 +02:00
$line -> fetch_optionals ();
2019-06-29 16:29:32 +02:00
2019-06-25 15:46:12 +02:00
// multilangs
2020-09-08 21:27:28 +02:00
if ( ! empty ( $conf -> global -> MAIN_MULTILANGS ) && ! empty ( $objp -> fk_product ) && ! empty ( $loadalsotranslation )) {
2022-05-18 23:52:43 +02:00
$tmpproduct = new Product ( $this -> db );
$tmpproduct -> fetch ( $objp -> fk_product );
$tmpproduct -> getMultiLangs ();
$line -> multilangs = $tmpproduct -> multilangs ;
2020-09-08 21:27:28 +02:00
}
2018-07-06 08:07:38 +02:00
$this -> lines [ $i ] = $line ;
$i ++ ;
}
$this -> db -> free ( $result );
return 1 ;
2020-05-21 15:05:19 +02:00
} else {
2019-11-08 10:53:31 +01:00
$this -> error = $this -> db -> error ();
2018-07-06 08:07:38 +02:00
return - 3 ;
}
}
/**
2020-06-07 18:30:46 +02:00
* Fetch previous and next situations invoices .
* Return all previous and next invoices ( both standard and credit notes ) .
2018-07-06 08:07:38 +02:00
*
* @ return void
*/
2020-09-08 21:27:28 +02:00
public function fetchPreviousNextSituationInvoice ()
2018-07-06 08:07:38 +02:00
{
global $conf ;
$this -> tab_previous_situation_invoice = array ();
$this -> tab_next_situation_invoice = array ();
2020-06-07 18:59:49 +02:00
$sql = 'SELECT rowid, type, situation_cycle_ref, situation_counter FROM ' . MAIN_DB_PREFIX . 'facture' ;
2021-08-27 23:36:06 +02:00
$sql .= " WHERE rowid <> " . (( int ) $this -> id );
$sql .= ' AND entity = ' . (( int ) $this -> entity );
2019-11-08 10:53:31 +01:00
$sql .= ' AND situation_cycle_ref = ' . ( int ) $this -> situation_cycle_ref ;
$sql .= ' ORDER BY situation_counter ASC' ;
2018-07-06 08:07:38 +02:00
dol_syslog ( get_class ( $this ) . '::fetchPreviousNextSituationInvoice ' , LOG_DEBUG );
$result = $this -> db -> query ( $sql );
2021-02-23 21:09:01 +01:00
if ( $result && $this -> db -> num_rows ( $result ) > 0 ) {
while ( $objp = $this -> db -> fetch_object ( $result )) {
2018-07-06 08:07:38 +02:00
$invoice = new Facture ( $this -> db );
2021-02-23 21:09:01 +01:00
if ( $invoice -> fetch ( $objp -> rowid ) > 0 ) {
2020-09-08 21:27:28 +02:00
if ( $objp -> situation_counter < $this -> situation_counter
|| ( $objp -> situation_counter == $this -> situation_counter && $objp -> rowid < $this -> id ) // This case appear when there are credit notes
2021-02-23 21:09:01 +01:00
) {
2020-09-08 21:27:28 +02:00
$this -> tab_previous_situation_invoice [] = $invoice ;
2020-05-21 15:05:19 +02:00
} else {
2020-09-08 21:27:28 +02:00
$this -> tab_next_situation_invoice [] = $invoice ;
2018-07-06 08:07:38 +02:00
}
}
}
}
}
/**
* Update database
*
* @ param User $user User that modify
* @ param int $notrigger 0 = launch triggers after , 1 = disable triggers
* @ return int < 0 if KO , > 0 if OK
*/
2020-09-08 21:27:28 +02:00
public function update ( User $user , $notrigger = 0 )
2018-07-06 08:07:38 +02:00
{
2018-08-12 16:29:26 +02:00
global $conf ;
2019-11-08 10:53:31 +01:00
$error = 0 ;
2018-07-06 08:07:38 +02:00
// Clean parameters
2021-02-23 21:09:01 +01:00
if ( empty ( $this -> type )) {
$this -> type = self :: TYPE_STANDARD ;
}
if ( isset ( $this -> ref )) {
$this -> ref = trim ( $this -> ref );
}
if ( isset ( $this -> ref_ext )) {
$this -> ref_ext = trim ( $this -> ref_ext );
}
if ( isset ( $this -> ref_client )) {
$this -> ref_client = trim ( $this -> ref_client );
}
if ( isset ( $this -> increment )) {
$this -> increment = trim ( $this -> increment );
}
if ( isset ( $this -> close_code )) {
$this -> close_code = trim ( $this -> close_code );
}
if ( isset ( $this -> close_note )) {
$this -> close_note = trim ( $this -> close_note );
}
if ( isset ( $this -> note ) || isset ( $this -> note_private )) {
$this -> note = ( isset ( $this -> note ) ? trim ( $this -> note ) : trim ( $this -> note_private )); // deprecated
}
if ( isset ( $this -> note ) || isset ( $this -> note_private )) {
$this -> note_private = ( isset ( $this -> note_private ) ? trim ( $this -> note_private ) : trim ( $this -> note ));
}
if ( isset ( $this -> note_public )) {
$this -> note_public = trim ( $this -> note_public );
}
if ( isset ( $this -> model_pdf )) {
$this -> model_pdf = trim ( $this -> model_pdf );
}
if ( isset ( $this -> import_key )) {
$this -> import_key = trim ( $this -> import_key );
}
if ( isset ( $this -> retained_warranty )) {
$this -> retained_warranty = floatval ( $this -> retained_warranty );
}
2019-09-03 16:23:39 +02:00
2018-07-06 08:07:38 +02:00
// Check parameters
// Put here code to add control on parameters values
// Update request
$sql = " UPDATE " . MAIN_DB_PREFIX . " facture SET " ;
2019-11-08 10:53:31 +01:00
$sql .= " ref= " . ( isset ( $this -> ref ) ? " ' " . $this -> db -> escape ( $this -> ref ) . " ' " : " null " ) . " , " ;
2020-09-04 17:54:25 +02:00
$sql .= " ref_ext= " . ( isset ( $this -> ref_ext ) ? " ' " . $this -> db -> escape ( $this -> ref_ext ) . " ' " : " null " ) . " , " ;
2019-11-08 10:53:31 +01:00
$sql .= " type= " . ( isset ( $this -> type ) ? $this -> db -> escape ( $this -> type ) : " null " ) . " , " ;
$sql .= " ref_client= " . ( isset ( $this -> ref_client ) ? " ' " . $this -> db -> escape ( $this -> ref_client ) . " ' " : " null " ) . " , " ;
$sql .= " increment= " . ( isset ( $this -> increment ) ? " ' " . $this -> db -> escape ( $this -> increment ) . " ' " : " null " ) . " , " ;
$sql .= " fk_soc= " . ( isset ( $this -> socid ) ? $this -> db -> escape ( $this -> socid ) : " null " ) . " , " ;
$sql .= " datec= " . ( strval ( $this -> date_creation ) != '' ? " ' " . $this -> db -> idate ( $this -> date_creation ) . " ' " : 'null' ) . " , " ;
$sql .= " datef= " . ( strval ( $this -> date ) != '' ? " ' " . $this -> db -> idate ( $this -> date ) . " ' " : 'null' ) . " , " ;
$sql .= " date_pointoftax= " . ( strval ( $this -> date_pointoftax ) != '' ? " ' " . $this -> db -> idate ( $this -> date_pointoftax ) . " ' " : 'null' ) . " , " ;
$sql .= " date_valid= " . ( strval ( $this -> date_validation ) != '' ? " ' " . $this -> db -> idate ( $this -> date_validation ) . " ' " : 'null' ) . " , " ;
$sql .= " paye= " . ( isset ( $this -> paye ) ? $this -> db -> escape ( $this -> paye ) : 0 ) . " , " ;
$sql .= " remise_percent= " . ( isset ( $this -> remise_percent ) ? $this -> db -> escape ( $this -> remise_percent ) : " null " ) . " , " ;
$sql .= " remise_absolue= " . ( isset ( $this -> remise_absolue ) ? $this -> db -> escape ( $this -> remise_absolue ) : " null " ) . " , " ;
$sql .= " close_code= " . ( isset ( $this -> close_code ) ? " ' " . $this -> db -> escape ( $this -> close_code ) . " ' " : " null " ) . " , " ;
$sql .= " close_note= " . ( isset ( $this -> close_note ) ? " ' " . $this -> db -> escape ( $this -> close_note ) . " ' " : " null " ) . " , " ;
2021-02-22 05:58:46 +01:00
$sql .= " total_tva= " . ( isset ( $this -> total_tva ) ? $this -> total_tva : " null " ) . " , " ;
2019-11-08 10:53:31 +01:00
$sql .= " localtax1= " . ( isset ( $this -> total_localtax1 ) ? $this -> total_localtax1 : " null " ) . " , " ;
$sql .= " localtax2= " . ( isset ( $this -> total_localtax2 ) ? $this -> total_localtax2 : " null " ) . " , " ;
2021-02-22 05:58:46 +01:00
$sql .= " total_ht= " . ( isset ( $this -> total_ht ) ? $this -> total_ht : " null " ) . " , " ;
2019-11-08 10:53:31 +01:00
$sql .= " total_ttc= " . ( isset ( $this -> total_ttc ) ? $this -> total_ttc : " null " ) . " , " ;
$sql .= " revenuestamp= " . (( isset ( $this -> revenuestamp ) && $this -> revenuestamp != '' ) ? $this -> db -> escape ( $this -> revenuestamp ) : " null " ) . " , " ;
$sql .= " fk_statut= " . ( isset ( $this -> statut ) ? $this -> db -> escape ( $this -> statut ) : " null " ) . " , " ;
$sql .= " fk_user_author= " . ( isset ( $this -> user_author ) ? $this -> db -> escape ( $this -> user_author ) : " null " ) . " , " ;
$sql .= " fk_user_valid= " . ( isset ( $this -> fk_user_valid ) ? $this -> db -> escape ( $this -> fk_user_valid ) : " null " ) . " , " ;
$sql .= " fk_facture_source= " . ( isset ( $this -> fk_facture_source ) ? $this -> db -> escape ( $this -> fk_facture_source ) : " null " ) . " , " ;
$sql .= " fk_projet= " . ( isset ( $this -> fk_project ) ? $this -> db -> escape ( $this -> fk_project ) : " null " ) . " , " ;
$sql .= " fk_cond_reglement= " . ( isset ( $this -> cond_reglement_id ) ? $this -> db -> escape ( $this -> cond_reglement_id ) : " null " ) . " , " ;
$sql .= " fk_mode_reglement= " . ( isset ( $this -> mode_reglement_id ) ? $this -> db -> escape ( $this -> mode_reglement_id ) : " null " ) . " , " ;
$sql .= " date_lim_reglement= " . ( strval ( $this -> date_lim_reglement ) != '' ? " ' " . $this -> db -> idate ( $this -> date_lim_reglement ) . " ' " : '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 " ) . " , " ;
2020-12-13 13:34:21 +01:00
$sql .= " model_pdf= " . ( isset ( $this -> model_pdf ) ? " ' " . $this -> db -> escape ( $this -> model_pdf ) . " ' " : " null " ) . " , " ;
2019-11-08 10:53:31 +01:00
$sql .= " import_key= " . ( isset ( $this -> import_key ) ? " ' " . $this -> db -> escape ( $this -> import_key ) . " ' " : " null " ) . " , " ;
$sql .= " situation_cycle_ref= " . ( empty ( $this -> situation_cycle_ref ) ? " null " : $this -> db -> escape ( $this -> situation_cycle_ref )) . " , " ;
$sql .= " situation_counter= " . ( empty ( $this -> situation_counter ) ? " null " : $this -> db -> escape ( $this -> situation_counter )) . " , " ;
$sql .= " situation_final= " . ( empty ( $this -> situation_final ) ? " 0 " : $this -> db -> escape ( $this -> situation_final )) . " , " ;
$sql .= " retained_warranty= " . ( empty ( $this -> retained_warranty ) ? " 0 " : $this -> db -> escape ( $this -> retained_warranty )) . " , " ;
$sql .= " retained_warranty_date_limit= " . ( strval ( $this -> retained_warranty_date_limit ) != '' ? " ' " . $this -> db -> idate ( $this -> retained_warranty_date_limit ) . " ' " : 'null' ) . " , " ;
$sql .= " retained_warranty_fk_cond_reglement= " . ( isset ( $this -> retained_warranty_fk_cond_reglement ) ? intval ( $this -> retained_warranty_fk_cond_reglement ) : " null " );
2021-03-14 12:20:23 +01:00
$sql .= " WHERE rowid= " . (( int ) $this -> id );
2018-07-06 08:07:38 +02:00
$this -> db -> begin ();
dol_syslog ( get_class ( $this ) . " ::update " , LOG_DEBUG );
$resql = $this -> db -> query ( $sql );
2019-11-08 10:53:31 +01:00
if ( ! $resql ) {
2021-03-01 20:37:16 +01:00
$error ++ ;
$this -> errors [] = " Error " . $this -> db -> lasterror ();
2018-07-06 08:07:38 +02:00
}
2021-02-23 21:09:01 +01:00
if ( ! $error ) {
2019-11-08 10:53:31 +01:00
$result = $this -> insertExtraFields ();
2021-02-23 21:09:01 +01:00
if ( $result < 0 ) {
2018-08-12 16:29:26 +02:00
$error ++ ;
2018-07-06 08:07:38 +02:00
}
}
2021-02-23 21:09:01 +01:00
if ( ! $error && ! $notrigger ) {
2018-08-12 16:29:26 +02:00
// Call trigger
2019-11-08 10:53:31 +01:00
$result = $this -> call_trigger ( 'BILL_MODIFY' , $user );
2021-02-23 21:09:01 +01:00
if ( $result < 0 ) {
$error ++ ;
}
2018-08-12 16:29:26 +02:00
// End call triggers
}
2018-07-06 08:07:38 +02:00
// Commit or rollback
2021-02-23 21:09:01 +01:00
if ( $error ) {
foreach ( $this -> errors as $errmsg ) {
2018-07-06 08:07:38 +02:00
dol_syslog ( get_class ( $this ) . " ::update " . $errmsg , LOG_ERR );
2019-11-08 10:53:31 +01:00
$this -> error .= ( $this -> error ? ', ' . $errmsg : $errmsg );
2018-07-06 08:07:38 +02:00
}
$this -> db -> rollback ();
2019-11-08 10:53:31 +01:00
return - 1 * $error ;
2020-05-21 15:05:19 +02:00
} else {
2018-07-06 08:07:38 +02:00
$this -> db -> commit ();
return 1 ;
}
}
2020-09-08 21:27:28 +02:00
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2018-07-06 08:07:38 +02:00
/**
* Add a discount line into an invoice ( as an invoice line ) using an existing absolute discount ( Consume the discount )
*
* @ param int $idremise Id of absolute discount
* @ return int > 0 if OK , < 0 if KO
*/
2020-09-08 21:27:28 +02:00
public function insert_discount ( $idremise )
2018-07-06 08:07:38 +02:00
{
2020-09-08 21:27:28 +02:00
// phpcs:enable
2021-11-16 16:02:55 +01:00
global $conf , $langs ;
2018-07-06 08:07:38 +02:00
include_once DOL_DOCUMENT_ROOT . '/core/lib/price.lib.php' ;
include_once DOL_DOCUMENT_ROOT . '/core/class/discount.class.php' ;
$this -> db -> begin ();
2019-11-08 10:53:31 +01:00
$remise = new DiscountAbsolute ( $this -> db );
$result = $remise -> fetch ( $idremise );
2018-07-06 08:07:38 +02:00
2021-02-23 21:09:01 +01:00
if ( $result > 0 ) {
if ( $remise -> fk_facture ) { // Protection against multiple submission
2019-11-08 10:53:31 +01:00
$this -> error = $langs -> trans ( " ErrorDiscountAlreadyUsed " );
2018-07-06 08:07:38 +02:00
$this -> db -> rollback ();
return - 5 ;
}
2019-11-08 10:53:31 +01:00
$facligne = new FactureLigne ( $this -> db );
$facligne -> fk_facture = $this -> id ;
$facligne -> fk_remise_except = $remise -> id ;
$facligne -> desc = $remise -> description ; // Description ligne
$facligne -> vat_src_code = $remise -> vat_src_code ;
$facligne -> tva_tx = $remise -> tva_tx ;
2018-07-06 08:07:38 +02:00
$facligne -> subprice = - $remise -> amount_ht ;
2019-11-08 10:53:31 +01:00
$facligne -> fk_product = 0 ; // Id produit predefini
$facligne -> qty = 1 ;
$facligne -> remise_percent = 0 ;
$facligne -> rang = - 1 ;
$facligne -> info_bits = 2 ;
2018-07-06 08:07:38 +02:00
2022-01-11 09:54:27 +01:00
if ( ! empty ( $conf -> global -> MAIN_ADD_LINE_AT_POSITION )) {
2021-11-16 16:02:55 +01:00
$facligne -> rang = 1 ;
2021-11-23 10:44:43 +01:00
$linecount = count ( $this -> lines );
for ( $ii = 1 ; $ii <= $linecount ; $ii ++ ) {
2021-11-16 16:02:55 +01:00
$this -> updateRangOfLine ( $this -> lines [ $ii - 1 ] -> id , $ii + 1 );
}
}
2018-07-06 08:07:38 +02:00
// Get buy/cost price of invoice that is source of discount
2021-02-23 21:09:01 +01:00
if ( $remise -> fk_facture_source > 0 ) {
2020-09-08 21:27:28 +02:00
$srcinvoice = new Facture ( $this -> db );
$srcinvoice -> fetch ( $remise -> fk_facture_source );
include_once DOL_DOCUMENT_ROOT . '/core/class/html.formmargin.class.php' ; // TODO Move this into commonobject
$formmargin = new FormMargin ( $this -> db );
$arraytmp = $formmargin -> getMarginInfosArray ( $srcinvoice , false );
$facligne -> pa_ht = $arraytmp [ 'pa_total' ];
2018-07-06 08:07:38 +02:00
}
$facligne -> total_ht = - $remise -> amount_ht ;
$facligne -> total_tva = - $remise -> amount_tva ;
$facligne -> total_ttc = - $remise -> amount_ttc ;
$facligne -> multicurrency_subprice = - $remise -> multicurrency_subprice ;
2018-10-17 15:49:08 +02:00
$facligne -> multicurrency_total_ht = - $remise -> multicurrency_amount_ht ;
$facligne -> multicurrency_total_tva = - $remise -> multicurrency_amount_tva ;
$facligne -> multicurrency_total_ttc = - $remise -> multicurrency_amount_ttc ;
2018-07-06 08:07:38 +02:00
2019-11-08 10:53:31 +01:00
$lineid = $facligne -> insert ();
2021-02-23 21:09:01 +01:00
if ( $lineid > 0 ) {
2019-11-08 10:53:31 +01:00
$result = $this -> update_price ( 1 );
2021-02-23 21:09:01 +01:00
if ( $result > 0 ) {
2018-07-06 08:07:38 +02:00
// Create link between discount and invoice line
2019-11-08 10:53:31 +01:00
$result = $remise -> link_to_invoice ( $lineid , 0 );
2021-02-23 21:09:01 +01:00
if ( $result < 0 ) {
2019-11-08 10:53:31 +01:00
$this -> error = $remise -> error ;
2018-07-06 08:07:38 +02:00
$this -> db -> rollback ();
return - 4 ;
}
$this -> db -> commit ();
return 1 ;
2020-05-21 15:05:19 +02:00
} else {
2019-11-08 10:53:31 +01:00
$this -> error = $facligne -> error ;
2018-07-06 08:07:38 +02:00
$this -> db -> rollback ();
return - 1 ;
}
2020-05-21 15:05:19 +02:00
} else {
2019-11-08 10:53:31 +01:00
$this -> error = $facligne -> error ;
2018-07-06 08:07:38 +02:00
$this -> db -> rollback ();
return - 2 ;
}
2020-05-21 15:05:19 +02:00
} else {
2018-07-06 08:07:38 +02:00
$this -> db -> rollback ();
return - 3 ;
}
}
2020-09-08 21:27:28 +02:00
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2018-07-06 08:07:38 +02:00
/**
* Set customer ref
*
* @ param string $ref_client Customer ref
* @ param int $notrigger 1 = Does not execute triggers , 0 = execute triggers
* @ return int < 0 if KO , > 0 if OK
*/
2020-09-08 21:27:28 +02:00
public function set_ref_client ( $ref_client , $notrigger = 0 )
2018-07-06 08:07:38 +02:00
{
2020-09-08 21:27:28 +02:00
// phpcs:enable
global $user ;
2018-07-06 08:07:38 +02:00
2019-11-08 10:53:31 +01:00
$error = 0 ;
2018-07-06 08:07:38 +02:00
$this -> db -> begin ();
$sql = 'UPDATE ' . MAIN_DB_PREFIX . 'facture' ;
2021-02-23 21:09:01 +01:00
if ( empty ( $ref_client )) {
2018-07-06 08:07:38 +02:00
$sql .= ' SET ref_client = NULL' ;
2021-02-23 21:09:01 +01:00
} else {
$sql .= ' SET ref_client = \'' . $this -> db -> escape ( $ref_client ) . '\'' ;
}
2021-08-27 23:36:06 +02:00
$sql .= " WHERE rowid = " . (( int ) $this -> id );
2018-07-06 08:07:38 +02:00
dol_syslog ( __METHOD__ . ' this->id=' . $this -> id . ', ref_client=' . $ref_client , LOG_DEBUG );
2019-11-08 10:53:31 +01:00
$resql = $this -> db -> query ( $sql );
2021-02-23 21:09:01 +01:00
if ( ! $resql ) {
2019-11-08 10:53:31 +01:00
$this -> errors [] = $this -> db -> error ();
2018-07-06 08:07:38 +02:00
$error ++ ;
}
2021-02-23 21:09:01 +01:00
if ( ! $error ) {
2018-07-06 08:07:38 +02:00
$this -> ref_client = $ref_client ;
}
2021-02-23 21:09:01 +01:00
if ( ! $notrigger && empty ( $error )) {
2018-07-06 08:07:38 +02:00
// Call trigger
2019-11-08 10:53:31 +01:00
$result = $this -> call_trigger ( 'BILL_MODIFY' , $user );
2021-02-23 21:09:01 +01:00
if ( $result < 0 ) {
$error ++ ;
}
2018-07-06 08:07:38 +02:00
// End call triggers
}
2021-02-23 21:09:01 +01:00
if ( ! $error ) {
2018-07-06 08:07:38 +02:00
$this -> ref_client = $ref_client ;
$this -> db -> commit ();
return 1 ;
2020-05-21 15:05:19 +02:00
} else {
2021-02-23 21:09:01 +01:00
foreach ( $this -> errors as $errmsg ) {
2018-07-06 08:07:38 +02:00
dol_syslog ( __METHOD__ . ' Error: ' . $errmsg , LOG_ERR );
2019-11-08 10:53:31 +01:00
$this -> error .= ( $this -> error ? ', ' . $errmsg : $errmsg );
2018-07-06 08:07:38 +02:00
}
$this -> db -> rollback ();
2019-11-08 10:53:31 +01:00
return - 1 * $error ;
2018-07-06 08:07:38 +02:00
}
}
/**
* Delete invoice
*
* @ param User $user User making the deletion .
* @ param int $notrigger 1 = Does not execute triggers , 0 = execute triggers
* @ param int $idwarehouse Id warehouse to use for stock change .
* @ return int < 0 if KO , 0 = Refused , > 0 if OK
*/
2020-09-08 21:27:28 +02:00
public function delete ( $user , $notrigger = 0 , $idwarehouse = - 1 )
2018-07-06 08:07:38 +02:00
{
2019-11-08 10:53:31 +01:00
global $langs , $conf ;
2018-07-06 08:07:38 +02:00
require_once DOL_DOCUMENT_ROOT . '/core/lib/files.lib.php' ;
2019-11-08 10:53:31 +01:00
$rowid = $this -> id ;
2018-07-06 08:07:38 +02:00
2020-12-13 13:34:21 +01:00
dol_syslog ( get_class ( $this ) . " ::delete rowid= " . $rowid . " , ref= " . $this -> ref . " , thirdparty= " . ( empty ( $this -> thirdparty ) ? '' : $this -> thirdparty -> name ), LOG_DEBUG );
2018-07-06 08:07:38 +02:00
// Test to avoid invoice deletion (allowed if draft)
$result = $this -> is_erasable ();
2021-02-23 21:09:01 +01:00
if ( $result <= 0 ) {
return 0 ;
}
2018-07-06 08:07:38 +02:00
2019-11-08 10:53:31 +01:00
$error = 0 ;
2018-07-06 08:07:38 +02:00
$this -> db -> begin ();
2021-02-23 21:09:01 +01:00
if ( ! $error && ! $notrigger ) {
2020-09-08 21:27:28 +02:00
// Call trigger
$result = $this -> call_trigger ( 'BILL_DELETE' , $user );
2021-02-23 21:09:01 +01:00
if ( $result < 0 ) {
$error ++ ;
}
2020-09-08 21:27:28 +02:00
// End call triggers
2018-07-06 08:07:38 +02:00
}
// Removed extrafields
2019-11-08 10:53:31 +01:00
if ( ! $error ) {
$result = $this -> deleteExtraFields ();
2021-02-23 21:09:01 +01:00
if ( $result < 0 ) {
2018-07-06 08:07:38 +02:00
$error ++ ;
dol_syslog ( get_class ( $this ) . " ::delete error deleteExtraFields " . $this -> error , LOG_ERR );
}
}
2021-02-23 21:09:01 +01:00
if ( ! $error ) {
2018-07-06 08:07:38 +02:00
// Delete linked object
$res = $this -> deleteObjectLinked ();
2021-02-23 21:09:01 +01:00
if ( $res < 0 ) {
$error ++ ;
}
2018-07-06 08:07:38 +02:00
}
2021-02-23 21:09:01 +01:00
if ( ! $error ) {
2018-07-06 08:07:38 +02:00
// If invoice was converted into a discount not yet consumed, we remove discount
$sql = 'DELETE FROM ' . MAIN_DB_PREFIX . 'societe_remise_except' ;
2021-03-30 17:45:15 +02:00
$sql .= ' WHERE fk_facture_source = ' . (( int ) $rowid );
2019-11-08 10:53:31 +01:00
$sql .= ' AND fk_facture_line IS NULL' ;
$resql = $this -> db -> query ( $sql );
2018-07-06 08:07:38 +02:00
2021-04-06 09:15:34 +02:00
// If invoice has consumed discounts
2018-07-06 08:07:38 +02:00
$this -> fetch_lines ();
2019-11-08 10:53:31 +01:00
$list_rowid_det = array ();
2021-02-23 21:09:01 +01:00
foreach ( $this -> lines as $key => $invoiceline ) {
2019-11-12 10:11:30 +01:00
$list_rowid_det [] = $invoiceline -> id ;
2018-07-06 08:07:38 +02:00
}
2021-04-06 09:15:34 +02:00
// Consumed discounts are freed
2021-02-23 21:09:01 +01:00
if ( count ( $list_rowid_det )) {
2018-07-06 08:07:38 +02:00
$sql = 'UPDATE ' . MAIN_DB_PREFIX . 'societe_remise_except' ;
2019-11-08 10:53:31 +01:00
$sql .= ' SET fk_facture = NULL, fk_facture_line = NULL' ;
2021-03-22 12:00:41 +01:00
$sql .= ' WHERE fk_facture_line IN (' . $this -> db -> sanitize ( join ( ',' , $list_rowid_det )) . ')' ;
2018-07-06 08:07:38 +02:00
2021-02-23 21:09:01 +01:00
if ( ! $this -> db -> query ( $sql )) {
2019-11-08 10:53:31 +01:00
$this -> error = $this -> db -> error () . " sql= " . $sql ;
2020-11-26 09:16:16 +01:00
$this -> errors [] = $this -> error ;
2018-07-06 08:07:38 +02:00
$this -> db -> rollback ();
return - 5 ;
}
}
2021-09-21 14:20:01 +02:00
// Remove other links to the deleted invoice
$sql = 'UPDATE ' . MAIN_DB_PREFIX . 'eventorganization_conferenceorboothattendee' ;
2021-09-21 14:23:21 +02:00
$sql .= ' SET fk_invoice = NULL' ;
$sql .= ' WHERE fk_invoice = ' . (( int ) $rowid );
2021-09-21 14:20:01 +02:00
if ( ! $this -> db -> query ( $sql )) {
$this -> error = $this -> db -> error () . " sql= " . $sql ;
$this -> errors [] = $this -> error ;
$this -> db -> rollback ();
return - 5 ;
}
$sql = 'UPDATE ' . MAIN_DB_PREFIX . 'projet_task_time' ;
$sql .= ' SET invoice_id = NULL, invoice_line_id = NULL' ;
$sql .= ' WHERE invoice_id = ' . (( int ) $rowid );
if ( ! $this -> db -> query ( $sql )) {
$this -> error = $this -> db -> error () . " sql= " . $sql ;
$this -> errors [] = $this -> error ;
$this -> db -> rollback ();
return - 5 ;
}
2020-01-31 15:12:17 +01:00
// If we decrease stock on invoice validation, we increase back if a warehouse id was provided
2021-02-23 21:09:01 +01:00
if ( $this -> type != self :: TYPE_DEPOSIT && $result >= 0 && ! empty ( $conf -> stock -> enabled ) && ! empty ( $conf -> global -> STOCK_CALCULATE_ON_BILL ) && $idwarehouse != - 1 ) {
2018-07-06 08:07:38 +02:00
require_once DOL_DOCUMENT_ROOT . '/product/stock/class/mouvementstock.class.php' ;
$langs -> load ( " agenda " );
2019-11-08 10:53:31 +01:00
$num = count ( $this -> lines );
2021-02-23 21:09:01 +01:00
for ( $i = 0 ; $i < $num ; $i ++ ) {
if ( $this -> lines [ $i ] -> fk_product > 0 ) {
2018-07-06 08:07:38 +02:00
$mouvP = new MouvementStock ( $this -> db );
$mouvP -> origin = & $this ;
2022-03-22 13:46:55 +01:00
$mouvP -> setOrigin ( $this -> element , $this -> id );
2018-07-06 08:07:38 +02:00
// We decrease stock for product
2021-02-23 21:09:01 +01:00
if ( $this -> type == self :: TYPE_CREDIT_NOTE ) {
$result = $mouvP -> livraison ( $user , $this -> lines [ $i ] -> fk_product , $idwarehouse , $this -> lines [ $i ] -> qty , $this -> lines [ $i ] -> subprice , $langs -> trans ( " InvoiceDeleteDolibarr " , $this -> ref ));
} else {
$result = $mouvP -> reception ( $user , $this -> lines [ $i ] -> fk_product , $idwarehouse , $this -> lines [ $i ] -> qty , 0 , $langs -> trans ( " InvoiceDeleteDolibarr " , $this -> ref )); // we use 0 for price, to not change the weighted average value
}
2018-07-06 08:07:38 +02:00
}
}
}
2020-09-08 21:27:28 +02:00
// Invoice line extrafileds
2020-05-02 03:39:56 +02:00
$main = MAIN_DB_PREFIX . 'facturedet' ;
$ef = $main . " _extrafields " ;
2021-09-21 14:20:01 +02:00
$sqlef = " DELETE FROM " . $ef . " WHERE fk_object IN (SELECT rowid FROM " . $main . " WHERE fk_facture = " . (( int ) $rowid ) . " ) " ;
2018-07-06 08:07:38 +02:00
// Delete invoice line
2021-03-30 11:36:50 +02:00
$sql = 'DELETE FROM ' . MAIN_DB_PREFIX . 'facturedet WHERE fk_facture = ' . (( int ) $rowid );
2018-07-06 08:07:38 +02:00
2021-02-23 21:09:01 +01:00
if ( $this -> db -> query ( $sqlef ) && $this -> db -> query ( $sql ) && $this -> delete_linked_contact ()) {
2021-03-29 15:32:09 +02:00
$sql = 'DELETE FROM ' . MAIN_DB_PREFIX . 'facture WHERE rowid = ' . (( int ) $rowid );
2018-07-06 08:07:38 +02:00
2019-11-08 10:53:31 +01:00
$resql = $this -> db -> query ( $sql );
2021-02-23 21:09:01 +01:00
if ( $resql ) {
2020-09-12 04:25:54 +02:00
// Delete record into ECM index (Note that delete is also done when deleting files with the dol_delete_dir_recursive
$this -> deleteEcmFiles ();
2020-09-03 12:43:38 +02:00
2018-07-06 08:07:38 +02:00
// On efface le repertoire de pdf provisoire
$ref = dol_sanitizeFileName ( $this -> ref );
2021-02-23 21:09:01 +01:00
if ( $conf -> facture -> dir_output && ! empty ( $this -> ref )) {
2019-11-08 10:53:31 +01:00
$dir = $conf -> facture -> dir_output . " / " . $ref ;
$file = $conf -> facture -> dir_output . " / " . $ref . " / " . $ref . " .pdf " ;
2021-02-23 21:09:01 +01:00
if ( file_exists ( $file )) { // We must delete all files before deleting directory
2019-11-08 10:53:31 +01:00
$ret = dol_delete_preview ( $this );
2018-07-06 08:07:38 +02:00
2021-02-23 21:09:01 +01:00
if ( ! dol_delete_file ( $file , 0 , 0 , 0 , $this )) { // For triggers
2018-09-25 00:39:28 +02:00
$langs -> load ( " errors " );
2019-11-08 10:53:31 +01:00
$this -> error = $langs -> trans ( " ErrorFailToDeleteFile " , $file );
2020-11-26 09:16:16 +01:00
$this -> errors [] = $this -> error ;
2018-07-06 08:07:38 +02:00
$this -> db -> rollback ();
return 0 ;
}
}
2021-02-23 21:09:01 +01:00
if ( file_exists ( $dir )) {
if ( ! dol_delete_dir_recursive ( $dir )) { // For remove dir and meta
2018-09-25 00:39:28 +02:00
$langs -> load ( " errors " );
2019-11-08 10:53:31 +01:00
$this -> error = $langs -> trans ( " ErrorFailToDeleteDir " , $dir );
2020-11-26 09:16:16 +01:00
$this -> errors [] = $this -> error ;
2018-07-06 08:07:38 +02:00
$this -> db -> rollback ();
return 0 ;
}
}
}
$this -> db -> commit ();
return 1 ;
2020-05-21 15:05:19 +02:00
} else {
2019-11-08 10:53:31 +01:00
$this -> error = $this -> db -> lasterror () . " sql= " . $sql ;
2020-11-26 09:16:16 +01:00
$this -> errors [] = $this -> error ;
2018-07-06 08:07:38 +02:00
$this -> db -> rollback ();
return - 6 ;
}
2020-05-21 15:05:19 +02:00
} else {
2019-11-08 10:53:31 +01:00
$this -> error = $this -> db -> lasterror () . " sql= " . $sql ;
2020-11-26 09:16:16 +01:00
$this -> errors [] = $this -> error ;
2018-07-06 08:07:38 +02:00
$this -> db -> rollback ();
return - 4 ;
}
2020-05-21 15:05:19 +02:00
} else {
2018-07-06 08:07:38 +02:00
$this -> db -> rollback ();
return - 2 ;
}
}
2020-09-08 21:27:28 +02:00
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2018-07-06 08:07:38 +02:00
/**
2020-03-16 19:23:18 +01:00
* Tag the invoice as paid completely ( if close_code is filled ) => this -> fk_statut = 2 , this -> paye = 1
* or partialy ( if close_code filled ) + appel trigger BILL_PAYED => this -> fk_statut = 2 , this -> paye stay 0
2018-07-06 08:07:38 +02:00
*
2021-02-09 09:49:37 +01:00
* @ deprecated
* @ see setPaid ()
2020-03-16 19:23:18 +01:00
* @ param User $user Object user that modify
2018-07-06 08:07:38 +02:00
* @ param string $close_code Code renseigne si on classe a payee completement alors que paiement incomplet ( cas escompte par exemple )
* @ param string $close_note Commentaire renseigne si on classe a payee alors que paiement incomplet ( cas escompte par exemple )
* @ return int < 0 if KO , > 0 if OK
*/
2020-09-08 21:27:28 +02:00
public function set_paid ( $user , $close_code = '' , $close_note = '' )
2018-07-06 08:07:38 +02:00
{
2020-09-08 21:27:28 +02:00
// phpcs:enable
2021-02-09 09:40:07 +01:00
dol_syslog ( get_class ( $this ) . " ::set_paid is deprecated, use setPaid instead " , LOG_NOTICE );
2021-02-09 09:49:37 +01:00
return $this -> setPaid ( $user , $close_code , $close_note );
2021-02-09 09:40:07 +01:00
}
/**
* Tag the invoice as paid completely ( if close_code is filled ) => this -> fk_statut = 2 , this -> paye = 1
2021-11-15 04:26:14 +01:00
* or partially ( if close_code filled ) + appel trigger BILL_PAYED => this -> fk_statut = 2 , this -> paye stay 0
2021-02-09 09:40:07 +01:00
*
* @ param User $user Object user that modify
* @ param string $close_code Code renseigne si on classe a payee completement alors que paiement incomplet ( cas escompte par exemple )
* @ param string $close_note Commentaire renseigne si on classe a payee alors que paiement incomplet ( cas escompte par exemple )
* @ return int < 0 if KO , > 0 if OK
*/
public function setPaid ( $user , $close_code = '' , $close_note = '' )
{
2019-11-08 10:53:31 +01:00
$error = 0 ;
2018-07-06 08:07:38 +02:00
2021-02-23 21:09:01 +01:00
if ( $this -> paye != 1 ) {
2018-07-06 08:07:38 +02:00
$this -> db -> begin ();
2019-10-14 16:00:03 +02:00
2019-11-08 10:53:31 +01:00
$now = dol_now ();
2018-07-06 08:07:38 +02:00
2021-11-15 04:26:14 +01:00
dol_syslog ( get_class ( $this ) . " ::setPaid rowid= " . (( int ) $this -> id ), LOG_DEBUG );
2018-07-06 08:07:38 +02:00
$sql = 'UPDATE ' . MAIN_DB_PREFIX . 'facture SET' ;
2019-11-08 10:53:31 +01:00
$sql .= ' fk_statut=' . self :: STATUS_CLOSED ;
2021-02-23 21:09:01 +01:00
if ( ! $close_code ) {
$sql .= ', paye=1' ;
}
if ( $close_code ) {
$sql .= " , close_code=' " . $this -> db -> escape ( $close_code ) . " ' " ;
}
if ( $close_note ) {
$sql .= " , close_note=' " . $this -> db -> escape ( $close_note ) . " ' " ;
}
2021-08-27 23:36:06 +02:00
$sql .= ', fk_user_closing = ' . (( int ) $user -> id );
2019-11-08 10:53:31 +01:00
$sql .= " , date_closing = ' " . $this -> db -> idate ( $now ) . " ' " ;
2021-08-27 23:36:06 +02:00
$sql .= " WHERE rowid = " . (( int ) $this -> id );
2018-07-06 08:07:38 +02:00
$resql = $this -> db -> query ( $sql );
2021-02-23 21:09:01 +01:00
if ( $resql ) {
2020-09-08 21:27:28 +02:00
// Call trigger
$result = $this -> call_trigger ( 'BILL_PAYED' , $user );
2021-02-23 21:09:01 +01:00
if ( $result < 0 ) {
$error ++ ;
}
2020-09-08 21:27:28 +02:00
// End call triggers
2020-05-21 15:05:19 +02:00
} else {
2018-07-06 08:07:38 +02:00
$error ++ ;
2019-11-08 10:53:31 +01:00
$this -> error = $this -> db -> lasterror ();
2018-07-06 08:07:38 +02:00
}
2021-02-23 21:09:01 +01:00
if ( ! $error ) {
2018-07-06 08:07:38 +02:00
$this -> db -> commit ();
return 1 ;
2020-05-21 15:05:19 +02:00
} else {
2018-07-06 08:07:38 +02:00
$this -> db -> rollback ();
return - 1 ;
}
2020-05-21 15:05:19 +02:00
} else {
2018-07-06 08:07:38 +02:00
return 0 ;
}
}
2020-09-08 21:27:28 +02:00
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2018-07-06 08:07:38 +02:00
/**
* Tag la facture comme non payee completement + appel trigger BILL_UNPAYED
* Fonction utilisee quand un paiement prelevement est refuse ,
* ou quand une facture annulee et reouverte .
*
2021-02-09 09:40:07 +01:00
* @ deprecated
* @ see setUnpaid ()
2018-07-06 08:07:38 +02:00
* @ param User $user Object user that change status
* @ return int < 0 if KO , > 0 if OK
*/
2020-09-08 21:27:28 +02:00
public function set_unpaid ( $user )
2018-07-06 08:07:38 +02:00
{
2020-09-08 21:27:28 +02:00
// phpcs:enable
2021-02-09 09:40:07 +01:00
dol_syslog ( get_class ( $this ) . " ::set_unpaid is deprecated, use setUnpaid instead " , LOG_NOTICE );
2021-02-09 09:49:37 +01:00
return $this -> setUnpaid ( $user );
2021-02-09 09:40:07 +01:00
}
/**
* Tag la facture comme non payee completement + appel trigger BILL_UNPAYED
* Fonction utilisee quand un paiement prelevement est refuse ,
* ou quand une facture annulee et reouverte .
*
* @ param User $user Object user that change status
* @ return int < 0 if KO , > 0 if OK
*/
public function setUnpaid ( $user )
{
2019-11-08 10:53:31 +01:00
$error = 0 ;
2018-07-06 08:07:38 +02:00
$this -> db -> begin ();
$sql = 'UPDATE ' . MAIN_DB_PREFIX . 'facture' ;
2019-11-08 10:53:31 +01:00
$sql .= ' SET paye=0, fk_statut=' . self :: STATUS_VALIDATED . ', close_code=null, close_note=null,' ;
$sql .= ' date_closing=null,' ;
$sql .= ' fk_user_closing=null' ;
2021-08-27 23:36:06 +02:00
$sql .= " WHERE rowid = " . (( int ) $this -> id );
2018-07-06 08:07:38 +02:00
2021-11-15 04:26:14 +01:00
dol_syslog ( get_class ( $this ) . " ::setUnpaid " , LOG_DEBUG );
2018-07-06 08:07:38 +02:00
$resql = $this -> db -> query ( $sql );
2021-02-23 21:09:01 +01:00
if ( $resql ) {
2020-09-08 21:27:28 +02:00
// Call trigger
$result = $this -> call_trigger ( 'BILL_UNPAYED' , $user );
2021-02-23 21:09:01 +01:00
if ( $result < 0 ) {
$error ++ ;
}
2020-09-08 21:27:28 +02:00
// End call triggers
2020-05-21 15:05:19 +02:00
} else {
2018-07-06 08:07:38 +02:00
$error ++ ;
2019-11-08 10:53:31 +01:00
$this -> error = $this -> db -> error ();
2018-07-06 08:07:38 +02:00
dol_print_error ( $this -> db );
}
2021-02-23 21:09:01 +01:00
if ( ! $error ) {
2018-07-06 08:07:38 +02:00
$this -> db -> commit ();
return 1 ;
2020-05-21 15:05:19 +02:00
} else {
2018-07-06 08:07:38 +02:00
$this -> db -> rollback ();
return - 1 ;
}
}
2020-09-08 21:27:28 +02:00
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2018-07-06 08:07:38 +02:00
/**
* Tag invoice as canceled , with no payment on it ( example for replacement invoice or payment never received ) + call trigger BILL_CANCEL
* Warning , if option to decrease stock on invoice was set , this function does not change stock ( it might be a cancel because
* of no payment even if merchandises were sent ) .
*
2021-02-09 13:10:11 +01:00
* @ deprecated
* @ see setCanceled ()
2018-07-06 08:07:38 +02:00
* @ param User $user Object user making change
* @ param string $close_code Code of closing invoice ( CLOSECODE_REPLACED , CLOSECODE_ ... )
* @ param string $close_note Comment
* @ return int < 0 if KO , > 0 if OK
*/
2020-09-08 21:27:28 +02:00
public function set_canceled ( $user , $close_code = '' , $close_note = '' )
2018-07-06 08:07:38 +02:00
{
2020-09-08 21:27:28 +02:00
// phpcs:enable
2021-02-09 13:10:11 +01:00
dol_syslog ( get_class ( $this ) . " ::set_canceled is deprecated, use setCanceled instead " , LOG_NOTICE );
return $this -> setCanceled ( $user , $close_code , $close_note );
}
2018-07-06 08:07:38 +02:00
2021-02-09 13:10:11 +01:00
/**
* Tag invoice as canceled , with no payment on it ( example for replacement invoice or payment never received ) + call trigger BILL_CANCEL
* Warning , if option to decrease stock on invoice was set , this function does not change stock ( it might be a cancel because
* of no payment even if merchandises were sent ) .
*
* @ param User $user Object user making change
* @ param string $close_code Code of closing invoice ( CLOSECODE_REPLACED , CLOSECODE_ ... )
* @ param string $close_note Comment
* @ return int < 0 if KO , > 0 if OK
*/
public function setCanceled ( $user , $close_code = '' , $close_note = '' )
{
2021-03-14 12:20:23 +01:00
dol_syslog ( get_class ( $this ) . " ::setCanceled rowid= " . (( int ) $this -> id ), LOG_DEBUG );
2018-07-06 08:07:38 +02:00
$this -> db -> begin ();
$sql = 'UPDATE ' . MAIN_DB_PREFIX . 'facture SET' ;
2019-11-08 10:53:31 +01:00
$sql .= ' fk_statut=' . self :: STATUS_ABANDONED ;
2021-02-23 21:09:01 +01:00
if ( $close_code ) {
$sql .= " , close_code=' " . $this -> db -> escape ( $close_code ) . " ' " ;
}
if ( $close_note ) {
$sql .= " , close_note=' " . $this -> db -> escape ( $close_note ) . " ' " ;
}
2021-08-27 23:36:06 +02:00
$sql .= " WHERE rowid = " . (( int ) $this -> id );
2018-07-06 08:07:38 +02:00
$resql = $this -> db -> query ( $sql );
2021-02-23 21:09:01 +01:00
if ( $resql ) {
2021-04-06 09:15:34 +02:00
// Bound discounts are deducted from the invoice
// as they have not been used since the invoice is abandoned.
2018-07-06 08:07:38 +02:00
$sql = 'UPDATE ' . MAIN_DB_PREFIX . 'societe_remise_except' ;
2019-11-08 10:53:31 +01:00
$sql .= ' SET fk_facture = NULL' ;
2021-08-27 23:36:06 +02:00
$sql .= ' WHERE fk_facture = ' . (( int ) $this -> id );
2018-07-06 08:07:38 +02:00
2019-11-08 10:53:31 +01:00
$resql = $this -> db -> query ( $sql );
2021-02-23 21:09:01 +01:00
if ( $resql ) {
2020-09-08 21:27:28 +02:00
// Call trigger
$result = $this -> call_trigger ( 'BILL_CANCEL' , $user );
2021-02-23 21:09:01 +01:00
if ( $result < 0 ) {
2018-07-06 08:07:38 +02:00
$this -> db -> rollback ();
return - 1 ;
}
2020-09-08 21:27:28 +02:00
// End call triggers
2018-07-06 08:07:38 +02:00
$this -> db -> commit ();
return 1 ;
2020-05-21 15:05:19 +02:00
} else {
2019-11-08 10:53:31 +01:00
$this -> error = $this -> db -> error () . " sql= " . $sql ;
2018-07-06 08:07:38 +02:00
$this -> db -> rollback ();
return - 1 ;
}
2020-05-21 15:05:19 +02:00
} else {
2019-11-08 10:53:31 +01:00
$this -> error = $this -> db -> error () . " sql= " . $sql ;
2018-07-06 08:07:38 +02:00
$this -> db -> rollback ();
return - 2 ;
}
}
/**
* Tag invoice as validated + call trigger BILL_VALIDATE
* Object must have lines loaded with fetch_lines
*
* @ param User $user Object user that validate
* @ param string $force_number Reference to force on invoice
* @ param int $idwarehouse Id of warehouse to use for stock decrease if option to decreasenon stock is on ( 0 = no decrease )
* @ param int $notrigger 1 = Does not execute triggers , 0 = execute triggers
2020-11-08 14:39:20 +01:00
* @ param int $batch_rule 0 = do not decrement batch , else batch rule to use , 1 = take in batches ordered by sellby and eatby dates
2020-09-08 21:27:28 +02:00
* @ return int < 0 if KO , 0 = Nothing done because invoice is not a draft , > 0 if OK
2018-07-06 08:07:38 +02:00
*/
2020-09-08 21:27:28 +02:00
public function validate ( $user , $force_number = '' , $idwarehouse = 0 , $notrigger = 0 , $batch_rule = 0 )
2018-07-06 08:07:38 +02:00
{
2022-03-08 11:29:01 +01:00
global $conf , $langs , $mysoc ;
2018-07-06 08:07:38 +02:00
require_once DOL_DOCUMENT_ROOT . '/core/lib/files.lib.php' ;
2020-11-08 14:39:20 +01:00
2020-02-21 11:08:34 +01:00
$productStatic = null ;
$warehouseStatic = null ;
if ( $batch_rule > 0 ) {
2020-03-12 12:45:44 +01:00
require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php' ;
require_once DOL_DOCUMENT_ROOT . '/product/class/productbatch.class.php' ;
require_once DOL_DOCUMENT_ROOT . '/product/stock/class/entrepot.class.php' ;
2020-02-21 11:08:34 +01:00
$productStatic = new Product ( $this -> db );
$warehouseStatic = new Entrepot ( $this -> db );
2022-03-01 00:01:13 +01:00
$productbatch = new ProductBatch ( $this -> db );
2020-02-21 11:08:34 +01:00
}
2018-07-06 08:07:38 +02:00
2019-11-08 10:53:31 +01:00
$now = dol_now ();
2018-07-06 08:07:38 +02:00
2019-11-08 10:53:31 +01:00
$error = 0 ;
2018-07-06 08:07:38 +02:00
dol_syslog ( get_class ( $this ) . '::validate user=' . $user -> id . ', force_number=' . $force_number . ', idwarehouse=' . $idwarehouse );
// Force to have object complete for checks
$this -> fetch_thirdparty ();
$this -> fetch_lines ();
// Check parameters
2021-03-08 09:14:23 +01:00
if ( $this -> statut != self :: STATUS_DRAFT ) {
dol_syslog ( get_class ( $this ) . " ::validate status is not draft. operation canceled. " , LOG_WARNING );
2018-07-06 08:07:38 +02:00
return 0 ;
}
2021-02-23 21:09:01 +01:00
if ( count ( $this -> lines ) <= 0 ) {
2020-09-08 21:27:28 +02:00
$langs -> load ( " errors " );
2019-11-08 10:53:31 +01:00
$this -> error = $langs -> trans ( " ErrorObjectMustHaveLinesToBeValidated " , $this -> ref );
2018-07-06 08:07:38 +02:00
return - 1 ;
}
if (( empty ( $conf -> global -> MAIN_USE_ADVANCED_PERMS ) && empty ( $user -> rights -> facture -> creer ))
2021-02-23 21:09:01 +01:00
|| ( ! empty ( $conf -> global -> MAIN_USE_ADVANCED_PERMS ) && empty ( $user -> rights -> facture -> invoice_advance -> validate ))) {
2019-11-08 10:53:31 +01:00
$this -> error = 'Permission denied' ;
2018-07-06 08:07:38 +02:00
dol_syslog ( get_class ( $this ) . " ::validate " . $this -> error . ' MAIN_USE_ADVANCED_PERMS=' . $conf -> global -> MAIN_USE_ADVANCED_PERMS , LOG_ERR );
return - 1 ;
}
2022-03-02 10:16:14 +01:00
if ( ! empty ( $conf -> global -> INVOICE_CHECK_POSTERIOR_DATE )) {
2022-05-16 21:02:09 +02:00
$last_of_type = $this -> willBeLastOfSameType ( true );
2022-03-02 10:16:14 +01:00
if ( ! $last_of_type [ 0 ]) {
2022-03-02 12:53:44 +01:00
$this -> error = $langs -> transnoentities ( " ErrorInvoiceIsNotLastOfSameType " , $this -> ref , dol_print_date ( $this -> date , 'day' ), dol_print_date ( $last_of_type [ 1 ], 'day' ));
2022-03-02 10:16:14 +01:00
return - 1 ;
}
}
2018-07-06 08:07:38 +02:00
2022-03-08 11:29:01 +01:00
// Check for mandatory fields in thirdparty (defined into setup)
2022-03-29 15:20:36 +02:00
if ( ! empty ( $this -> thirdparty ) && is_object ( $this -> thirdparty )) {
2022-04-26 11:46:00 +02:00
$array_to_check = array ( 'IDPROF1' , 'IDPROF2' , 'IDPROF3' , 'IDPROF4' , 'IDPROF5' , 'IDPROF6' , 'EMAIL' , 'ACCOUNTANCY_CODE_CUSTOMER' );
2022-03-29 15:20:36 +02:00
foreach ( $array_to_check as $key ) {
$keymin = strtolower ( $key );
if ( ! property_exists ( $this -> thirdparty , $keymin )) {
continue ;
2022-03-25 16:47:41 +01:00
}
2022-03-29 15:20:36 +02:00
$vallabel = $this -> thirdparty -> $keymin ;
$i = ( int ) preg_replace ( '/[^0-9]/' , '' , $key );
if ( $i > 0 ) {
if ( $this -> thirdparty -> isACompany ()) {
// Check for mandatory prof id (but only if country is other than ours)
if ( $mysoc -> country_id > 0 && $this -> thirdparty -> country_id == $mysoc -> country_id ) {
$idprof_mandatory = 'SOCIETE_' . $key . '_INVOICE_MANDATORY' ;
if ( ! $vallabel && ! empty ( $conf -> global -> $idprof_mandatory )) {
$langs -> load ( " errors " );
$this -> error = $langs -> trans ( 'ErrorProdIdIsMandatory' , $langs -> transcountry ( 'ProfId' . $i , $this -> thirdparty -> country_code )) . ' (' . $langs -> trans ( " ForbiddenBySetupRules " ) . ') [' . $langs -> trans ( 'Company' ) . ' : ' . $this -> thirdparty -> name . ']' ;
dol_syslog ( __METHOD__ . ' ' . $this -> error , LOG_ERR );
return - 1 ;
}
}
}
} else {
if ( $key == 'EMAIL' ) {
// Check for mandatory
if ( ! empty ( $conf -> global -> SOCIETE_EMAIL_INVOICE_MANDATORY ) && ! isValidEMail ( $this -> thirdparty -> email )) {
2022-03-08 11:29:01 +01:00
$langs -> load ( " errors " );
2022-03-29 15:20:36 +02:00
$this -> error = $langs -> trans ( " ErrorBadEMail " , $this -> thirdparty -> email ) . ' (' . $langs -> trans ( " ForbiddenBySetupRules " ) . ') [' . $langs -> trans ( 'Company' ) . ' : ' . $this -> thirdparty -> name . ']' ;
2022-03-08 11:29:01 +01:00
dol_syslog ( __METHOD__ . ' ' . $this -> error , LOG_ERR );
return - 1 ;
}
}
2022-04-26 11:46:00 +02:00
if ( $key == 'ACCOUNTANCY_CODE_CUSTOMER' ) {
// Check for mandatory
if ( ! empty ( $conf -> global -> SOCIETE_ACCOUNTANCY_CODE_CUSTOMER_INVOICE_MANDATORY ) && empty ( $this -> thirdparty -> code_compta )) {
$langs -> load ( " errors " );
$this -> error = $langs -> trans ( " ErrorAccountancyCodeCustomerIsMandatory " , $this -> thirdparty -> name ) . ' (' . $langs -> trans ( " ForbiddenBySetupRules " ) . ')' ;
dol_syslog ( __METHOD__ . ' ' . $this -> error , LOG_ERR );
return - 1 ;
}
}
2022-03-08 11:29:01 +01:00
}
}
}
2022-03-29 15:55:47 +02:00
// Check for mandatory fields in $this
$array_to_check = array ( 'REF_CLIENT' => 'RefCustomer' );
foreach ( $array_to_check as $key => $val ) {
$keymin = strtolower ( $key );
$vallabel = $this -> $keymin ;
// Check for mandatory
$keymandatory = 'INVOICE_' . $key . '_MANDATORY_FOR_VALIDATION' ;
if ( ! $vallabel && ! empty ( $conf -> global -> $keymandatory )) {
$langs -> load ( " errors " );
$error ++ ;
setEventMessages ( $langs -> trans ( " ErrorFieldRequired " , $langs -> transnoentitiesnoconv ( $val )), null , 'errors' );
}
}
2018-07-06 08:07:38 +02:00
$this -> db -> begin ();
// Check parameters
2021-02-23 21:09:01 +01:00
if ( $this -> type == self :: TYPE_REPLACEMENT ) { // if this is a replacement invoice
2020-11-08 14:39:20 +01:00
// Check that source invoice is known
2021-02-23 21:09:01 +01:00
if ( $this -> fk_facture_source <= 0 ) {
2019-11-08 10:53:31 +01:00
$this -> error = $langs -> trans ( " ErrorFieldRequired " , $langs -> transnoentitiesnoconv ( " InvoiceReplacement " ));
2018-07-06 08:07:38 +02:00
$this -> db -> rollback ();
return - 10 ;
}
2020-11-01 17:01:26 +01:00
// Load source invoice that has been replaced
2019-11-08 10:53:31 +01:00
$facreplaced = new Facture ( $this -> db );
$result = $facreplaced -> fetch ( $this -> fk_facture_source );
2021-02-23 21:09:01 +01:00
if ( $result <= 0 ) {
2019-11-08 10:53:31 +01:00
$this -> error = $langs -> trans ( " ErrorBadInvoice " );
2018-07-06 08:07:38 +02:00
$this -> db -> rollback ();
return - 11 ;
}
2020-11-01 17:01:26 +01:00
// Check that source invoice not already replaced by another one.
2019-11-08 10:53:31 +01:00
$idreplacement = $facreplaced -> getIdReplacingInvoice ( 'validated' );
2021-02-23 21:09:01 +01:00
if ( $idreplacement && $idreplacement != $this -> id ) {
2019-11-08 10:53:31 +01:00
$facreplacement = new Facture ( $this -> db );
2018-07-06 08:07:38 +02:00
$facreplacement -> fetch ( $idreplacement );
2019-11-08 10:53:31 +01:00
$this -> error = $langs -> trans ( " ErrorInvoiceAlreadyReplaced " , $facreplaced -> ref , $facreplacement -> ref );
2018-07-06 08:07:38 +02:00
$this -> db -> rollback ();
return - 12 ;
}
2021-02-09 13:10:11 +01:00
$result = $facreplaced -> setCanceled ( $user , self :: CLOSECODE_REPLACED , '' );
2021-02-23 21:09:01 +01:00
if ( $result < 0 ) {
2019-11-08 10:53:31 +01:00
$this -> error = $facreplaced -> error ;
2018-07-06 08:07:38 +02:00
$this -> db -> rollback ();
return - 13 ;
}
}
// Define new ref
2021-02-23 21:09:01 +01:00
if ( $force_number ) {
2018-07-06 08:07:38 +02:00
$num = $force_number ;
2021-02-23 21:09:01 +01:00
} elseif ( preg_match ( '/^[\(]?PROV/i' , $this -> ref ) || empty ( $this -> ref )) { // empty should not happened, but when it occurs, the test save life
if ( ! empty ( $conf -> global -> FAC_FORCE_DATE_VALIDATION )) { // If option enabled, we force invoice date
2019-11-08 10:53:31 +01:00
$this -> date = dol_now ();
$this -> date_lim_reglement = $this -> calculate_date_lim_reglement ();
2018-07-06 08:07:38 +02:00
}
$num = $this -> getNextNumRef ( $this -> thirdparty );
2020-05-21 15:05:19 +02:00
} else {
2018-07-06 08:07:38 +02:00
$num = $this -> ref ;
}
2022-07-07 22:35:56 +02:00
2020-03-03 11:49:17 +01:00
$this -> newref = dol_sanitizeFileName ( $num );
2018-07-06 08:07:38 +02:00
2021-02-23 21:09:01 +01:00
if ( $num ) {
2018-07-06 08:07:38 +02:00
$this -> update_price ( 1 );
// Validate
$sql = 'UPDATE ' . MAIN_DB_PREFIX . 'facture' ;
2022-07-07 22:35:56 +02:00
$sql .= " SET ref = ' " . $this -> db -> escape ( $num ) . " ', fk_statut = " . self :: STATUS_VALIDATED . " , fk_user_valid = " . ( $user -> id > 0 ? $user -> id : " null " ) . " , date_valid = ' " . $this -> db -> idate ( $now ) . " ' " ;
2021-02-23 21:09:01 +01:00
if ( ! empty ( $conf -> global -> FAC_FORCE_DATE_VALIDATION )) { // If option enabled, we force invoice date
2019-11-08 10:53:31 +01:00
$sql .= " , datef=' " . $this -> db -> idate ( $this -> date ) . " ' " ;
$sql .= " , date_lim_reglement=' " . $this -> db -> idate ( $this -> date_lim_reglement ) . " ' " ;
2018-07-06 08:07:38 +02:00
}
2021-08-27 23:36:06 +02:00
$sql .= " WHERE rowid = " . (( int ) $this -> id );
2018-07-06 08:07:38 +02:00
dol_syslog ( get_class ( $this ) . " ::validate " , LOG_DEBUG );
2019-11-08 10:53:31 +01:00
$resql = $this -> db -> query ( $sql );
2021-02-23 21:09:01 +01:00
if ( ! $resql ) {
2018-07-06 08:07:38 +02:00
dol_print_error ( $this -> db );
$error ++ ;
}
2021-11-15 04:26:14 +01:00
// We check if the invoice was provisional
2021-02-23 21:09:01 +01:00
if ( ! $error && ( preg_match ( '/^[\(]?PROV/i' , $this -> ref ))) {
2018-07-06 08:07:38 +02:00
// La verif qu'une remise n'est pas utilisee 2 fois est faite au moment de l'insertion de ligne
}
2021-02-23 21:09:01 +01:00
if ( ! $error ) {
2018-07-06 08:07:38 +02:00
// Define third party as a customer
2019-11-08 10:53:31 +01:00
$result = $this -> thirdparty -> set_as_client ();
2018-07-06 08:07:38 +02:00
2021-11-15 04:26:14 +01:00
// If active we decrement the main product and its components at invoice validation
2021-02-23 21:09:01 +01:00
if ( $this -> type != self :: TYPE_DEPOSIT && $result >= 0 && ! empty ( $conf -> stock -> enabled ) && ! empty ( $conf -> global -> STOCK_CALCULATE_ON_BILL ) && $idwarehouse > 0 ) {
2018-07-06 08:07:38 +02:00
require_once DOL_DOCUMENT_ROOT . '/product/stock/class/mouvementstock.class.php' ;
$langs -> load ( " agenda " );
// Loop on each line
2019-11-08 10:53:31 +01:00
$cpt = count ( $this -> lines );
2021-02-23 21:09:01 +01:00
for ( $i = 0 ; $i < $cpt ; $i ++ ) {
if ( $this -> lines [ $i ] -> fk_product > 0 ) {
2018-07-06 08:07:38 +02:00
$mouvP = new MouvementStock ( $this -> db );
$mouvP -> origin = & $this ;
2022-03-22 13:46:55 +01:00
$mouvP -> setOrigin ( $this -> element , $this -> id );
2018-07-06 08:07:38 +02:00
// We decrease stock for product
2020-02-21 11:08:34 +01:00
if ( $this -> type == self :: TYPE_CREDIT_NOTE ) {
$result = $mouvP -> reception ( $user , $this -> lines [ $i ] -> fk_product , $idwarehouse , $this -> lines [ $i ] -> qty , 0 , $langs -> trans ( " InvoiceValidatedInDolibarr " , $num ));
if ( $result < 0 ) {
$error ++ ;
$this -> error = $mouvP -> error ;
}
} else {
$is_batch_line = false ;
if ( $batch_rule > 0 ) {
$productStatic -> fetch ( $this -> lines [ $i ] -> fk_product );
if ( $productStatic -> hasbatch ()) {
$is_batch_line = true ;
$product_qty_remain = $this -> lines [ $i ] -> qty ;
$sortfield = null ;
$sortorder = null ;
// find all batch order by sellby (DLC) and eatby dates (DLUO) first
if ( $batch_rule == Productbatch :: BATCH_RULE_SELLBY_EATBY_DATES_FIRST ) {
$sortfield = 'pl.sellby,pl.eatby,pb.qty,pl.rowid' ;
$sortorder = 'ASC,ASC,ASC,ASC' ;
}
2022-03-01 00:01:13 +01:00
$resBatchList = $productbatch -> findAllForProduct ( $productStatic -> id , $idwarehouse , ( ! empty ( $conf -> global -> STOCK_ALLOW_NEGATIVE_TRANSFER ) ? null : 0 ), $sortfield , $sortorder );
2020-02-21 11:08:34 +01:00
if ( ! is_array ( $resBatchList )) {
$error ++ ;
$this -> error = $this -> db -> lasterror ();
2020-02-21 12:00:16 +01:00
}
if ( ! $error ) {
2020-02-21 11:08:34 +01:00
$batchList = $resBatchList ;
if ( empty ( $batchList )) {
$error ++ ;
$langs -> load ( 'errors' );
$warehouseStatic -> fetch ( $idwarehouse );
$this -> error = $langs -> trans ( 'ErrorBatchNoFoundForProductInWarehouse' , $productStatic -> label , $warehouseStatic -> ref );
2020-03-12 12:45:44 +01:00
dol_syslog ( __METHOD__ . ' Error: ' . $langs -> transnoentitiesnoconv ( 'ErrorBatchNoFoundForProductInWarehouse' , $productStatic -> label , $warehouseStatic -> ref ), LOG_ERR );
2020-02-21 12:00:16 +01:00
}
2020-02-21 11:08:34 +01:00
2020-02-21 12:00:16 +01:00
foreach ( $batchList as $batch ) {
2021-02-23 21:09:01 +01:00
if ( $batch -> qty <= 0 ) {
continue ; // try to decrement only batches have positive quantity first
}
2020-02-21 11:08:34 +01:00
2020-02-21 12:00:16 +01:00
// enough quantity in this batch
if ( $batch -> qty >= $product_qty_remain ) {
$product_batch_qty = $product_qty_remain ;
2021-02-23 21:09:01 +01:00
} else {
// not enough (take all in batch)
2020-02-21 12:00:16 +01:00
$product_batch_qty = $batch -> qty ;
}
$result = $mouvP -> livraison ( $user , $productStatic -> id , $idwarehouse , $product_batch_qty , $this -> lines [ $i ] -> subprice , $langs -> trans ( 'InvoiceValidatedInDolibarr' , $num ), '' , '' , '' , $batch -> batch );
if ( $result < 0 ) {
$error ++ ;
$this -> error = $mouvP -> error ;
break ;
2020-02-21 11:08:34 +01:00
}
2020-02-21 12:00:16 +01:00
$product_qty_remain -= $product_batch_qty ;
// all product quantity was decremented
2021-02-23 21:09:01 +01:00
if ( $product_qty_remain <= 0 ) {
break ;
}
2020-02-21 12:00:16 +01:00
}
if ( ! $error && $product_qty_remain > 0 ) {
if ( $conf -> global -> STOCK_ALLOW_NEGATIVE_TRANSFER ) {
// take in the first batch
$batch = $batchList [ 0 ];
$result = $mouvP -> livraison ( $user , $productStatic -> id , $idwarehouse , $product_qty_remain , $this -> lines [ $i ] -> subprice , $langs -> trans ( 'InvoiceValidatedInDolibarr' , $num ), '' , '' , '' , $batch -> batch );
if ( $result < 0 ) {
2020-02-21 11:08:34 +01:00
$error ++ ;
2020-02-21 12:00:16 +01:00
$this -> error = $mouvP -> error ;
2020-02-21 11:08:34 +01:00
}
2020-02-21 12:00:16 +01:00
} else {
$error ++ ;
$langs -> load ( 'errors' );
$warehouseStatic -> fetch ( $idwarehouse );
$this -> error = $langs -> trans ( 'ErrorBatchNoFoundEnoughQuantityForProductInWarehouse' , $productStatic -> label , $warehouseStatic -> ref );
2020-03-12 12:45:44 +01:00
dol_syslog ( __METHOD__ . ' Error: ' . $langs -> transnoentitiesnoconv ( 'ErrorBatchNoFoundEnoughQuantityForProductInWarehouse' , $productStatic -> label , $warehouseStatic -> ref ), LOG_ERR );
2020-02-21 11:08:34 +01:00
}
}
}
}
}
if ( ! $is_batch_line ) {
$result = $mouvP -> livraison ( $user , $this -> lines [ $i ] -> fk_product , $idwarehouse , $this -> lines [ $i ] -> qty , $this -> lines [ $i ] -> subprice , $langs -> trans ( " InvoiceValidatedInDolibarr " , $num ));
if ( $result < 0 ) {
$error ++ ;
$this -> error = $mouvP -> error ;
}
}
2018-07-06 08:07:38 +02:00
}
}
}
}
}
2022-03-25 17:00:23 +01:00
/*
* Set situation_final to 0 if is a credit note and the invoice source is a invoice situation ( case when invoice situation is at 100 % )
* So we can continue to create new invoice situation
*/
if ( ! $error && $this -> type == self :: TYPE_CREDIT_NOTE && $this -> fk_facture_source > 0 ) {
$invoice_situation = new Facture ( $this -> db );
$result = $invoice_situation -> fetch ( $this -> fk_facture_source );
2022-04-04 10:40:10 +02:00
if ( $result > 0 && $invoice_situation -> type == self :: TYPE_SITUATION && $invoice_situation -> situation_final == 1 ) {
2022-03-25 17:00:23 +01:00
$invoice_situation -> situation_final = 0 ;
// Disable triggers because module can force situation_final to 1 by triggers (ex: SubTotal)
$result = $invoice_situation -> setFinal ( $user , 1 );
}
if ( $result < 0 ) {
$this -> error = $invoice_situation -> error ;
$this -> errors = $invoice_situation -> errors ;
$error ++ ;
}
}
2018-07-06 08:07:38 +02:00
// Trigger calls
2021-02-23 21:09:01 +01:00
if ( ! $error && ! $notrigger ) {
2020-09-08 21:27:28 +02:00
// Call trigger
$result = $this -> call_trigger ( 'BILL_VALIDATE' , $user );
2021-02-23 21:09:01 +01:00
if ( $result < 0 ) {
$error ++ ;
}
2020-09-08 21:27:28 +02:00
// End call triggers
2018-07-06 08:07:38 +02:00
}
2021-02-23 21:09:01 +01:00
if ( ! $error ) {
2018-07-06 08:07:38 +02:00
$this -> oldref = $this -> ref ;
// Rename directory if dir was a temporary ref
2021-02-23 21:09:01 +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-08 10:53:31 +01:00
$sql = 'UPDATE ' . MAIN_DB_PREFIX . " ecm_files set filename = CONCAT(' " . $this -> db -> escape ( $this -> newref ) . " ', SUBSTR(filename, " . ( strlen ( $this -> ref ) + 1 ) . " )), filepath = 'facture/ " . $this -> db -> escape ( $this -> newref ) . " ' " ;
$sql .= " WHERE filename LIKE ' " . $this -> db -> escape ( $this -> ref ) . " %' AND filepath = 'facture/ " . $this -> db -> escape ( $this -> ref ) . " ' and entity = " . $conf -> entity ;
2019-07-28 22:26:55 +02:00
$resql = $this -> db -> query ( $sql );
2021-02-23 21:09:01 +01:00
if ( ! $resql ) {
2021-03-01 20:37:16 +01:00
$error ++ ;
$this -> error = $this -> db -> lasterror ();
2021-02-23 21:09:01 +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-07-06 08:07:38 +02:00
$oldref = dol_sanitizeFileName ( $this -> ref );
$newref = dol_sanitizeFileName ( $num );
$dirsource = $conf -> facture -> dir_output . '/' . $oldref ;
$dirdest = $conf -> facture -> dir_output . '/' . $newref ;
2021-02-23 21:09:01 +01:00
if ( ! $error && file_exists ( $dirsource )) {
2018-07-06 08:07:38 +02:00
dol_syslog ( get_class ( $this ) . " ::validate rename dir " . $dirsource . " into " . $dirdest );
2021-02-23 21:09:01 +01:00
if ( @ rename ( $dirsource , $dirdest )) {
2018-07-06 08:07:38 +02:00
dol_syslog ( " Rename ok " );
2020-09-08 21:27:28 +02:00
// Rename docs starting with $oldref with $newref
$listoffiles = dol_dir_list ( $conf -> facture -> dir_output . '/' . $newref , 'files' , 1 , '^' . preg_quote ( $oldref , '/' ));
2021-02-23 21:09:01 +01:00
foreach ( $listoffiles as $fileentry ) {
2020-09-08 21:27:28 +02:00
$dirsource = $fileentry [ 'name' ];
$dirdest = preg_replace ( '/^' . preg_quote ( $oldref , '/' ) . '/' , $newref , $dirsource );
$dirsource = $fileentry [ 'path' ] . '/' . $dirsource ;
$dirdest = $fileentry [ 'path' ] . '/' . $dirdest ;
@ rename ( $dirsource , $dirdest );
}
2018-07-06 08:07:38 +02:00
}
}
}
}
2021-02-23 21:09:01 +01:00
if ( ! $error && ! $this -> is_last_in_cycle ()) {
if ( ! $this -> updatePriceNextInvoice ( $langs )) {
2018-07-06 08:07:38 +02:00
$error ++ ;
}
}
2018-09-06 14:33:22 +02:00
// Set new ref and define current status
2021-02-23 21:09:01 +01:00
if ( ! $error ) {
2018-07-06 08:07:38 +02:00
$this -> ref = $num ;
2019-11-08 10:53:31 +01:00
$this -> ref = $num ;
$this -> statut = self :: STATUS_VALIDATED ;
2021-03-08 09:14:23 +01:00
$this -> status = self :: STATUS_VALIDATED ;
2019-11-08 10:53:31 +01:00
$this -> brouillon = 0 ;
$this -> date_validation = $now ;
2018-07-06 08:07:38 +02:00
$i = 0 ;
2021-02-23 21:09:01 +01:00
if ( ! empty ( $conf -> global -> INVOICE_USE_SITUATION )) {
2020-09-08 21:27:28 +02:00
$final = true ;
$nboflines = count ( $this -> lines );
while (( $i < $nboflines ) && $final ) {
$final = ( $this -> lines [ $i ] -> situation_percent == 100 );
$i ++ ;
}
2018-07-06 08:07:38 +02:00
2021-02-23 21:09:01 +01:00
if ( empty ( $final )) {
$this -> situation_final = 0 ;
} else {
$this -> situation_final = 1 ;
}
2018-07-06 08:07:38 +02:00
2020-09-08 21:27:28 +02:00
$this -> setFinal ( $user );
}
2018-07-06 08:07:38 +02:00
}
2020-05-21 15:05:19 +02:00
} else {
2018-07-06 08:07:38 +02:00
$error ++ ;
}
2021-02-23 21:09:01 +01:00
if ( ! $error ) {
2018-07-06 08:07:38 +02:00
$this -> db -> commit ();
return 1 ;
2020-05-21 15:05:19 +02:00
} else {
2018-07-06 08:07:38 +02:00
$this -> db -> rollback ();
return - 1 ;
}
}
/**
* Update price of next invoice
*
* @ param Translate $langs Translate object
2021-03-08 09:14:23 +01:00
* @ return bool false if KO , true if OK
2018-07-06 08:07:38 +02:00
*/
2020-09-08 21:27:28 +02:00
public function updatePriceNextInvoice ( & $langs )
2018-07-06 08:07:38 +02:00
{
2021-02-23 21:09:01 +01:00
foreach ( $this -> tab_next_situation_invoice as $next_invoice ) {
2018-07-06 08:07:38 +02:00
$is_last = $next_invoice -> is_last_in_cycle ();
2021-02-23 21:09:01 +01:00
if ( $next_invoice -> statut == self :: STATUS_DRAFT && $is_last != 1 ) {
2018-07-06 08:07:38 +02:00
$this -> error = $langs -> trans ( 'updatePriceNextInvoiceErrorUpdateline' , $next_invoice -> ref );
return false ;
}
$next_invoice -> brouillon = 1 ;
2021-03-08 09:14:23 +01:00
2021-02-23 21:09:01 +01:00
foreach ( $next_invoice -> lines as $line ) {
2019-10-26 18:13:20 +02:00
$result = $next_invoice -> updateline (
2021-02-23 21:09:01 +01:00
$line -> id ,
$line -> desc ,
$line -> subprice ,
$line -> qty ,
$line -> remise_percent ,
$line -> date_start ,
$line -> date_end ,
$line -> tva_tx ,
$line -> localtax1_tx ,
$line -> localtax2_tx ,
'HT' ,
$line -> info_bits ,
$line -> product_type ,
$line -> fk_parent_line ,
0 ,
$line -> fk_fournprice ,
$line -> pa_ht ,
$line -> label ,
$line -> special_code ,
$line -> array_options ,
$line -> situation_percent ,
2019-10-26 18:13:20 +02:00
$line -> fk_unit
);
2018-07-06 08:07:38 +02:00
2021-02-23 21:09:01 +01:00
if ( $result < 0 ) {
2018-07-06 08:07:38 +02:00
$this -> error = $langs -> trans ( 'updatePriceNextInvoiceErrorUpdateline' , $next_invoice -> ref );
return false ;
}
}
break ; // Only the next invoice and not each next invoice
}
return true ;
}
/**
* Set draft status
*
* @ param User $user Object user that modify
* @ param int $idwarehouse Id warehouse to use for stock change .
* @ return int < 0 if KO , > 0 if OK
*/
2019-05-01 09:38:27 +02:00
public function setDraft ( $user , $idwarehouse = - 1 )
2018-07-06 08:07:38 +02:00
{
2020-09-08 21:27:28 +02:00
// phpcs:enable
2019-11-08 10:53:31 +01:00
global $conf , $langs ;
2018-07-06 08:07:38 +02:00
2019-11-08 10:53:31 +01:00
$error = 0 ;
2018-07-06 08:07:38 +02:00
2021-02-23 21:09:01 +01:00
if ( $this -> statut == self :: STATUS_DRAFT ) {
2019-05-01 09:38:27 +02:00
dol_syslog ( __METHOD__ . " already draft status " , LOG_WARNING );
2018-07-06 08:07:38 +02:00
return 0 ;
}
2019-05-01 09:38:27 +02:00
dol_syslog ( __METHOD__ , LOG_DEBUG );
2019-03-21 17:37:56 +01:00
2018-07-06 08:07:38 +02:00
$this -> db -> begin ();
$sql = " UPDATE " . MAIN_DB_PREFIX . " facture " ;
2019-11-08 10:53:31 +01:00
$sql .= " SET fk_statut = " . self :: STATUS_DRAFT ;
2021-08-23 19:33:24 +02:00
$sql .= " WHERE rowid = " . (( int ) $this -> id );
2018-07-06 08:07:38 +02:00
2019-11-08 10:53:31 +01:00
$result = $this -> db -> query ( $sql );
2021-02-23 21:09:01 +01:00
if ( $result ) {
if ( ! $error ) {
2019-11-08 10:53:31 +01:00
$this -> oldcopy = clone $this ;
2019-05-01 09:38:27 +02:00
}
2019-03-21 17:37:56 +01:00
2020-01-31 15:12:17 +01:00
// If we decrease stock on invoice validation, we increase back
2021-02-23 21:09:01 +01:00
if ( $this -> type != self :: TYPE_DEPOSIT && $result >= 0 && ! empty ( $conf -> stock -> enabled ) && ! empty ( $conf -> global -> STOCK_CALCULATE_ON_BILL )) {
2018-07-06 08:07:38 +02:00
require_once DOL_DOCUMENT_ROOT . '/product/stock/class/mouvementstock.class.php' ;
$langs -> load ( " agenda " );
2019-11-08 10:53:31 +01:00
$num = count ( $this -> lines );
2021-02-23 21:09:01 +01:00
for ( $i = 0 ; $i < $num ; $i ++ ) {
if ( $this -> lines [ $i ] -> fk_product > 0 ) {
2018-07-06 08:07:38 +02:00
$mouvP = new MouvementStock ( $this -> db );
$mouvP -> origin = & $this ;
2022-03-22 13:46:55 +01:00
$mouvP -> setOrigin ( $this -> element , $this -> id );
2018-07-06 08:07:38 +02:00
// We decrease stock for product
2021-02-23 21:09:01 +01:00
if ( $this -> type == self :: TYPE_CREDIT_NOTE ) {
$result = $mouvP -> livraison ( $user , $this -> lines [ $i ] -> fk_product , $idwarehouse , $this -> lines [ $i ] -> qty , $this -> lines [ $i ] -> subprice , $langs -> trans ( " InvoiceBackToDraftInDolibarr " , $this -> ref ));
} else {
$result = $mouvP -> reception ( $user , $this -> lines [ $i ] -> fk_product , $idwarehouse , $this -> lines [ $i ] -> qty , 0 , $langs -> trans ( " InvoiceBackToDraftInDolibarr " , $this -> ref )); // we use 0 for price, to not change the weighted average value
}
2018-07-06 08:07:38 +02:00
}
}
}
2021-02-23 21:09:01 +01:00
if ( $error == 0 ) {
2019-11-08 10:53:31 +01:00
$old_statut = $this -> statut ;
2018-07-06 08:07:38 +02:00
$this -> brouillon = 1 ;
$this -> statut = self :: STATUS_DRAFT ;
2021-03-08 09:14:23 +01:00
$this -> status = self :: STATUS_DRAFT ;
2019-03-21 17:37:56 +01:00
2019-05-01 09:38:27 +02:00
// Call trigger
2019-11-08 10:53:31 +01:00
$result = $this -> call_trigger ( 'BILL_UNVALIDATE' , $user );
2021-02-23 21:09:01 +01:00
if ( $result < 0 ) {
2018-07-06 08:07:38 +02:00
$error ++ ;
2019-11-08 10:53:31 +01:00
$this -> statut = $old_statut ;
2021-03-08 09:14:23 +01:00
$this -> status = $old_statut ;
2019-11-08 10:53:31 +01:00
$this -> brouillon = 0 ;
2018-07-06 08:07:38 +02:00
}
2019-05-01 09:38:27 +02:00
// End call triggers
2018-07-06 08:07:38 +02:00
} else {
$this -> db -> rollback ();
return - 1 ;
}
2021-02-23 21:09:01 +01:00
if ( $error == 0 ) {
2018-07-06 08:07:38 +02:00
$this -> db -> commit ();
return 1 ;
2020-05-21 15:05:19 +02:00
} else {
2018-07-06 08:07:38 +02:00
$this -> db -> rollback ();
return - 1 ;
}
2020-05-21 15:05:19 +02:00
} else {
2019-11-08 10:53:31 +01:00
$this -> error = $this -> db -> error ();
2018-07-06 08:07:38 +02:00
$this -> db -> rollback ();
return - 1 ;
}
}
/**
2019-10-19 19:16:28 +02:00
* Add an invoice line into database ( linked to product / service or not ) .
2023-03-19 17:38:22 +01:00
* Note : -> thirdparty must be defined .
2019-10-19 19:16:28 +02:00
* Les parametres sont deja cense etre juste et avec valeurs finales a l ' appel
* de cette methode . Aussi , pour le taux tva , il doit deja avoir ete defini
* par l ' appelant par la methode get_default_tva ( societe_vendeuse , societe_acheteuse , produit )
* et le desc doit deja avoir la bonne valeur ( a l ' appelant de gerer le multilangue )
2018-07-06 08:07:38 +02:00
*
2019-10-19 19:16:28 +02:00
* @ param string $desc Description of line
* @ param double $pu_ht Unit price without tax ( > 0 even for credit note )
* @ param double $qty Quantity
* @ param double $txtva Force Vat rate , - 1 for auto ( Can contain the vat_src_code too with syntax '9.9 (CODE)' )
* @ param double $txlocaltax1 Local tax 1 rate ( deprecated , use instead txtva with code inside )
* @ param double $txlocaltax2 Local tax 2 rate ( deprecated , use instead txtva with code inside )
* @ param int $fk_product Id of predefined product / service
* @ param double $remise_percent Percent of discount on line
* @ param int $date_start Date start of service
* @ param int $date_end Date end of service
* @ param int $ventil Code of dispatching into accountancy
* @ param int $info_bits Bits of type of lines
* @ param int $fk_remise_except Id discount used
* @ param string $price_base_type 'HT' or 'TTC'
* @ param double $pu_ttc Unit price with tax ( > 0 even for credit note )
* @ param int $type Type of line ( 0 = product , 1 = service ) . Not used if fk_product is defined , the type of product is used .
2022-05-03 14:18:48 +02:00
* @ param int $rang Position of line ( - 1 means last value + 1 )
2019-10-19 19:16:28 +02:00
* @ param int $special_code Special code ( also used by externals modules ! )
2020-03-12 09:44:43 +01:00
* @ param string $origin Depend on global conf MAIN_CREATEFROM_KEEP_LINE_ORIGIN_INFORMATION can be 'orderdet' , 'propaldet' ... , else 'order' , 'propal,' ....
* @ param int $origin_id Depend on global conf MAIN_CREATEFROM_KEEP_LINE_ORIGIN_INFORMATION can be Id of origin object ( aka line id ), else object id
2019-10-19 19:16:28 +02:00
* @ param int $fk_parent_line Id of parent line
* @ param int $fk_fournprice Supplier price id ( to calculate margin ) or ''
* @ param int $pa_ht Buying price of line ( to calculate margin ) or ''
* @ param string $label Label of the line ( deprecated , do not use )
* @ param array $array_options extrafields array
* @ param int $situation_percent Situation advance percentage
* @ param int $fk_prev_id Previous situation line id reference
* @ param string $fk_unit Code of the unit to use . Null to use the default one
2020-12-16 10:55:33 +01:00
* @ param double $pu_ht_devise Unit price in foreign currency
2020-09-04 19:32:42 +02:00
* @ param string $ref_ext External reference of the line
2022-05-03 14:18:48 +02:00
* @ param int $noupdateafterinsertline No update after insert of line
2019-10-19 19:16:28 +02:00
* @ return int < 0 if KO , Id of line if OK
2018-07-06 08:07:38 +02:00
*/
2020-09-08 21:27:28 +02:00
public function addline (
$desc ,
$pu_ht ,
$qty ,
$txtva ,
$txlocaltax1 = 0 ,
$txlocaltax2 = 0 ,
$fk_product = 0 ,
$remise_percent = 0 ,
$date_start = '' ,
$date_end = '' ,
$ventil = 0 ,
$info_bits = 0 ,
$fk_remise_except = '' ,
$price_base_type = 'HT' ,
$pu_ttc = 0 ,
2021-12-30 19:28:25 +01:00
$type = 0 ,
2020-09-08 21:27:28 +02:00
$rang = - 1 ,
$special_code = 0 ,
$origin = '' ,
$origin_id = 0 ,
$fk_parent_line = 0 ,
$fk_fournprice = null ,
$pa_ht = 0 ,
$label = '' ,
$array_options = 0 ,
$situation_percent = 100 ,
$fk_prev_id = 0 ,
$fk_unit = null ,
$pu_ht_devise = 0 ,
2022-05-03 14:18:48 +02:00
$ref_ext = '' ,
$noupdateafterinsertline = 0
2020-09-08 21:27:28 +02:00
) {
2018-07-06 08:07:38 +02:00
// Deprecation warning
if ( $label ) {
2019-11-08 10:53:31 +01:00
dol_syslog ( __METHOD__ . " : using line label is deprecated " , LOG_WARNING );
2018-07-06 08:07:38 +02:00
//var_dump(debug_backtrace(false));exit;
}
global $mysoc , $conf , $langs ;
2022-10-07 21:36:30 +02:00
dol_syslog ( get_class ( $this ) . " ::addline id= $this->id , pu_ht= $pu_ht , qty= $qty , txtva= $txtva , txlocaltax1= $txlocaltax1 , txlocaltax2= $txlocaltax2 , fk_product= $fk_product , remise_percent= $remise_percent , date_start= $date_start , date_end= $date_end , ventil= $ventil , info_bits= $info_bits , fk_remise_except= $fk_remise_except , price_base_type= $price_base_type , pu_ttc= $pu_ttc , type= $type , fk_unit= $fk_unit , desc= " . dol_trunc ( $desc , 25 ), LOG_DEBUG );
2019-03-21 21:00:06 +01:00
2021-02-23 21:09:01 +01:00
if ( $this -> statut == self :: STATUS_DRAFT ) {
2018-12-03 12:28:17 +01:00
include_once DOL_DOCUMENT_ROOT . '/core/lib/price.lib.php' ;
2018-07-06 08:07:38 +02:00
2018-12-03 12:28:17 +01:00
// Clean parameters
2021-02-23 21:09:01 +01:00
if ( empty ( $remise_percent )) {
$remise_percent = 0 ;
}
if ( empty ( $qty )) {
$qty = 0 ;
}
if ( empty ( $info_bits )) {
$info_bits = 0 ;
}
if ( empty ( $rang )) {
$rang = 0 ;
}
if ( empty ( $ventil )) {
$ventil = 0 ;
}
if ( empty ( $txtva )) {
$txtva = 0 ;
}
if ( empty ( $txlocaltax1 )) {
$txlocaltax1 = 0 ;
}
if ( empty ( $txlocaltax2 )) {
$txlocaltax2 = 0 ;
}
if ( empty ( $fk_parent_line ) || $fk_parent_line < 0 ) {
$fk_parent_line = 0 ;
}
if ( empty ( $fk_prev_id )) {
$fk_prev_id = 'null' ;
}
if ( ! isset ( $situation_percent ) || $situation_percent > 100 || ( string ) $situation_percent == '' ) {
$situation_percent = 100 ;
}
if ( empty ( $ref_ext )) {
$ref_ext = '' ;
}
2019-11-08 10:53:31 +01:00
$remise_percent = price2num ( $remise_percent );
$qty = price2num ( $qty );
$pu_ht = price2num ( $pu_ht );
$pu_ht_devise = price2num ( $pu_ht_devise );
$pu_ttc = price2num ( $pu_ttc );
$pa_ht = price2num ( $pa_ht );
2018-12-03 12:28:17 +01:00
if ( ! preg_match ( '/\((.*)\)/' , $txtva )) {
2019-11-08 10:53:31 +01:00
$txtva = price2num ( $txtva ); // $txtva can have format '5.0(XXX)' or '5'
2018-12-03 12:28:17 +01:00
}
2019-11-08 10:53:31 +01:00
$txlocaltax1 = price2num ( $txlocaltax1 );
$txlocaltax2 = price2num ( $txlocaltax2 );
2013-04-18 08:40:29 +02:00
2021-02-23 21:09:01 +01:00
if ( $price_base_type == 'HT' ) {
2019-11-08 10:53:31 +01:00
$pu = $pu_ht ;
2020-05-21 15:05:19 +02:00
} else {
2019-11-08 10:53:31 +01:00
$pu = $pu_ttc ;
2018-12-03 12:28:17 +01:00
}
2013-04-18 08:40:29 +02:00
2018-12-03 12:28:17 +01:00
// Check parameters
2021-02-23 21:09:01 +01:00
if ( $type < 0 ) {
return - 1 ;
}
2019-03-27 15:42:53 +01:00
2019-03-24 14:30:00 +01:00
if ( $date_start && $date_end && $date_start > $date_end ) {
$langs -> load ( " errors " );
2019-11-08 10:53:31 +01:00
$this -> error = $langs -> trans ( 'ErrorStartDateGreaterEnd' );
2019-03-24 14:30:00 +01:00
return - 1 ;
}
2018-07-06 08:07:38 +02:00
$this -> db -> begin ();
2019-11-08 10:53:31 +01:00
$product_type = $type ;
2021-07-04 21:02:02 +02:00
if ( ! empty ( $fk_product ) && $fk_product > 0 ) {
2019-11-08 10:53:31 +01:00
$product = new Product ( $this -> db );
$result = $product -> fetch ( $fk_product );
$product_type = $product -> type ;
2018-07-06 08:07:38 +02:00
2019-11-08 10:53:31 +01:00
if ( ! empty ( $conf -> global -> STOCK_MUST_BE_ENOUGH_FOR_INVOICE ) && $product_type == 0 && $product -> stock_reel < $qty ) {
2020-09-08 21:27:28 +02:00
$langs -> load ( " errors " );
$this -> error = $langs -> trans ( 'ErrorStockIsNotEnoughToAddProductOnInvoice' , $product -> ref );
2018-07-06 08:07:38 +02:00
$this -> db -> rollback ();
return - 3 ;
}
}
2019-11-08 10:53:31 +01:00
$localtaxes_type = getLocalTaxesFromRate ( $txtva , 0 , $this -> thirdparty , $mysoc );
2018-12-03 12:28:17 +01:00
// Clean vat code
2020-03-26 02:13:34 +01:00
$reg = array ();
2019-11-08 10:53:31 +01:00
$vat_src_code = '' ;
2021-02-23 21:09:01 +01:00
if ( preg_match ( '/\((.*)\)/' , $txtva , $reg )) {
2018-12-03 12:28:17 +01:00
$vat_src_code = $reg [ 1 ];
2019-11-08 10:53:31 +01:00
$txtva = preg_replace ( '/\s*\(.*\)/' , '' , $txtva ); // Remove code into vatrate.
2018-12-03 12:28:17 +01:00
}
2018-07-06 08:07:38 +02:00
// Calcul du total TTC et de la TVA pour la ligne a partir de
// qty, pu, remise_percent et txtva
// TRES IMPORTANT: C'est au moment de l'insertion ligne qu'on doit stocker
// la part ht, tva et ttc, et ce au niveau de la ligne qui a son propre taux tva.
$tabprice = calcul_price_total ( $qty , $pu , $remise_percent , $txtva , $txlocaltax1 , $txlocaltax2 , 0 , $price_base_type , $info_bits , $product_type , $mysoc , $localtaxes_type , $situation_percent , $this -> multicurrency_tx , $pu_ht_devise );
$total_ht = $tabprice [ 0 ];
$total_tva = $tabprice [ 1 ];
$total_ttc = $tabprice [ 2 ];
$total_localtax1 = $tabprice [ 9 ];
$total_localtax2 = $tabprice [ 10 ];
$pu_ht = $tabprice [ 3 ];
// MultiCurrency
2019-11-08 10:53:31 +01:00
$multicurrency_total_ht = $tabprice [ 16 ];
2020-09-08 21:27:28 +02:00
$multicurrency_total_tva = $tabprice [ 17 ];
$multicurrency_total_ttc = $tabprice [ 18 ];
2018-07-06 08:07:38 +02:00
$pu_ht_devise = $tabprice [ 19 ];
// Rank to use
2019-08-10 00:46:20 +02:00
$ranktouse = $rang ;
2021-02-23 21:09:01 +01:00
if ( $ranktouse == - 1 ) {
2018-07-06 08:07:38 +02:00
$rangmax = $this -> line_max ( $fk_parent_line );
2019-08-10 00:46:20 +02:00
$ranktouse = $rangmax + 1 ;
2018-07-06 08:07:38 +02:00
}
// Insert line
2019-11-08 10:53:31 +01:00
$this -> line = new FactureLigne ( $this -> db );
2018-07-06 08:07:38 +02:00
$this -> line -> context = $this -> context ;
2019-11-08 10:53:31 +01:00
$this -> line -> fk_facture = $this -> id ;
$this -> line -> label = $label ; // deprecated
$this -> line -> desc = $desc ;
2020-09-04 19:32:42 +02:00
$this -> line -> ref_ext = $ref_ext ;
2018-07-06 08:07:38 +02:00
2021-11-08 02:57:21 +01:00
$this -> line -> qty = ( $this -> type == self :: TYPE_CREDIT_NOTE ? abs ( $qty ) : $qty ); // For credit note, quantity is always positive and unit price negative
$this -> line -> subprice = ( $this -> type == self :: TYPE_CREDIT_NOTE ? - abs ( $pu_ht ) : $pu_ht ); // For credit note, unit price always negative, always positive otherwise
2018-07-06 08:07:38 +02:00
2019-11-08 10:53:31 +01:00
$this -> line -> vat_src_code = $vat_src_code ;
$this -> line -> tva_tx = $txtva ;
$this -> line -> localtax1_tx = ( $total_localtax1 ? $localtaxes_type [ 1 ] : 0 );
$this -> line -> localtax2_tx = ( $total_localtax2 ? $localtaxes_type [ 3 ] : 0 );
2020-12-22 17:33:17 +01:00
$this -> line -> localtax1_type = empty ( $localtaxes_type [ 0 ]) ? '' : $localtaxes_type [ 0 ];
$this -> line -> localtax2_type = empty ( $localtaxes_type [ 2 ]) ? '' : $localtaxes_type [ 2 ];
2018-07-06 08:07:38 +02:00
2021-11-08 02:57:21 +01:00
$this -> line -> total_ht = (( $this -> type == self :: TYPE_CREDIT_NOTE || $qty < 0 ) ? - abs ( $total_ht ) : $total_ht ); // For credit note and if qty is negative, total is negative
$this -> line -> total_ttc = (( $this -> type == self :: TYPE_CREDIT_NOTE || $qty < 0 ) ? - abs ( $total_ttc ) : $total_ttc ); // For credit note and if qty is negative, total is negative
$this -> line -> total_tva = (( $this -> type == self :: TYPE_CREDIT_NOTE || $qty < 0 ) ? - abs ( $total_tva ) : $total_tva ); // For credit note and if qty is negative, total is negative
$this -> line -> total_localtax1 = (( $this -> type == self :: TYPE_CREDIT_NOTE || $qty < 0 ) ? - abs ( $total_localtax1 ) : $total_localtax1 ); // For credit note and if qty is negative, total is negative
$this -> line -> total_localtax2 = (( $this -> type == self :: TYPE_CREDIT_NOTE || $qty < 0 ) ? - abs ( $total_localtax2 ) : $total_localtax2 ); // For credit note and if qty is negative, total is negative
2019-11-08 10:53:31 +01:00
$this -> line -> fk_product = $fk_product ;
$this -> line -> product_type = $product_type ;
$this -> line -> remise_percent = $remise_percent ;
$this -> line -> date_start = $date_start ;
$this -> line -> date_end = $date_end ;
$this -> line -> ventil = $ventil ;
$this -> line -> rang = $ranktouse ;
$this -> line -> info_bits = $info_bits ;
$this -> line -> fk_remise_except = $fk_remise_except ;
$this -> line -> special_code = $special_code ;
$this -> line -> fk_parent_line = $fk_parent_line ;
$this -> line -> origin = $origin ;
$this -> line -> origin_id = $origin_id ;
2018-07-06 08:07:38 +02:00
$this -> line -> situation_percent = $situation_percent ;
$this -> line -> fk_prev_id = $fk_prev_id ;
2019-11-08 10:53:31 +01:00
$this -> line -> fk_unit = $fk_unit ;
2018-07-06 08:07:38 +02:00
// infos marge
$this -> line -> fk_fournprice = $fk_fournprice ;
$this -> line -> pa_ht = $pa_ht ;
// Multicurrency
2019-11-08 10:53:31 +01:00
$this -> line -> fk_multicurrency = $this -> fk_multicurrency ;
$this -> line -> multicurrency_code = $this -> multicurrency_code ;
2021-11-08 02:57:21 +01:00
$this -> line -> multicurrency_subprice = ( $this -> type == self :: TYPE_CREDIT_NOTE ? - abs ( $pu_ht_devise ) : $pu_ht_devise ); // For credit note, unit price always negative, always positive otherwise
$this -> line -> multicurrency_total_ht = (( $this -> type == self :: TYPE_CREDIT_NOTE || $qty < 0 ) ? - abs ( $multicurrency_total_ht ) : $multicurrency_total_ht ); // For credit note and if qty is negative, total is negative
$this -> line -> multicurrency_total_tva = (( $this -> type == self :: TYPE_CREDIT_NOTE || $qty < 0 ) ? - abs ( $multicurrency_total_tva ) : $multicurrency_total_tva ); // For credit note and if qty is negative, total is negative
$this -> line -> multicurrency_total_ttc = (( $this -> type == self :: TYPE_CREDIT_NOTE || $qty < 0 ) ? - abs ( $multicurrency_total_ttc ) : $multicurrency_total_ttc ); // For credit note and if qty is negative, total is negative
2018-07-06 08:07:38 +02:00
2019-11-08 10:53:31 +01:00
if ( is_array ( $array_options ) && count ( $array_options ) > 0 ) {
$this -> line -> array_options = $array_options ;
2018-07-06 08:07:38 +02:00
}
2019-11-08 10:53:31 +01:00
$result = $this -> line -> insert ();
2021-02-23 21:09:01 +01:00
if ( $result > 0 ) {
2018-07-06 08:07:38 +02:00
// Reorder if child line
2021-02-23 21:09:01 +01:00
if ( ! empty ( $fk_parent_line )) {
$this -> line_order ( true , 'DESC' );
2021-11-16 16:15:55 +01:00
} elseif ( $ranktouse > 0 && $ranktouse <= count ( $this -> lines )) { // Update all rank of all other lines
2021-11-23 10:44:43 +01:00
$linecount = count ( $this -> lines );
for ( $ii = $ranktouse ; $ii <= $linecount ; $ii ++ ) {
2021-11-16 14:09:18 +01:00
$this -> updateRangOfLine ( $this -> lines [ $ii - 1 ] -> id , $ii + 1 );
}
2021-02-23 21:09:01 +01:00
}
2018-07-06 08:07:38 +02:00
// Mise a jour informations denormalisees au niveau de la facture meme
2022-05-03 14:18:48 +02:00
if ( empty ( $noupdateafterinsertline )) {
$result = $this -> update_price ( 1 , 'auto' , 0 , $mysoc ); // The addline method is designed to add line from user input so total calculation with update_price must be done using 'auto' mode.
}
2018-07-06 08:07:38 +02:00
2021-02-23 21:09:01 +01:00
if ( $result > 0 ) {
2018-07-06 08:07:38 +02:00
$this -> db -> commit ();
return $this -> line -> id ;
2020-05-21 15:05:19 +02:00
} else {
2019-11-08 10:53:31 +01:00
$this -> error = $this -> db -> lasterror ();
2018-07-06 08:07:38 +02:00
$this -> db -> rollback ();
return - 1 ;
}
2020-05-21 15:05:19 +02:00
} else {
2019-11-08 10:53:31 +01:00
$this -> error = $this -> line -> error ;
2021-02-08 20:44:40 +01:00
$this -> errors = $this -> line -> errors ;
2018-07-06 08:07:38 +02:00
$this -> db -> rollback ();
return - 2 ;
}
2020-05-21 15:05:19 +02:00
} else {
2020-09-04 16:30:34 +02:00
dol_syslog ( get_class ( $this ) . " ::addline status of invoice must be Draft to allow use of ->addline() " , LOG_ERR );
2018-07-06 08:07:38 +02:00
return - 3 ;
}
}
/**
* Update a detail line
*
* @ param int $rowid Id of line to update
* @ param string $desc Description of line
* @ param double $pu Prix unitaire ( HT ou TTC selon price_base_type ) ( > 0 even for credit note lines )
* @ param double $qty Quantity
2019-03-18 13:45:24 +01:00
* @ param double $remise_percent Percentage discount of the line
* @ param int $date_start Date de debut de validite du service
* @ param int $date_end Date de fin de validite du service
2018-07-06 08:07:38 +02:00
* @ param double $txtva VAT Rate ( Can be '8.5' , '8.5 (ABC)' )
* @ param double $txlocaltax1 Local tax 1 rate
* @ param double $txlocaltax2 Local tax 2 rate
* @ param string $price_base_type HT or TTC
* @ param int $info_bits Miscellaneous informations
* @ param int $type Type of line ( 0 = product , 1 = service )
* @ param int $fk_parent_line Id of parent line ( 0 in most cases , used by modules adding sublevels into lines ) .
* @ param int $skip_update_total Keep fields total_xxx to 0 ( used for special lines by some modules )
* @ param int $fk_fournprice Id of origin supplier price
* @ param int $pa_ht Price ( without tax ) of product when it was bought
* @ param string $label Label of the line ( deprecated , do not use )
* @ param int $special_code Special code ( also used by externals modules ! )
2020-09-08 21:27:28 +02:00
* @ param array $array_options extrafields array
2018-07-06 08:07:38 +02:00
* @ param int $situation_percent Situation advance percentage
* @ param string $fk_unit Code of the unit to use . Null to use the default one
* @ param double $pu_ht_devise Unit price in currency
* @ param int $notrigger disable line update trigger
2020-09-04 19:32:42 +02:00
* @ param string $ref_ext External reference of the line
2022-05-11 15:34:16 +02:00
* @ param integer $rang rank of line
2018-07-06 08:07:38 +02:00
* @ return int < 0 if KO , > 0 if OK
*/
2022-05-11 15:42:27 +02:00
public function updateline ( $rowid , $desc , $pu , $qty , $remise_percent , $date_start , $date_end , $txtva , $txlocaltax1 = 0 , $txlocaltax2 = 0 , $price_base_type = 'HT' , $info_bits = 0 , $type = self :: TYPE_STANDARD , $fk_parent_line = 0 , $skip_update_total = 0 , $fk_fournprice = null , $pa_ht = 0 , $label = '' , $special_code = 0 , $array_options = 0 , $situation_percent = 100 , $fk_unit = null , $pu_ht_devise = 0 , $notrigger = 0 , $ref_ext = '' , $rang = 0 )
2018-07-06 08:07:38 +02:00
{
2019-11-08 10:53:31 +01:00
global $conf , $user ;
2018-07-06 08:07:38 +02:00
// Deprecation warning
if ( $label ) {
2019-11-08 10:53:31 +01:00
dol_syslog ( __METHOD__ . " : using line label is deprecated " , LOG_WARNING );
2018-07-06 08:07:38 +02:00
}
include_once DOL_DOCUMENT_ROOT . '/core/lib/price.lib.php' ;
2019-11-08 10:53:31 +01:00
global $mysoc , $langs ;
2018-07-06 08:07:38 +02:00
dol_syslog ( get_class ( $this ) . " ::updateline rowid= $rowid , desc= $desc , pu= $pu , qty= $qty , remise_percent= $remise_percent , date_start= $date_start , date_end= $date_end , txtva= $txtva , txlocaltax1= $txlocaltax1 , txlocaltax2= $txlocaltax2 , price_base_type= $price_base_type , info_bits= $info_bits , type= $type , fk_parent_line= $fk_parent_line pa_ht= $pa_ht , special_code= $special_code , fk_unit= $fk_unit , pu_ht_devise= $pu_ht_devise " , LOG_DEBUG );
2021-03-08 09:14:23 +01:00
if ( $this -> statut == self :: STATUS_DRAFT ) {
2021-02-23 21:09:01 +01:00
if ( ! $this -> is_last_in_cycle () && empty ( $this -> error )) {
if ( ! $this -> checkProgressLine ( $rowid , $situation_percent )) {
if ( ! $this -> error ) {
$this -> error = $langs -> trans ( 'invoiceLineProgressError' );
}
2018-07-06 08:07:38 +02:00
return - 3 ;
}
}
2019-03-27 15:42:53 +01:00
2019-03-24 14:30:00 +01:00
if ( $date_start && $date_end && $date_start > $date_end ) {
$langs -> load ( " errors " );
2019-11-08 10:53:31 +01:00
$this -> error = $langs -> trans ( 'ErrorStartDateGreaterEnd' );
2019-03-24 14:30:00 +01:00
return - 1 ;
}
2018-07-06 08:07:38 +02:00
$this -> db -> begin ();
// Clean parameters
2021-02-23 21:09:01 +01:00
if ( empty ( $qty )) {
$qty = 0 ;
}
if ( empty ( $fk_parent_line ) || $fk_parent_line < 0 ) {
$fk_parent_line = 0 ;
}
if ( empty ( $special_code ) || $special_code == 3 ) {
$special_code = 0 ;
}
if ( ! isset ( $situation_percent ) || $situation_percent > 100 || ( string ) $situation_percent == '' ) {
$situation_percent = 100 ;
}
if ( empty ( $ref_ext )) {
$ref_ext = '' ;
}
2018-07-06 08:07:38 +02:00
2019-11-08 10:53:31 +01:00
$remise_percent = price2num ( $remise_percent );
2018-07-06 08:07:38 +02:00
$qty = price2num ( $qty );
$pu = price2num ( $pu );
2020-09-08 21:27:28 +02:00
$pu_ht_devise = price2num ( $pu_ht_devise );
2021-06-14 15:37:02 +02:00
$pa_ht = price2num ( $pa_ht );
2021-01-02 16:51:34 +01:00
if ( ! preg_match ( '/\((.*)\)/' , $txtva )) {
$txtva = price2num ( $txtva ); // $txtva can have format '5.0(XXX)' or '5'
}
2018-07-06 08:07:38 +02:00
$txlocaltax1 = price2num ( $txlocaltax1 );
$txlocaltax2 = price2num ( $txlocaltax2 );
// Check parameters
2021-02-23 21:09:01 +01:00
if ( $type < 0 ) {
return - 1 ;
}
2018-07-06 08:07:38 +02:00
// Calculate total with, without tax and tax from qty, pu, remise_percent and txtva
// TRES IMPORTANT: C'est au moment de l'insertion ligne qu'on doit stocker
// la part ht, tva et ttc, et ce au niveau de la ligne qui a son propre taux tva.
2019-11-08 10:53:31 +01:00
$localtaxes_type = getLocalTaxesFromRate ( $txtva , 0 , $this -> thirdparty , $mysoc );
2018-07-06 08:07:38 +02:00
// Clean vat code
2020-11-27 15:45:12 +01:00
$reg = array ();
2020-09-08 21:27:28 +02:00
$vat_src_code = '' ;
2021-02-23 21:09:01 +01:00
if ( preg_match ( '/\((.*)\)/' , $txtva , $reg )) {
2020-09-08 21:27:28 +02:00
$vat_src_code = $reg [ 1 ];
$txtva = preg_replace ( '/\s*\(.*\)/' , '' , $txtva ); // Remove code into vatrate.
}
2018-07-06 08:07:38 +02:00
2019-11-08 10:53:31 +01:00
$tabprice = calcul_price_total ( $qty , $pu , $remise_percent , $txtva , $txlocaltax1 , $txlocaltax2 , 0 , $price_base_type , $info_bits , $type , $mysoc , $localtaxes_type , $situation_percent , $this -> multicurrency_tx , $pu_ht_devise );
2018-07-06 08:07:38 +02:00
$total_ht = $tabprice [ 0 ];
$total_tva = $tabprice [ 1 ];
$total_ttc = $tabprice [ 2 ];
2019-11-08 10:53:31 +01:00
$total_localtax1 = $tabprice [ 9 ];
$total_localtax2 = $tabprice [ 10 ];
2018-07-06 08:07:38 +02:00
$pu_ht = $tabprice [ 3 ];
$pu_tva = $tabprice [ 4 ];
$pu_ttc = $tabprice [ 5 ];
// MultiCurrency
2019-11-08 10:53:31 +01:00
$multicurrency_total_ht = $tabprice [ 16 ];
2020-09-08 21:27:28 +02:00
$multicurrency_total_tva = $tabprice [ 17 ];
$multicurrency_total_ttc = $tabprice [ 18 ];
2018-07-06 08:07:38 +02:00
$pu_ht_devise = $tabprice [ 19 ];
// Old properties: $price, $remise (deprecated)
$price = $pu ;
$remise = 0 ;
2021-02-23 21:09:01 +01:00
if ( $remise_percent > 0 ) {
2019-01-27 11:55:16 +01:00
$remise = round (( $pu * $remise_percent / 100 ), 2 );
2018-07-06 08:07:38 +02:00
$price = ( $pu - $remise );
}
2019-11-08 10:53:31 +01:00
$price = price2num ( $price );
2018-07-06 08:07:38 +02:00
//Fetch current line from the database and then clone the object and set it in $oldline property
$line = new FactureLigne ( $this -> db );
$line -> fetch ( $rowid );
2020-01-25 14:03:24 +01:00
$line -> fetch_optionals ();
2018-07-06 08:07:38 +02:00
2021-02-23 21:09:01 +01:00
if ( ! empty ( $line -> fk_product )) {
2019-11-08 10:53:31 +01:00
$product = new Product ( $this -> db );
$result = $product -> fetch ( $line -> fk_product );
$product_type = $product -> type ;
2018-07-06 08:07:38 +02:00
2019-11-08 10:53:31 +01:00
if ( ! empty ( $conf -> global -> STOCK_MUST_BE_ENOUGH_FOR_INVOICE ) && $product_type == 0 && $product -> stock_reel < $qty ) {
2020-09-08 21:27:28 +02:00
$langs -> load ( " errors " );
$this -> error = $langs -> trans ( 'ErrorStockIsNotEnoughToAddProductOnInvoice' , $product -> ref );
2018-07-06 08:07:38 +02:00
$this -> db -> rollback ();
return - 3 ;
}
}
2018-07-05 11:52:41 +02:00
2018-07-06 08:07:38 +02:00
$staticline = clone $line ;
2018-07-05 11:52:41 +02:00
2018-07-06 08:07:38 +02:00
$line -> oldline = $staticline ;
$this -> line = $line ;
2020-09-08 21:27:28 +02:00
$this -> line -> context = $this -> context ;
2022-05-11 15:34:16 +02:00
$this -> line -> rang = $rang ;
2018-07-05 11:52:41 +02:00
2018-07-06 08:07:38 +02:00
// Reorder if fk_parent_line change
2021-02-23 21:09:01 +01:00
if ( ! empty ( $fk_parent_line ) && ! empty ( $staticline -> fk_parent_line ) && $fk_parent_line != $staticline -> fk_parent_line ) {
2018-07-06 08:07:38 +02:00
$rangmax = $this -> line_max ( $fk_parent_line );
$this -> line -> rang = $rangmax + 1 ;
}
2020-01-30 01:48:28 +01:00
$this -> line -> id = $rowid ;
2021-02-08 18:30:09 +01:00
$this -> line -> rowid = $rowid ;
$this -> line -> label = $label ;
2019-11-08 10:53:31 +01:00
$this -> line -> desc = $desc ;
2020-09-08 21:27:28 +02:00
$this -> line -> ref_ext = $ref_ext ;
2019-11-08 10:53:31 +01:00
$this -> line -> qty = ( $this -> type == self :: TYPE_CREDIT_NOTE ? abs ( $qty ) : $qty ); // For credit note, quantity is always positive and unit price negative
2018-07-06 08:07:38 +02:00
2019-11-08 10:53:31 +01:00
$this -> line -> vat_src_code = $vat_src_code ;
$this -> line -> tva_tx = $txtva ;
2018-07-06 08:07:38 +02:00
$this -> line -> localtax1_tx = $txlocaltax1 ;
$this -> line -> localtax2_tx = $txlocaltax2 ;
2020-12-22 17:33:17 +01:00
$this -> line -> localtax1_type = empty ( $localtaxes_type [ 0 ]) ? '' : $localtaxes_type [ 0 ];
$this -> line -> localtax2_type = empty ( $localtaxes_type [ 2 ]) ? '' : $localtaxes_type [ 2 ];
2018-07-06 08:07:38 +02:00
$this -> line -> remise_percent = $remise_percent ;
2020-09-15 11:18:21 +02:00
$this -> line -> subprice = ( $this -> type == self :: TYPE_CREDIT_NOTE ? - abs ( $pu_ht ) : $pu_ht ); // For credit note, unit price always negative, always positive otherwise
2019-11-08 10:53:31 +01:00
$this -> line -> date_start = $date_start ;
2018-07-06 08:07:38 +02:00
$this -> line -> date_end = $date_end ;
2019-11-08 10:53:31 +01:00
$this -> line -> total_ht = (( $this -> type == self :: TYPE_CREDIT_NOTE || $qty < 0 ) ? - abs ( $total_ht ) : $total_ht ); // For credit note and if qty is negative, total is negative
$this -> line -> total_tva = (( $this -> type == self :: TYPE_CREDIT_NOTE || $qty < 0 ) ? - abs ( $total_tva ) : $total_tva );
2018-07-06 08:07:38 +02:00
$this -> line -> total_localtax1 = $total_localtax1 ;
$this -> line -> total_localtax2 = $total_localtax2 ;
2019-11-08 10:53:31 +01:00
$this -> line -> total_ttc = (( $this -> type == self :: TYPE_CREDIT_NOTE || $qty < 0 ) ? - abs ( $total_ttc ) : $total_ttc );
2018-07-06 08:07:38 +02:00
$this -> line -> info_bits = $info_bits ;
$this -> line -> special_code = $special_code ;
$this -> line -> product_type = $type ;
2019-11-08 10:53:31 +01:00
$this -> line -> fk_parent_line = $fk_parent_line ;
$this -> line -> skip_update_total = $skip_update_total ;
$this -> line -> situation_percent = $situation_percent ;
$this -> line -> fk_unit = $fk_unit ;
2018-07-06 08:07:38 +02:00
$this -> line -> fk_fournprice = $fk_fournprice ;
$this -> line -> pa_ht = $pa_ht ;
// Multicurrency
2020-09-15 11:18:21 +02:00
$this -> line -> multicurrency_subprice = ( $this -> type == self :: TYPE_CREDIT_NOTE ? - abs ( $pu_ht_devise ) : $pu_ht_devise ); // For credit note, unit price always negative, always positive otherwise
$this -> line -> multicurrency_total_ht = (( $this -> type == self :: TYPE_CREDIT_NOTE || $qty < 0 ) ? - abs ( $multicurrency_total_ht ) : $multicurrency_total_ht ); // For credit note and if qty is negative, total is negative
$this -> line -> multicurrency_total_tva = (( $this -> type == self :: TYPE_CREDIT_NOTE || $qty < 0 ) ? - abs ( $multicurrency_total_tva ) : $multicurrency_total_tva );
$this -> line -> multicurrency_total_ttc = (( $this -> type == self :: TYPE_CREDIT_NOTE || $qty < 0 ) ? - abs ( $multicurrency_total_ttc ) : $multicurrency_total_ttc );
2018-07-06 08:07:38 +02:00
2019-11-08 10:53:31 +01:00
if ( is_array ( $array_options ) && count ( $array_options ) > 0 ) {
2020-01-25 14:03:24 +01:00
// We replace values in this->line->array_options only for entries defined into $array_options
2020-01-30 01:48:28 +01:00
foreach ( $array_options as $key => $value ) {
2020-01-25 14:03:24 +01:00
$this -> line -> array_options [ $key ] = $array_options [ $key ];
}
2018-07-06 08:07:38 +02:00
}
2019-11-08 10:53:31 +01:00
$result = $this -> line -> update ( $user , $notrigger );
2021-02-23 21:09:01 +01:00
if ( $result > 0 ) {
2018-07-06 08:07:38 +02:00
// Reorder if child line
2021-02-23 21:09:01 +01:00
if ( ! empty ( $fk_parent_line )) {
$this -> line_order ( true , 'DESC' );
}
2018-07-06 08:07:38 +02:00
// Mise a jour info denormalisees au niveau facture
2023-06-29 16:50:21 +02:00
$this -> update_price ( 1 , 'auto' );
2018-07-06 08:07:38 +02:00
$this -> db -> commit ();
return $result ;
2020-05-21 15:05:19 +02:00
} else {
2020-09-08 21:27:28 +02:00
$this -> error = $this -> line -> error ;
2018-07-06 08:07:38 +02:00
$this -> db -> rollback ();
return - 1 ;
}
2020-05-21 15:05:19 +02:00
} else {
2019-11-08 10:53:31 +01:00
$this -> error = " Invoice statut makes operation forbidden " ;
2018-07-06 08:07:38 +02:00
return - 2 ;
}
}
/**
* Check if the percent edited is lower of next invoice line
*
* @ param int $idline id of line to check
* @ param float $situation_percent progress percentage need to be test
* @ return false if KO , true if OK
*/
2020-09-08 21:27:28 +02:00
public function checkProgressLine ( $idline , $situation_percent )
2018-07-06 08:07:38 +02:00
{
$sql = 'SELECT fd.situation_percent FROM ' . MAIN_DB_PREFIX . ' facturedet fd
INNER JOIN '.MAIN_DB_PREFIX.' facture f ON ( fd . fk_facture = f . rowid )
2021-03-30 11:36:50 +02:00
WHERE fd . fk_prev_id = '.((int) $idline).' AND f . fk_statut <> 0 ' ;
2018-07-05 11:52:41 +02:00
2018-07-06 08:07:38 +02:00
$result = $this -> db -> query ( $sql );
2021-02-23 21:09:01 +01:00
if ( ! $result ) {
2019-11-08 10:53:31 +01:00
$this -> error = $this -> db -> error ();
2018-07-06 08:07:38 +02:00
return false ;
}
$obj = $this -> db -> fetch_object ( $result );
2021-02-23 21:09:01 +01:00
if ( $obj === null ) {
return true ;
} else {
return $situation_percent < $obj -> situation_percent ;
}
2018-07-06 08:07:38 +02:00
}
2020-09-08 21:27:28 +02:00
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2018-07-06 08:07:38 +02:00
/**
* Update invoice line with percentage
*
2022-04-07 15:59:42 +02:00
* @ param FactureLigne $line Invoice line
* @ param int $percent Percentage
* @ param boolean $update_price Update object price
2018-07-06 08:07:38 +02:00
* @ return void
*/
2022-04-07 15:59:42 +02:00
public function update_percent ( $line , $percent , $update_price = true )
2018-07-06 08:07:38 +02:00
{
2020-09-08 21:27:28 +02:00
// phpcs:enable
global $mysoc , $user ;
2018-07-06 08:07:38 +02:00
2020-09-08 21:27:28 +02:00
// Progress should never be changed for discount lines
2021-02-23 21:09:01 +01:00
if (( $line -> info_bits & 2 ) == 2 ) {
2020-09-08 21:27:28 +02:00
return ;
}
2019-05-22 10:46:38 +02:00
2019-05-26 11:36:16 +02:00
include_once DOL_DOCUMENT_ROOT . '/core/lib/price.lib.php' ;
2018-07-06 08:07:38 +02:00
// Cap percentages to 100
2021-02-23 21:09:01 +01:00
if ( $percent > 100 ) {
$percent = 100 ;
}
2018-07-06 08:07:38 +02:00
$line -> situation_percent = $percent ;
$tabprice = calcul_price_total ( $line -> qty , $line -> subprice , $line -> remise_percent , $line -> tva_tx , $line -> localtax1_tx , $line -> localtax2_tx , 0 , 'HT' , 0 , $line -> product_type , $mysoc , '' , $percent );
$line -> total_ht = $tabprice [ 0 ];
$line -> total_tva = $tabprice [ 1 ];
$line -> total_ttc = $tabprice [ 2 ];
$line -> total_localtax1 = $tabprice [ 9 ];
$line -> total_localtax2 = $tabprice [ 10 ];
$line -> multicurrency_total_ht = $tabprice [ 16 ];
$line -> multicurrency_total_tva = $tabprice [ 17 ];
$line -> multicurrency_total_ttc = $tabprice [ 18 ];
$line -> update ( $user );
2022-04-07 15:59:42 +02:00
// sometimes it is better to not update price for each line, ie when updating situation on all lines
if ( $update_price ) {
$this -> update_price ( 1 );
}
2018-07-06 08:07:38 +02:00
}
/**
* Delete line in database
*
* @ param int $rowid Id of line to delete
* @ return int < 0 if KO , > 0 if OK
*/
2020-09-08 21:27:28 +02:00
public function deleteline ( $rowid )
2018-07-06 08:07:38 +02:00
{
2020-09-08 21:27:28 +02:00
global $user ;
2018-07-05 11:52:41 +02:00
2021-04-25 15:55:36 +02:00
dol_syslog ( get_class ( $this ) . " ::deleteline rowid= " . (( int ) $rowid ), LOG_DEBUG );
2018-07-05 11:52:41 +02:00
2021-03-08 09:14:23 +01:00
if ( $this -> statut != self :: STATUS_DRAFT ) {
2019-11-08 10:53:31 +01:00
$this -> error = 'ErrorDeleteLineNotAllowedByObjectStatus' ;
2018-07-06 08:07:38 +02:00
return - 1 ;
}
2018-07-05 11:52:41 +02:00
2018-07-06 08:07:38 +02:00
$this -> db -> begin ();
2018-07-05 11:52:41 +02:00
2021-04-06 09:15:34 +02:00
// Free discount linked to invoice line
2018-07-06 08:07:38 +02:00
$sql = 'UPDATE ' . MAIN_DB_PREFIX . 'societe_remise_except' ;
2019-11-08 10:53:31 +01:00
$sql .= ' SET fk_facture_line = NULL' ;
2021-03-30 11:36:50 +02:00
$sql .= ' WHERE fk_facture_line = ' . (( int ) $rowid );
2018-07-05 11:52:41 +02:00
2018-07-06 08:07:38 +02:00
dol_syslog ( get_class ( $this ) . " ::deleteline " , LOG_DEBUG );
$result = $this -> db -> query ( $sql );
2021-02-23 21:09:01 +01:00
if ( ! $result ) {
2019-11-08 10:53:31 +01:00
$this -> error = $this -> db -> error ();
2018-07-06 08:07:38 +02:00
$this -> db -> rollback ();
return - 1 ;
}
2018-07-05 11:52:41 +02:00
2019-11-08 10:53:31 +01:00
$line = new FactureLigne ( $this -> db );
2018-07-05 11:52:41 +02:00
2020-09-08 21:27:28 +02:00
$line -> context = $this -> context ;
2018-07-05 11:52:41 +02:00
2018-07-06 08:07:38 +02:00
// For triggers
$result = $line -> fetch ( $rowid );
2021-02-23 21:09:01 +01:00
if ( ! ( $result > 0 )) {
dol_print_error ( $this -> db , $line -> error , $line -> errors );
}
2018-07-06 08:07:38 +02:00
2021-02-23 21:09:01 +01:00
if ( $line -> delete ( $user ) > 0 ) {
2019-11-08 10:53:31 +01:00
$result = $this -> update_price ( 1 );
2018-07-06 08:07:38 +02:00
2021-02-23 21:09:01 +01:00
if ( $result > 0 ) {
2018-07-06 08:07:38 +02:00
$this -> db -> commit ();
return 1 ;
2020-05-21 15:05:19 +02:00
} else {
2018-07-06 08:07:38 +02:00
$this -> db -> rollback ();
2019-11-08 10:53:31 +01:00
$this -> error = $this -> db -> lasterror ();
2018-07-06 08:07:38 +02:00
return - 1 ;
}
2020-05-21 15:05:19 +02:00
} else {
2018-07-06 08:07:38 +02:00
$this -> db -> rollback ();
2019-11-08 10:53:31 +01:00
$this -> error = $line -> error ;
2018-07-06 08:07:38 +02:00
return - 1 ;
}
}
2020-09-08 21:27:28 +02:00
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2018-07-06 08:07:38 +02:00
/**
* Set percent discount
*
2021-02-09 13:25:55 +01:00
* @ deprecated
* @ see setDiscount ()
2018-07-06 08:07:38 +02:00
* @ param User $user User that set discount
* @ param double $remise Discount
* @ param int $notrigger 1 = Does not execute triggers , 0 = execute triggers
* @ return int < 0 if ko , > 0 if ok
*/
2020-09-08 21:27:28 +02:00
public function set_remise ( $user , $remise , $notrigger = 0 )
2018-07-06 08:07:38 +02:00
{
2020-09-08 21:27:28 +02:00
// phpcs:enable
2021-02-09 13:25:55 +01:00
dol_syslog ( get_class ( $this ) . " ::set_remise is deprecated, use setDiscount instead " , LOG_NOTICE );
return $this -> setDiscount ( $user , $remise , $notrigger );
}
/**
* Set percent discount
*
* @ param User $user User that set discount
* @ param double $remise Discount
* @ param int $notrigger 1 = Does not execute triggers , 0 = execute triggers
* @ return int < 0 if ko , > 0 if ok
*/
public function setDiscount ( $user , $remise , $notrigger = 0 )
{
2018-07-06 08:07:38 +02:00
// Clean parameters
2021-02-23 21:09:01 +01:00
if ( empty ( $remise )) {
$remise = 0 ;
}
2018-07-06 08:07:38 +02:00
2021-02-23 21:09:01 +01:00
if ( $user -> rights -> facture -> creer ) {
2021-03-29 22:51:36 +02:00
$remise = price2num ( $remise , 2 );
2018-07-06 08:07:38 +02:00
2019-11-08 10:53:31 +01:00
$error = 0 ;
2018-07-06 08:07:38 +02:00
$this -> db -> begin ();
$sql = 'UPDATE ' . MAIN_DB_PREFIX . 'facture' ;
2021-03-29 22:51:36 +02:00
$sql .= ' SET remise_percent = ' . (( float ) $remise );
2021-08-27 23:36:06 +02:00
$sql .= " WHERE rowid = " . (( int ) $this -> id );
2019-11-08 10:53:31 +01:00
$sql .= ' AND fk_statut = ' . self :: STATUS_DRAFT ;
2018-07-06 08:07:38 +02:00
dol_syslog ( __METHOD__ , LOG_DEBUG );
2019-11-08 10:53:31 +01:00
$resql = $this -> db -> query ( $sql );
2021-02-23 21:09:01 +01:00
if ( ! $resql ) {
2019-11-08 10:53:31 +01:00
$this -> errors [] = $this -> db -> error ();
2018-07-06 08:07:38 +02:00
$error ++ ;
}
2021-02-23 21:09:01 +01:00
if ( ! $notrigger && empty ( $error )) {
2018-07-06 08:07:38 +02:00
// Call trigger
2019-11-08 10:53:31 +01:00
$result = $this -> call_trigger ( 'BILL_MODIFY' , $user );
2021-02-23 21:09:01 +01:00
if ( $result < 0 ) {
$error ++ ;
}
2018-07-06 08:07:38 +02:00
// End call triggers
}
2021-02-23 21:09:01 +01:00
if ( ! $error ) {
2018-07-06 08:07:38 +02:00
$this -> remise_percent = $remise ;
$this -> update_price ( 1 );
$this -> db -> commit ();
return 1 ;
2020-05-21 15:05:19 +02:00
} else {
2021-02-23 21:09:01 +01:00
foreach ( $this -> errors as $errmsg ) {
2018-07-06 08:07:38 +02:00
dol_syslog ( __METHOD__ . ' Error: ' . $errmsg , LOG_ERR );
2019-11-08 10:53:31 +01:00
$this -> error .= ( $this -> error ? ', ' . $errmsg : $errmsg );
2018-07-06 08:07:38 +02:00
}
$this -> db -> rollback ();
2019-11-08 10:53:31 +01:00
return - 1 * $error ;
2018-07-06 08:07:38 +02:00
}
}
}
2020-09-08 21:27:28 +02:00
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2018-07-06 08:07:38 +02:00
/**
* Set absolute discount
*
* @ param User $user User that set discount
* @ param double $remise Discount
* @ param int $notrigger 1 = Does not execute triggers , 0 = execute triggers
* @ return int < 0 if KO , > 0 if OK
*/
2020-09-08 21:27:28 +02:00
public function set_remise_absolue ( $user , $remise , $notrigger = 0 )
2018-07-06 08:07:38 +02:00
{
2020-09-08 21:27:28 +02:00
// phpcs:enable
2021-02-23 21:09:01 +01:00
if ( empty ( $remise )) {
$remise = 0 ;
}
2018-07-06 08:07:38 +02:00
2021-02-23 21:09:01 +01:00
if ( $user -> rights -> facture -> creer ) {
2019-11-08 10:53:31 +01:00
$error = 0 ;
2018-07-06 08:07:38 +02:00
$this -> db -> begin ();
2019-11-08 10:53:31 +01:00
$remise = price2num ( $remise );
2018-07-06 08:07:38 +02:00
$sql = 'UPDATE ' . MAIN_DB_PREFIX . 'facture' ;
2021-03-30 03:37:54 +02:00
$sql .= ' SET remise_absolue = ' . (( float ) $remise );
2021-08-27 23:36:06 +02:00
$sql .= " WHERE rowid = " . (( int ) $this -> id );
2019-11-08 10:53:31 +01:00
$sql .= ' AND fk_statut = ' . self :: STATUS_DRAFT ;
2018-07-06 08:07:38 +02:00
dol_syslog ( __METHOD__ , LOG_DEBUG );
2019-11-08 10:53:31 +01:00
$resql = $this -> db -> query ( $sql );
2021-02-23 21:09:01 +01:00
if ( ! $resql ) {
2019-11-08 10:53:31 +01:00
$this -> errors [] = $this -> db -> error ();
2018-07-06 08:07:38 +02:00
$error ++ ;
}
2021-02-23 21:09:01 +01:00
if ( ! $error ) {
2019-11-08 10:53:31 +01:00
$this -> oldcopy = clone $this ;
2018-07-06 08:07:38 +02:00
$this -> remise_absolue = $remise ;
$this -> update_price ( 1 );
}
2021-02-23 21:09:01 +01:00
if ( ! $notrigger && empty ( $error )) {
2018-07-06 08:07:38 +02:00
// Call trigger
2019-11-08 10:53:31 +01:00
$result = $this -> call_trigger ( 'BILL_MODIFY' , $user );
2021-02-23 21:09:01 +01:00
if ( $result < 0 ) {
$error ++ ;
}
2018-07-06 08:07:38 +02:00
// End call triggers
}
2021-02-23 21:09:01 +01:00
if ( ! $error ) {
2018-07-06 08:07:38 +02:00
$this -> db -> commit ();
return 1 ;
2020-05-21 15:05:19 +02:00
} else {
2021-02-23 21:09:01 +01:00
foreach ( $this -> errors as $errmsg ) {
2018-07-06 08:07:38 +02:00
dol_syslog ( __METHOD__ . ' Error: ' . $errmsg , LOG_ERR );
2019-11-08 10:53:31 +01:00
$this -> error .= ( $this -> error ? ', ' . $errmsg : $errmsg );
2018-07-06 08:07:38 +02:00
}
$this -> db -> rollback ();
2019-11-08 10:53:31 +01:00
return - 1 * $error ;
2018-07-06 08:07:38 +02:00
}
}
}
/**
* Return next reference of customer invoice not already used ( or last reference )
* according to numbering module defined into constant FACTURE_ADDON
*
* @ param Societe $soc object company
* @ param string $mode 'next' for next value or 'last' for last value
* @ return string free ref or last ref
*/
2020-09-08 21:27:28 +02:00
public function getNextNumRef ( $soc , $mode = 'next' )
2018-07-06 08:07:38 +02:00
{
global $conf , $langs ;
2020-03-12 17:43:59 +01:00
if ( $this -> module_source == 'takepos' ) {
2021-08-17 04:57:53 +02:00
$langs -> load ( 'cashdesk' );
2018-07-06 08:07:38 +02:00
2020-03-12 17:43:59 +01:00
$moduleName = 'takepos' ;
$moduleSourceName = 'Takepos' ;
$addonConstName = 'TAKEPOS_REF_ADDON' ;
// Clean parameters (if not defined or using deprecated value)
2021-02-23 21:09:01 +01:00
if ( empty ( $conf -> global -> TAKEPOS_REF_ADDON )) {
$conf -> global -> TAKEPOS_REF_ADDON = 'mod_takepos_ref_simple' ;
}
2020-03-12 17:43:59 +01:00
$addon = $conf -> global -> TAKEPOS_REF_ADDON ;
} else {
$langs -> load ( 'bills' );
$moduleName = 'facture' ;
$moduleSourceName = 'Invoice' ;
$addonConstName = 'FACTURE_ADDON' ;
2018-07-06 08:07:38 +02:00
2020-03-31 16:36:42 +02:00
// Clean parameters (if not defined or using deprecated value)
2021-02-23 21:09:01 +01:00
if ( empty ( $conf -> global -> FACTURE_ADDON )) {
$conf -> global -> FACTURE_ADDON = 'mod_facture_terre' ;
} elseif ( $conf -> global -> FACTURE_ADDON == 'terre' ) {
$conf -> global -> FACTURE_ADDON = 'mod_facture_terre' ;
} elseif ( $conf -> global -> FACTURE_ADDON == 'mercure' ) {
$conf -> global -> FACTURE_ADDON = 'mod_facture_mercure' ;
}
2018-07-06 08:07:38 +02:00
2020-03-12 17:43:59 +01:00
$addon = $conf -> global -> FACTURE_ADDON ;
}
if ( ! empty ( $addon )) {
2022-04-08 10:19:20 +02:00
dol_syslog ( " Call getNextNumRef with " . $addonConstName . " = " . $conf -> global -> FACTURE_ADDON . " , thirdparty= " . $soc -> name . " , type= " . $soc -> typent_code . " , mode= " . $mode , LOG_DEBUG );
2018-07-06 08:07:38 +02:00
2019-11-08 10:53:31 +01:00
$mybool = false ;
2018-07-06 08:07:38 +02:00
2020-04-23 18:55:10 +02:00
$file = $addon . '.php' ;
2020-03-12 17:43:59 +01:00
$classname = $addon ;
2019-02-23 16:03:40 +01:00
2018-07-06 08:07:38 +02:00
// Include file with class
$dirmodels = array_merge ( array ( '/' ), ( array ) $conf -> modules_parts [ 'models' ]);
foreach ( $dirmodels as $reldir ) {
2020-04-23 18:55:10 +02:00
$dir = dol_buildpath ( $reldir . 'core/modules/' . $moduleName . '/' );
2018-07-06 08:07:38 +02:00
// Load file with numbering class (if found)
2020-04-23 18:55:10 +02:00
if ( is_file ( $dir . $file ) && is_readable ( $dir . $file )) {
$mybool |= include_once $dir . $file ;
2020-03-12 17:43:59 +01:00
}
2018-07-06 08:07:38 +02:00
}
// For compatibility
2020-03-12 17:43:59 +01:00
if ( ! $mybool ) {
2020-04-23 18:55:10 +02:00
$file = $addon . '/' . $addon . '.modules.php' ;
$classname = 'mod_' . $moduleName . '_' . $addon ;
2019-01-27 11:55:16 +01:00
$classname = preg_replace ( '/\-.*$/' , '' , $classname );
2018-07-06 08:07:38 +02:00
// Include file with class
2020-03-12 17:43:59 +01:00
foreach ( $conf -> file -> dol_document_root as $dirroot ) {
2020-04-23 18:55:10 +02:00
$dir = $dirroot . '/core/modules/' . $moduleName . '/' ;
2018-07-06 08:07:38 +02:00
// Load file with numbering class (if found)
2020-04-23 18:55:10 +02:00
if ( is_file ( $dir . $file ) && is_readable ( $dir . $file )) {
$mybool |= include_once $dir . $file ;
2020-03-12 17:43:59 +01:00
}
2018-07-06 08:07:38 +02:00
}
}
2019-02-23 16:03:40 +01:00
2020-03-12 17:43:59 +01:00
if ( ! $mybool ) {
2020-04-23 18:55:10 +02:00
dol_print_error ( '' , 'Failed to include file ' . $file );
2018-07-06 08:07:38 +02:00
return '' ;
}
$obj = new $classname ();
2022-07-07 22:35:56 +02:00
2019-01-27 11:55:16 +01:00
$numref = $obj -> getNextValue ( $soc , $this , $mode );
2018-07-06 08:07:38 +02:00
2022-07-07 22:35:56 +02:00
2018-07-06 08:07:38 +02:00
/**
* $numref can be empty in case we ask for the last value because if there is no invoice created with the
* set up mask .
*/
if ( $mode != 'last' && ! $numref ) {
2019-11-08 10:53:31 +01:00
$this -> error = $obj -> error ;
2020-03-12 17:43:59 +01:00
return '' ;
2018-07-06 08:07:38 +02:00
}
return $numref ;
2020-03-12 17:43:59 +01:00
} else {
$langs -> load ( 'errors' );
2020-04-23 18:55:10 +02:00
print $langs -> trans ( 'Error' ) . ' ' . $langs -> trans ( 'ErrorModuleSetupNotComplete' , $langs -> transnoentitiesnoconv ( $moduleSourceName ));
2020-03-12 17:43:59 +01:00
return '' ;
2018-07-06 08:07:38 +02:00
}
}
/**
* Load miscellaneous information for tab " Info "
*
* @ param int $id Id of object to load
* @ return void
*/
2020-09-08 21:27:28 +02:00
public function info ( $id )
2018-07-06 08:07:38 +02:00
{
$sql = 'SELECT c.rowid, datec, date_valid as datev, tms as datem,' ;
2019-11-08 10:53:31 +01:00
$sql .= ' date_closing as dateclosing,' ;
$sql .= ' fk_user_author, fk_user_valid, fk_user_closing' ;
$sql .= ' FROM ' . MAIN_DB_PREFIX . 'facture as c' ;
2021-03-14 11:48:39 +01:00
$sql .= ' WHERE c.rowid = ' . (( int ) $id );
2018-07-06 08:07:38 +02:00
2019-11-08 10:53:31 +01:00
$result = $this -> db -> query ( $sql );
2021-02-23 21:09:01 +01:00
if ( $result ) {
if ( $this -> db -> num_rows ( $result )) {
2018-07-06 08:07:38 +02:00
$obj = $this -> db -> fetch_object ( $result );
$this -> id = $obj -> rowid ;
2021-02-23 21:09:01 +01:00
if ( $obj -> fk_user_author ) {
2018-07-06 08:07:38 +02:00
$cuser = new User ( $this -> db );
$cuser -> fetch ( $obj -> fk_user_author );
2019-11-08 10:53:31 +01:00
$this -> user_creation = $cuser ;
2018-07-06 08:07:38 +02:00
}
2021-02-23 21:09:01 +01:00
if ( $obj -> fk_user_valid ) {
2018-07-06 08:07:38 +02:00
$vuser = new User ( $this -> db );
$vuser -> fetch ( $obj -> fk_user_valid );
$this -> user_validation = $vuser ;
}
2021-02-23 21:09:01 +01:00
if ( $obj -> fk_user_closing ) {
2019-09-06 11:40:26 +02:00
$cluser = new User ( $this -> db );
2019-09-29 15:45:41 +02:00
$cluser -> fetch ( $obj -> fk_user_closing );
2019-11-08 10:53:31 +01:00
$this -> user_closing = $cluser ;
2019-09-06 11:40:26 +02:00
}
2019-10-14 16:00:03 +02:00
2018-07-06 08:07:38 +02:00
$this -> date_creation = $this -> db -> jdate ( $obj -> datec );
$this -> date_modification = $this -> db -> jdate ( $obj -> datem );
2019-09-06 11:40:26 +02:00
$this -> date_validation = $this -> db -> jdate ( $obj -> datev );
2019-09-29 15:45:41 +02:00
$this -> date_closing = $this -> db -> jdate ( $obj -> dateclosing );
2018-07-06 08:07:38 +02:00
}
$this -> db -> free ( $result );
2020-05-21 15:05:19 +02:00
} else {
2018-07-06 08:07:38 +02:00
dol_print_error ( $this -> db );
}
}
2020-09-08 21:27:28 +02:00
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2018-07-06 08:07:38 +02:00
/**
* Return list of invoices ( eventually filtered on a user ) into an array
*
* @ param int $shortlist 0 = Return array [ id ] = ref , 1 = Return array []( id => id , ref => ref , name => name )
* @ param int $draft 0 = not draft , 1 = draft
* @ param User $excluser Objet user to exclude
* @ param int $socid Id third pary
* @ param int $limit For pagination
* @ param int $offset For pagination
* @ param string $sortfield Sort criteria
* @ param string $sortorder Sort order
2019-10-09 18:47:25 +02:00
* @ return array | int - 1 if KO , array with result if OK
2018-07-06 08:07:38 +02:00
*/
2020-09-08 21:27:28 +02:00
public function liste_array ( $shortlist = 0 , $draft = 0 , $excluser = '' , $socid = 0 , $limit = 0 , $offset = 0 , $sortfield = 'f.datef,f.rowid' , $sortorder = 'DESC' )
2018-07-06 08:07:38 +02:00
{
2020-09-08 21:27:28 +02:00
// phpcs:enable
2019-11-08 10:53:31 +01:00
global $conf , $user ;
2018-07-06 08:07:38 +02:00
$ga = array ();
$sql = " SELECT s.rowid, s.nom as name, s.client, " ;
2019-11-08 10:53:31 +01:00
$sql .= " f.rowid as fid, f.ref as ref, f.datef as df " ;
2021-10-22 22:15:59 +02:00
if ( empty ( $user -> rights -> societe -> client -> voir ) && ! $socid ) {
2021-02-23 21:09:01 +01:00
$sql .= " , sc.fk_soc, sc.fk_user " ;
}
2019-11-08 10:53:31 +01:00
$sql .= " FROM " . MAIN_DB_PREFIX . " societe as s, " . MAIN_DB_PREFIX . " facture as f " ;
2021-10-22 22:15:59 +02:00
if ( empty ( $user -> rights -> societe -> client -> voir ) && ! $socid ) {
2021-02-23 21:09:01 +01:00
$sql .= " , " . MAIN_DB_PREFIX . " societe_commerciaux as sc " ;
}
2019-11-08 10:53:31 +01:00
$sql .= " WHERE f.entity IN ( " . getEntity ( 'invoice' ) . " ) " ;
$sql .= " AND f.fk_soc = s.rowid " ;
2021-10-22 22:15:59 +02:00
if ( empty ( $user -> rights -> societe -> client -> voir ) && ! $socid ) { //restriction
2021-08-23 17:41:11 +02:00
$sql .= " AND s.rowid = sc.fk_soc AND sc.fk_user = " . (( int ) $user -> id );
2018-07-06 08:07:38 +02:00
}
2021-02-23 21:09:01 +01:00
if ( $socid ) {
2021-03-22 13:31:06 +01:00
$sql .= " AND s.rowid = " . (( int ) $socid );
2021-02-23 21:09:01 +01:00
}
if ( $draft ) {
$sql .= " AND f.fk_statut = " . self :: STATUS_DRAFT ;
}
if ( is_object ( $excluser )) {
2021-08-23 19:33:24 +02:00
$sql .= " AND f.fk_user_author <> " . (( int ) $excluser -> id );
2021-02-23 21:09:01 +01:00
}
2019-11-08 10:53:31 +01:00
$sql .= $this -> db -> order ( $sortfield , $sortorder );
$sql .= $this -> db -> plimit ( $limit , $offset );
2018-07-06 08:07:38 +02:00
2019-11-08 10:53:31 +01:00
$result = $this -> db -> query ( $sql );
2021-02-23 21:09:01 +01:00
if ( $result ) {
2018-07-06 08:07:38 +02:00
$numc = $this -> db -> num_rows ( $result );
2021-02-23 21:09:01 +01:00
if ( $numc ) {
2018-07-06 08:07:38 +02:00
$i = 0 ;
2021-02-23 21:09:01 +01:00
while ( $i < $numc ) {
2018-07-06 08:07:38 +02:00
$obj = $this -> db -> fetch_object ( $result );
2021-02-23 21:09:01 +01:00
if ( $shortlist == 1 ) {
2018-07-06 08:07:38 +02:00
$ga [ $obj -> fid ] = $obj -> ref ;
2021-02-23 21:09:01 +01:00
} elseif ( $shortlist == 2 ) {
2018-07-06 08:07:38 +02:00
$ga [ $obj -> fid ] = $obj -> ref . ' (' . $obj -> name . ')' ;
2020-05-21 15:05:19 +02:00
} else {
2019-11-08 10:53:31 +01:00
$ga [ $i ][ 'id' ] = $obj -> fid ;
2018-07-06 08:07:38 +02:00
$ga [ $i ][ 'ref' ] = $obj -> ref ;
$ga [ $i ][ 'name' ] = $obj -> name ;
}
$i ++ ;
}
}
return $ga ;
2020-05-21 15:05:19 +02:00
} else {
2018-07-06 08:07:38 +02:00
dol_print_error ( $this -> db );
return - 1 ;
}
}
2020-09-08 21:27:28 +02:00
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2018-07-06 08:07:38 +02:00
/**
* Return list of invoices qualified to be replaced by another invoice .
* Invoices matching the following rules are returned :
* ( Status validated or abandonned for a reason 'other' ) + not payed + no payment at all + not already replaced
*
2021-06-30 12:43:44 +02:00
* @ param int $socid Id thirdparty
* @ return array | int Array of invoices ( 'id' => id , 'ref' => ref , 'status' => status , 'paymentornot' => 0 / 1 )
2018-07-06 08:07:38 +02:00
*/
2020-09-08 21:27:28 +02:00
public function list_replacable_invoices ( $socid = 0 )
2018-07-06 08:07:38 +02:00
{
2020-09-08 21:27:28 +02:00
// phpcs:enable
2018-07-06 08:07:38 +02:00
global $conf ;
$return = array ();
2021-06-30 12:43:44 +02:00
$sql = " SELECT f.rowid as rowid, f.ref, f.fk_statut as status, f.paye as paid, " ;
2019-11-08 10:53:31 +01:00
$sql .= " ff.rowid as rowidnext " ;
2021-06-30 12:43:44 +02:00
//$sql .= ", SUM(pf.amount) as alreadypaid";
2019-11-08 10:53:31 +01:00
$sql .= " FROM " . MAIN_DB_PREFIX . " facture as f " ;
$sql .= " LEFT JOIN " . MAIN_DB_PREFIX . " paiement_facture as pf ON f.rowid = pf.fk_facture " ;
$sql .= " LEFT JOIN " . MAIN_DB_PREFIX . " facture as ff ON f.rowid = ff.fk_facture_source " ;
$sql .= " WHERE (f.fk_statut = " . self :: STATUS_VALIDATED . " OR (f.fk_statut = " . self :: STATUS_ABANDONED . " AND f.close_code = ' " . self :: CLOSECODE_ABANDONED . " ')) " ;
$sql .= " AND f.entity IN ( " . getEntity ( 'invoice' ) . " ) " ;
2021-06-30 12:43:44 +02:00
$sql .= " AND f.paye = 0 " ; // Not paid completely
$sql .= " AND pf.fk_paiement IS NULL " ; // No payment already done
$sql .= " AND ff.fk_statut IS NULL " ; // Return true if it is not a replacement invoice
2021-02-23 21:09:01 +01:00
if ( $socid > 0 ) {
2021-06-09 15:36:47 +02:00
$sql .= " AND f.fk_soc = " . (( int ) $socid );
2021-02-23 21:09:01 +01:00
}
2021-06-30 12:43:44 +02:00
//$sql .= " GROUP BY f.rowid, f.ref, f.fk_statut, f.paye, ff.rowid";
2019-11-08 10:53:31 +01:00
$sql .= " ORDER BY f.ref " ;
2018-07-06 08:07:38 +02:00
dol_syslog ( get_class ( $this ) . " ::list_replacable_invoices " , LOG_DEBUG );
2019-11-08 10:53:31 +01:00
$resql = $this -> db -> query ( $sql );
2021-02-23 21:09:01 +01:00
if ( $resql ) {
while ( $obj = $this -> db -> fetch_object ( $resql )) {
2021-06-30 12:43:44 +02:00
$return [ $obj -> rowid ] = array (
'id' => $obj -> rowid ,
'ref' => $obj -> ref ,
'status' => $obj -> status ,
'paid' => $obj -> paid ,
'alreadypaid' => 0
);
2018-07-06 08:07:38 +02:00
}
//print_r($return);
return $return ;
2020-05-21 15:05:19 +02:00
} else {
2019-11-08 10:53:31 +01:00
$this -> error = $this -> db -> error ();
2018-07-06 08:07:38 +02:00
return - 1 ;
}
}
2020-09-08 21:27:28 +02:00
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2018-07-06 08:07:38 +02:00
/**
* Return list of invoices qualified to be corrected by a credit note .
* Invoices matching the following rules are returned :
* ( validated + payment on process ) or classified ( payed completely or payed partiely ) + not already replaced + not already a credit note
*
* @ param int $socid Id thirdparty
* @ return array Array of invoices ( $id => array ( 'ref' => , 'paymentornot' => , 'status' => , 'paye' => )
*/
2020-09-08 21:27:28 +02:00
public function list_qualified_avoir_invoices ( $socid = 0 )
2018-07-06 08:07:38 +02:00
{
2020-09-08 21:27:28 +02:00
// phpcs:enable
2018-07-06 08:07:38 +02:00
global $conf ;
$return = array ();
2018-12-02 14:31:45 +01:00
$sql = " SELECT f.rowid as rowid, f.ref, f.fk_statut, f.type, f.paye, pf.fk_paiement " ;
2019-11-08 10:53:31 +01:00
$sql .= " FROM " . MAIN_DB_PREFIX . " facture as f " ;
$sql .= " LEFT JOIN " . MAIN_DB_PREFIX . " paiement_facture as pf ON f.rowid = pf.fk_facture " ;
$sql .= " LEFT JOIN " . MAIN_DB_PREFIX . " facture as ff ON (f.rowid = ff.fk_facture_source AND ff.type= " . self :: TYPE_REPLACEMENT . " ) " ;
$sql .= " WHERE f.entity IN ( " . getEntity ( 'invoice' ) . " ) " ;
$sql .= " AND f.fk_statut in ( " . self :: STATUS_VALIDATED . " , " . self :: STATUS_CLOSED . " ) " ;
2018-07-06 08:07:38 +02:00
// $sql.= " WHERE f.fk_statut >= 1";
// $sql.= " AND (f.paye = 1"; // Classee payee completement
// $sql.= " OR f.close_code IS NOT NULL)"; // Classee payee partiellement
2019-11-08 10:53:31 +01:00
$sql .= " AND ff.type IS NULL " ; // Renvoi vrai si pas facture de remplacement
2021-06-10 16:29:30 +02:00
$sql .= " AND f.type <> " . self :: TYPE_CREDIT_NOTE ; // Exclude credit note invoices from selection
2018-07-06 08:07:38 +02:00
2019-11-08 10:53:31 +01:00
if ( ! empty ( $conf -> global -> INVOICE_USE_SITUATION_CREDIT_NOTE )) {
2021-06-10 16:29:30 +02:00
// Keep invoices that are not situation invoices or that are the last in serie if it is a situation invoice
$sql .= " AND (f.type <> " . self :: TYPE_SITUATION . " OR f.rowid IN " ;
2021-06-14 15:37:02 +02:00
$sql .= '(SELECT MAX(fs.rowid)' ; // This select returns several ID becasue of the group by later
2021-06-10 16:29:30 +02:00
$sql .= " FROM " . MAIN_DB_PREFIX . " facture as fs " ;
$sql .= " WHERE fs.entity IN ( " . getEntity ( 'invoice' ) . " ) " ;
$sql .= " AND fs.type = " . self :: TYPE_SITUATION ;
$sql .= " AND fs.fk_statut IN ( " . self :: STATUS_VALIDATED . " , " . self :: STATUS_CLOSED . " ) " ;
if ( $socid > 0 ) {
2021-06-10 16:31:28 +02:00
$sql .= " AND fs.fk_soc = " . (( int ) $socid );
2021-06-10 16:29:30 +02:00
}
2021-06-14 15:37:02 +02:00
$sql .= " GROUP BY fs.situation_cycle_ref) " ; // For each situation_cycle_ref, we take the higher rowid
2021-06-10 16:29:30 +02:00
$sql .= " ) " ;
2020-05-21 15:05:19 +02:00
} else {
2021-06-10 16:29:30 +02:00
$sql .= " AND f.type <> " . self :: TYPE_SITUATION ; // Keep invoices that are not situation invoices
2018-07-06 08:07:38 +02:00
}
2021-02-23 21:09:01 +01:00
if ( $socid > 0 ) {
2021-03-22 11:30:18 +01:00
$sql .= " AND f.fk_soc = " . (( int ) $socid );
2021-02-23 21:09:01 +01:00
}
2019-11-08 10:53:31 +01:00
$sql .= " ORDER BY f.ref " ;
2018-07-06 08:07:38 +02:00
dol_syslog ( get_class ( $this ) . " ::list_qualified_avoir_invoices " , LOG_DEBUG );
2019-11-08 10:53:31 +01:00
$resql = $this -> db -> query ( $sql );
2021-02-23 21:09:01 +01:00
if ( $resql ) {
while ( $obj = $this -> db -> fetch_object ( $resql )) {
2019-11-08 10:53:31 +01:00
$qualified = 0 ;
2021-02-23 21:09:01 +01:00
if ( $obj -> fk_statut == self :: STATUS_VALIDATED ) {
$qualified = 1 ;
}
if ( $obj -> fk_statut == self :: STATUS_CLOSED ) {
$qualified = 1 ;
}
if ( $qualified ) {
2018-12-02 14:31:45 +01:00
//$ref=$obj->ref;
2019-11-08 10:53:31 +01:00
$paymentornot = ( $obj -> fk_paiement ? 1 : 0 );
$return [ $obj -> rowid ] = array ( 'ref' => $obj -> ref , 'status' => $obj -> fk_statut , 'type' => $obj -> type , 'paye' => $obj -> paye , 'paymentornot' => $paymentornot );
2018-07-06 08:07:38 +02:00
}
}
return $return ;
2020-05-21 15:05:19 +02:00
} else {
2019-11-08 10:53:31 +01:00
$this -> error = $this -> db -> error ();
2018-07-06 08:07:38 +02:00
return - 1 ;
}
}
2020-09-08 21:27:28 +02:00
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2018-07-06 08:07:38 +02:00
/**
* Load indicators for dashboard ( this -> nbtodo and this -> nbtodolate )
*
* @ param User $user Object user
* @ return WorkboardResponse | int < 0 if KO , WorkboardResponse if OK
*/
2020-09-08 21:27:28 +02:00
public function load_board ( $user )
2018-07-06 08:07:38 +02:00
{
2020-09-08 21:27:28 +02:00
// phpcs:enable
2018-07-06 08:07:38 +02:00
global $conf , $langs ;
$clause = " WHERE " ;
2022-01-09 19:48:38 +01:00
$sql = " SELECT f.rowid, f.date_lim_reglement as datefin, f.fk_statut, f.total_ht " ;
2019-11-08 10:53:31 +01:00
$sql .= " FROM " . MAIN_DB_PREFIX . " facture as f " ;
2021-10-22 22:15:59 +02:00
if ( empty ( $user -> rights -> societe -> client -> voir ) && ! $user -> socid ) {
2022-01-09 19:48:38 +01:00
$sql .= " JOIN " . MAIN_DB_PREFIX . " societe_commerciaux as sc ON f.fk_soc = sc.fk_soc " ;
2021-08-23 17:41:11 +02:00
$sql .= " WHERE sc.fk_user = " . (( int ) $user -> id );
2018-07-06 08:07:38 +02:00
$clause = " AND " ;
}
2019-11-08 10:53:31 +01:00
$sql .= $clause . " f.paye=0 " ;
$sql .= " AND f.entity IN ( " . getEntity ( 'invoice' ) . " ) " ;
$sql .= " AND f.fk_statut = " . self :: STATUS_VALIDATED ;
2021-02-23 21:09:01 +01:00
if ( $user -> socid ) {
2021-08-23 17:41:11 +02:00
$sql .= " AND f.fk_soc = " . (( int ) $user -> socid );
2021-02-23 21:09:01 +01:00
}
2018-07-06 08:07:38 +02:00
2019-11-08 10:53:31 +01:00
$resql = $this -> db -> query ( $sql );
2021-02-23 21:09:01 +01:00
if ( $resql ) {
2018-07-06 08:07:38 +02:00
$langs -> load ( " bills " );
2019-11-08 10:53:31 +01:00
$now = dol_now ();
2018-07-06 08:07:38 +02:00
$response = new WorkboardResponse ();
2019-11-08 10:53:31 +01:00
$response -> warning_delay = $conf -> facture -> client -> warning_delay / 60 / 60 / 24 ;
$response -> label = $langs -> trans ( " CustomerBillsUnpaid " );
$response -> labelShort = $langs -> trans ( " Unpaid " );
$response -> url = DOL_URL_ROOT . '/compta/facture/list.php?search_status=1&mainmenu=billing&leftmenu=customers_bills' ;
$response -> img = img_object ( '' , " bill " );
2018-07-06 08:07:38 +02:00
$generic_facture = new Facture ( $this -> db );
2021-02-23 21:09:01 +01:00
while ( $obj = $this -> db -> fetch_object ( $resql )) {
2018-07-06 08:07:38 +02:00
$generic_facture -> date_lim_reglement = $this -> db -> jdate ( $obj -> datefin );
$generic_facture -> statut = $obj -> fk_statut ;
$response -> nbtodo ++ ;
2021-06-13 15:59:22 +02:00
$response -> total += $obj -> total_ht ;
2018-07-06 08:07:38 +02:00
if ( $generic_facture -> hasDelay ()) {
$response -> nbtodolate ++ ;
2020-02-13 12:36:05 +01:00
$response -> url_late = DOL_URL_ROOT . '/compta/facture/list.php?search_option=late&mainmenu=billing&leftmenu=customers_bills' ;
2018-07-06 08:07:38 +02:00
}
}
2022-01-09 19:48:38 +01:00
$this -> db -> free ( $resql );
2018-07-06 08:07:38 +02:00
return $response ;
2020-05-21 15:05:19 +02:00
} else {
2018-07-06 08:07:38 +02:00
dol_print_error ( $this -> db );
2019-11-08 10:53:31 +01:00
$this -> error = $this -> db -> error ();
2018-07-06 08:07:38 +02:00
return - 1 ;
}
}
/* gestion des contacts d'une facture */
/**
* Retourne id des contacts clients de facturation
*
* @ return array Liste des id contacts facturation
*/
2020-09-08 21:27:28 +02:00
public function getIdBillingContact ()
2018-07-06 08:07:38 +02:00
{
2019-01-27 11:55:16 +01:00
return $this -> getIdContact ( 'external' , 'BILLING' );
2018-07-06 08:07:38 +02:00
}
/**
* Retourne id des contacts clients de livraison
*
* @ return array Liste des id contacts livraison
*/
2020-09-08 21:27:28 +02:00
public function getIdShippingContact ()
2018-07-06 08:07:38 +02:00
{
2019-01-27 11:55:16 +01:00
return $this -> getIdContact ( 'external' , 'SHIPPING' );
2018-07-06 08:07:38 +02:00
}
/**
* Initialise an instance with random values .
* Used to build previews or test instances .
* id must be 0 if object instance is a specimen .
*
* @ param string $option '' = Create a specimen invoice with lines , 'nolines' = No lines
* @ return void
*/
2020-09-08 21:27:28 +02:00
public function initAsSpecimen ( $option = '' )
2018-07-06 08:07:38 +02:00
{
2020-12-13 13:34:21 +01:00
global $conf , $langs , $user ;
2018-07-06 08:07:38 +02:00
2019-11-08 10:53:31 +01:00
$now = dol_now ();
$arraynow = dol_getdate ( $now );
$nownotime = dol_mktime ( 0 , 0 , 0 , $arraynow [ 'mon' ], $arraynow [ 'mday' ], $arraynow [ 'year' ]);
2018-07-05 11:52:41 +02:00
2020-09-08 21:27:28 +02:00
// Load array of products prodids
2018-07-06 08:07:38 +02:00
$num_prods = 0 ;
$prodids = array ();
$sql = " SELECT rowid " ;
2019-11-08 10:53:31 +01:00
$sql .= " FROM " . MAIN_DB_PREFIX . " product " ;
$sql .= " WHERE entity IN ( " . getEntity ( 'product' ) . " ) " ;
2020-08-19 01:43:48 +02:00
$sql .= $this -> db -> plimit ( 100 );
2018-07-06 08:07:38 +02:00
$resql = $this -> db -> query ( $sql );
2021-02-23 21:09:01 +01:00
if ( $resql ) {
2018-07-06 08:07:38 +02:00
$num_prods = $this -> db -> num_rows ( $resql );
$i = 0 ;
2021-02-23 21:09:01 +01:00
while ( $i < $num_prods ) {
2018-07-06 08:07:38 +02:00
$i ++ ;
$row = $this -> db -> fetch_row ( $resql );
$prodids [ $i ] = $row [ 0 ];
}
}
//Avoid php warning Warning: mt_rand(): max(0) is smaller than min(1) when no product exists
if ( empty ( $num_prods )) {
2019-11-08 10:53:31 +01:00
$num_prods = 1 ;
2018-07-06 08:07:38 +02:00
}
// Initialize parameters
2019-11-08 10:53:31 +01:00
$this -> id = 0 ;
2018-07-06 08:07:38 +02:00
$this -> entity = 1 ;
$this -> ref = 'SPECIMEN' ;
2019-11-08 10:53:31 +01:00
$this -> specimen = 1 ;
2018-07-06 08:07:38 +02:00
$this -> socid = 1 ;
$this -> date = $nownotime ;
2019-11-08 10:53:31 +01:00
$this -> date_lim_reglement = $nownotime + 3600 * 24 * 30 ;
2018-07-06 08:07:38 +02:00
$this -> cond_reglement_id = 1 ;
$this -> cond_reglement_code = 'RECEP' ;
2019-11-08 10:53:31 +01:00
$this -> date_lim_reglement = $this -> calculate_date_lim_reglement ();
$this -> mode_reglement_id = 0 ; // Not forced to show payment mode CHQ + VIR
$this -> mode_reglement_code = '' ; // Not forced to show payment mode CHQ + VIR
2020-01-21 00:16:11 +01:00
2019-11-08 10:53:31 +01:00
$this -> note_public = 'This is a comment (public)' ;
$this -> note_private = 'This is a comment (private)' ;
$this -> note = 'This is a comment (private)' ;
2020-01-21 00:16:11 +01:00
2020-12-13 13:34:21 +01:00
$this -> fk_user_author = $user -> id ;
2020-01-21 00:16:11 +01:00
$this -> multicurrency_tx = 1 ;
$this -> multicurrency_code = $conf -> currency ;
2019-11-08 10:53:31 +01:00
$this -> fk_incoterms = 0 ;
$this -> location_incoterms = '' ;
2018-07-06 08:07:38 +02:00
2021-02-23 21:09:01 +01:00
if ( empty ( $option ) || $option != 'nolines' ) {
2018-07-06 08:07:38 +02:00
// Lines
$nbp = 5 ;
$xnbp = 0 ;
2021-02-23 21:09:01 +01:00
while ( $xnbp < $nbp ) {
2019-11-08 10:53:31 +01:00
$line = new FactureLigne ( $this -> db );
$line -> desc = $langs -> trans ( " Description " ) . " " . $xnbp ;
$line -> qty = 1 ;
$line -> subprice = 100 ;
$line -> tva_tx = 19.6 ;
$line -> localtax1_tx = 0 ;
$line -> localtax2_tx = 0 ;
$line -> remise_percent = 0 ;
2021-02-23 21:09:01 +01:00
if ( $xnbp == 1 ) { // Qty is negative (product line)
2018-07-06 08:07:38 +02:00
$prodid = mt_rand ( 1 , $num_prods );
2019-11-08 10:53:31 +01:00
$line -> fk_product = $prodids [ $prodid ];
$line -> qty = - 1 ;
$line -> total_ht = - 100 ;
$line -> total_ttc = - 119.6 ;
$line -> total_tva = - 19.6 ;
$line -> multicurrency_total_ht = - 200 ;
$line -> multicurrency_total_ttc = - 239.2 ;
$line -> multicurrency_total_tva = - 39.2 ;
2021-02-23 21:09:01 +01:00
} elseif ( $xnbp == 2 ) { // UP is negative (free line)
2019-11-08 10:53:31 +01:00
$line -> subprice = - 100 ;
$line -> total_ht = - 100 ;
$line -> total_ttc = - 119.6 ;
$line -> total_tva = - 19.6 ;
$line -> remise_percent = 0 ;
$line -> multicurrency_total_ht = - 200 ;
$line -> multicurrency_total_ttc = - 239.2 ;
$line -> multicurrency_total_tva = - 39.2 ;
2021-02-23 21:09:01 +01:00
} elseif ( $xnbp == 3 ) { // Discount is 50% (product line)
2018-07-06 08:07:38 +02:00
$prodid = mt_rand ( 1 , $num_prods );
2019-11-08 10:53:31 +01:00
$line -> fk_product = $prodids [ $prodid ];
$line -> total_ht = 50 ;
$line -> total_ttc = 59.8 ;
$line -> total_tva = 9.8 ;
$line -> multicurrency_total_ht = 100 ;
$line -> multicurrency_total_ttc = 119.6 ;
$line -> multicurrency_total_tva = 19.6 ;
$line -> remise_percent = 50 ;
2020-05-21 15:05:19 +02:00
} else // (product line)
2018-07-06 08:07:38 +02:00
{
$prodid = mt_rand ( 1 , $num_prods );
2019-11-08 10:53:31 +01:00
$line -> fk_product = $prodids [ $prodid ];
$line -> total_ht = 100 ;
$line -> total_ttc = 119.6 ;
$line -> total_tva = 19.6 ;
$line -> multicurrency_total_ht = 200 ;
$line -> multicurrency_total_ttc = 239.2 ;
$line -> multicurrency_total_tva = 39.2 ;
$line -> remise_percent = 0 ;
2018-07-06 08:07:38 +02:00
}
2019-11-08 10:53:31 +01:00
$this -> lines [ $xnbp ] = $line ;
2018-07-06 08:07:38 +02:00
$this -> total_ht += $line -> total_ht ;
$this -> total_tva += $line -> total_tva ;
$this -> total_ttc += $line -> total_ttc ;
$this -> multicurrency_total_ht += $line -> multicurrency_total_ht ;
$this -> multicurrency_total_tva += $line -> multicurrency_total_tva ;
$this -> multicurrency_total_ttc += $line -> multicurrency_total_ttc ;
$xnbp ++ ;
}
$this -> revenuestamp = 0 ;
// Add a line "offered"
2019-11-08 10:53:31 +01:00
$line = new FactureLigne ( $this -> db );
$line -> desc = $langs -> trans ( " Description " ) . " (offered line) " ;
$line -> qty = 1 ;
$line -> subprice = 100 ;
$line -> tva_tx = 19.6 ;
$line -> localtax1_tx = 0 ;
$line -> localtax2_tx = 0 ;
$line -> remise_percent = 100 ;
$line -> total_ht = 0 ;
$line -> total_ttc = 0 ; // 90 * 1.196
$line -> total_tva = 0 ;
$line -> multicurrency_total_ht = 0 ;
$line -> multicurrency_total_ttc = 0 ;
$line -> multicurrency_total_tva = 0 ;
2018-07-06 08:07:38 +02:00
$prodid = mt_rand ( 1 , $num_prods );
2019-11-08 10:53:31 +01:00
$line -> fk_product = $prodids [ $prodid ];
2018-07-06 08:07:38 +02:00
2019-11-08 10:53:31 +01:00
$this -> lines [ $xnbp ] = $line ;
2018-07-06 08:07:38 +02:00
$xnbp ++ ;
}
}
2020-09-08 21:27:28 +02:00
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2018-07-06 08:07:38 +02:00
/**
* Load indicators for dashboard ( this -> nbtodo and this -> nbtodolate )
*
* @ return int < 0 if KO , > 0 if OK
*/
2020-09-08 21:27:28 +02:00
public function load_state_board ()
2018-07-06 08:07:38 +02:00
{
2020-09-08 21:27:28 +02:00
// phpcs:enable
2018-07-06 08:07:38 +02:00
global $conf , $user ;
2019-11-08 10:53:31 +01:00
$this -> nb = array ();
2018-07-06 08:07:38 +02:00
$clause = " WHERE " ;
$sql = " SELECT count(f.rowid) as nb " ;
2019-11-08 10:53:31 +01:00
$sql .= " FROM " . MAIN_DB_PREFIX . " facture as f " ;
$sql .= " LEFT JOIN " . MAIN_DB_PREFIX . " societe as s ON f.fk_soc = s.rowid " ;
2021-10-22 22:15:59 +02:00
if ( empty ( $user -> rights -> societe -> client -> voir ) && ! $user -> socid ) {
2019-11-08 10:53:31 +01:00
$sql .= " LEFT JOIN " . MAIN_DB_PREFIX . " societe_commerciaux as sc ON s.rowid = sc.fk_soc " ;
2021-08-23 17:41:11 +02:00
$sql .= " WHERE sc.fk_user = " . (( int ) $user -> id );
2018-07-06 08:07:38 +02:00
$clause = " AND " ;
}
2019-11-08 10:53:31 +01:00
$sql .= " " . $clause . " f.entity IN ( " . getEntity ( 'invoice' ) . " ) " ;
2018-07-06 08:07:38 +02:00
2019-11-08 10:53:31 +01:00
$resql = $this -> db -> query ( $sql );
2021-02-23 21:09:01 +01:00
if ( $resql ) {
while ( $obj = $this -> db -> fetch_object ( $resql )) {
2019-11-08 10:53:31 +01:00
$this -> nb [ " invoices " ] = $obj -> nb ;
2018-07-06 08:07:38 +02:00
}
2020-09-08 21:27:28 +02:00
$this -> db -> free ( $resql );
2018-07-06 08:07:38 +02:00
return 1 ;
2020-05-21 15:05:19 +02:00
} else {
2018-07-06 08:07:38 +02:00
dol_print_error ( $this -> db );
2019-11-08 10:53:31 +01:00
$this -> error = $this -> db -> error ();
2018-07-06 08:07:38 +02:00
return - 1 ;
}
}
/**
* Create an array of invoice lines
*
* @ return int > 0 if OK , < 0 if KO
*/
2020-09-08 21:27:28 +02:00
public function getLinesArray ()
2018-07-06 08:07:38 +02:00
{
2020-09-08 21:27:28 +02:00
return $this -> fetch_lines ();
2018-07-06 08:07:38 +02:00
}
/**
* Create a document onto disk according to template module .
*
2020-12-13 13:34:21 +01:00
* @ param string $modele Generator to use . Caller must set it to obj -> model_pdf or GETPOST ( 'model' , 'alpha' ) for example .
* @ param Translate $outputlangs Object lang to use for translation
2018-07-06 08:07:38 +02:00
* @ param int $hidedetails Hide details of lines
* @ param int $hidedesc Hide description
* @ param int $hideref Hide ref
2020-11-01 17:01:26 +01:00
* @ param null | array $moreparams Array to provide more information
2018-07-06 08:07:38 +02:00
* @ return int < 0 if KO , > 0 if OK
*/
2019-01-27 15:20:16 +01:00
public function generateDocument ( $modele , $outputlangs , $hidedetails = 0 , $hidedesc = 0 , $hideref = 0 , $moreparams = null )
2018-07-06 08:07:38 +02:00
{
2019-11-08 10:53:31 +01:00
global $conf , $langs ;
2018-07-06 08:07:38 +02:00
2020-11-01 17:01:26 +01:00
$outputlangs -> loadLangs ( array ( " bills " , " products " ));
2018-07-06 08:07:38 +02:00
2021-02-23 21:09:01 +01:00
if ( ! dol_strlen ( $modele )) {
2018-10-15 13:30:07 +02:00
$modele = 'crabe' ;
$thisTypeConfName = 'FACTURE_ADDON_PDF_' . $this -> type ;
2020-12-13 13:34:21 +01:00
if ( ! empty ( $this -> model_pdf )) {
$modele = $this -> model_pdf ;
} elseif ( ! empty ( $this -> modelpdf )) { // deprecated
2018-10-15 13:30:07 +02:00
$modele = $this -> modelpdf ;
2019-11-08 10:53:31 +01:00
} elseif ( ! empty ( $conf -> global -> $thisTypeConfName )) {
2018-10-15 13:30:07 +02:00
$modele = $conf -> global -> $thisTypeConfName ;
2019-11-08 10:53:31 +01:00
} elseif ( ! empty ( $conf -> global -> FACTURE_ADDON_PDF )) {
2018-10-15 13:30:07 +02:00
$modele = $conf -> global -> FACTURE_ADDON_PDF ;
}
2018-07-06 08:07:38 +02:00
}
$modelpath = " core/modules/facture/doc/ " ;
return $this -> commonGenerateDocument ( $modelpath , $modele , $outputlangs , $hidedetails , $hidedesc , $hideref , $moreparams );
}
/**
* Gets the smallest reference available for a new cycle
*
* @ return int >= 1 if OK , - 1 if error
*/
2020-09-08 21:27:28 +02:00
public function newCycle ()
2018-07-06 08:07:38 +02:00
{
2019-11-08 10:53:31 +01:00
$sql = 'SELECT max(situation_cycle_ref) FROM ' . MAIN_DB_PREFIX . 'facture as f' ;
$sql .= " WHERE f.entity IN ( " . getEntity ( 'invoice' , 0 ) . " ) " ;
2018-07-06 08:07:38 +02:00
$resql = $this -> db -> query ( $sql );
if ( $resql ) {
2022-05-18 23:40:42 +02:00
if ( $this -> db -> num_rows ( $resql ) > 0 ) {
2018-07-06 08:07:38 +02:00
$res = $this -> db -> fetch_array ( $resql );
$ref = $res [ 'max(situation_cycle_ref)' ];
$ref ++ ;
} else {
$ref = 1 ;
}
$this -> db -> free ( $resql );
return $ref ;
} else {
$this -> error = $this -> db -> lasterror ();
2019-11-08 10:53:31 +01:00
dol_syslog ( " Error sql= " . $sql . " , error= " . $this -> error , LOG_ERR );
2018-07-06 08:07:38 +02:00
return - 1 ;
}
}
2020-09-08 21:27:28 +02:00
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2018-07-06 08:07:38 +02:00
/**
* Checks if the invoice is the first of a cycle
*
* @ return boolean
*/
2020-09-08 21:27:28 +02:00
public function is_first ()
2018-07-06 08:07:38 +02:00
{
2020-09-08 21:27:28 +02:00
// phpcs:enable
2018-07-06 08:07:38 +02:00
return ( $this -> situation_counter == 1 );
}
2020-09-08 21:27:28 +02:00
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2018-07-06 08:07:38 +02:00
/**
* Returns an array containing the previous situations as Facture objects
*
* @ return mixed - 1 if error , array of previous situations
*/
2020-09-08 21:27:28 +02:00
public function get_prev_sits ()
2018-07-06 08:07:38 +02:00
{
2020-09-08 21:27:28 +02:00
// phpcs:enable
2018-07-06 08:07:38 +02:00
global $conf ;
2019-11-08 10:53:31 +01:00
$sql = 'SELECT rowid FROM ' . MAIN_DB_PREFIX . 'facture' ;
2021-03-30 17:45:15 +02:00
$sql .= ' WHERE situation_cycle_ref = ' . (( int ) $this -> situation_cycle_ref );
2021-08-27 23:36:06 +02:00
$sql .= ' AND situation_counter < ' . (( int ) $this -> situation_counter );
2019-11-08 10:53:31 +01:00
$sql .= ' AND entity = ' . ( $this -> entity > 0 ? $this -> entity : $conf -> entity );
2018-07-06 08:07:38 +02:00
$resql = $this -> db -> query ( $sql );
$res = array ();
2022-05-18 23:40:42 +02:00
if ( $resql && $this -> db -> num_rows ( $resql ) > 0 ) {
2018-07-06 08:07:38 +02:00
while ( $row = $this -> db -> fetch_object ( $resql )) {
$id = $row -> rowid ;
$situation = new Facture ( $this -> db );
$situation -> fetch ( $id );
$res [] = $situation ;
}
} else {
$this -> error = $this -> db -> error ();
2019-11-08 10:53:31 +01:00
dol_syslog ( " Error sql= " . $sql . " , error= " . $this -> error , LOG_ERR );
2018-07-06 08:07:38 +02:00
return - 1 ;
}
return $res ;
}
/**
* Sets the invoice as a final situation
*
* @ param User $user Object user
* @ param int $notrigger 1 = Does not execute triggers , 0 = execute triggers
* @ return int < 0 if KO , > 0 if OK
*/
2020-09-08 21:27:28 +02:00
public function setFinal ( User $user , $notrigger = 0 )
2018-07-06 08:07:38 +02:00
{
2019-11-08 10:53:31 +01:00
$error = 0 ;
2018-07-06 08:07:38 +02:00
$this -> db -> begin ();
2021-08-27 23:36:06 +02:00
$sql = 'UPDATE ' . MAIN_DB_PREFIX . 'facture SET situation_final = ' . (( int ) $this -> situation_final ) . ' WHERE rowid = ' . (( int ) $this -> id );
2018-07-06 08:07:38 +02:00
dol_syslog ( __METHOD__ , LOG_DEBUG );
2019-11-08 10:53:31 +01:00
$resql = $this -> db -> query ( $sql );
2021-02-23 21:09:01 +01:00
if ( ! $resql ) {
2019-11-08 10:53:31 +01:00
$this -> errors [] = $this -> db -> error ();
2018-07-06 08:07:38 +02:00
$error ++ ;
}
2021-02-23 21:09:01 +01:00
if ( ! $notrigger && empty ( $error )) {
2018-07-06 08:07:38 +02:00
// Call trigger
2019-11-08 10:53:31 +01:00
$result = $this -> call_trigger ( 'BILL_MODIFY' , $user );
2021-02-23 21:09:01 +01:00
if ( $result < 0 ) {
$error ++ ;
}
2018-07-06 08:07:38 +02:00
// End call triggers
}
2021-02-23 21:09:01 +01:00
if ( ! $error ) {
2018-07-06 08:07:38 +02:00
$this -> db -> commit ();
return 1 ;
2020-05-21 15:05:19 +02:00
} else {
2021-02-23 21:09:01 +01:00
foreach ( $this -> errors as $errmsg ) {
2018-07-06 08:07:38 +02:00
dol_syslog ( __METHOD__ . ' Error: ' . $errmsg , LOG_ERR );
2019-11-08 10:53:31 +01:00
$this -> error .= ( $this -> error ? ', ' . $errmsg : $errmsg );
2018-07-06 08:07:38 +02:00
}
$this -> db -> rollback ();
2019-11-08 10:53:31 +01:00
return - 1 * $error ;
2018-07-06 08:07:38 +02:00
}
}
2020-09-08 21:27:28 +02:00
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2018-07-06 08:07:38 +02:00
/**
* Checks if the invoice is the last in its cycle
*
* @ return bool Last of the cycle status
*/
2020-09-08 21:27:28 +02:00
public function is_last_in_cycle ()
2018-07-06 08:07:38 +02:00
{
2020-09-08 21:27:28 +02:00
// phpcs:enable
2018-07-06 08:07:38 +02:00
global $conf ;
if ( ! empty ( $this -> situation_cycle_ref )) {
// No point in testing anything if we're not inside a cycle
2019-11-08 10:53:31 +01:00
$sql = 'SELECT max(situation_counter) FROM ' . MAIN_DB_PREFIX . 'facture' ;
2021-03-30 17:45:15 +02:00
$sql .= ' WHERE situation_cycle_ref = ' . (( int ) $this -> situation_cycle_ref );
2019-11-08 10:53:31 +01:00
$sql .= ' AND entity = ' . ( $this -> entity > 0 ? $this -> entity : $conf -> entity );
2018-07-06 08:07:38 +02:00
$resql = $this -> db -> query ( $sql );
2022-05-18 23:40:42 +02:00
if ( $resql && $this -> db -> num_rows ( $resql ) > 0 ) {
2018-07-06 08:07:38 +02:00
$res = $this -> db -> fetch_array ( $resql );
$last = $res [ 'max(situation_counter)' ];
return ( $last == $this -> situation_counter );
} else {
$this -> error = $this -> db -> lasterror ();
2019-11-08 10:53:31 +01:00
dol_syslog ( get_class ( $this ) . " ::select Error " . $this -> error , LOG_ERR );
2018-07-06 08:07:38 +02:00
return false ;
}
} else {
return true ;
}
}
/**
* Function used to replace a thirdparty id with another one .
*
2019-03-07 11:16:24 +01:00
* @ param DoliDB $db Database handler
2019-03-11 01:41:09 +01:00
* @ param int $origin_id Old third - party id
* @ param int $dest_id New third - party id
2018-07-06 08:07:38 +02:00
* @ return bool
*/
public static function replaceThirdparty ( DoliDB $db , $origin_id , $dest_id )
{
$tables = array (
'facture'
);
return CommonObject :: commonReplaceThirdparty ( $db , $origin_id , $dest_id , $tables );
}
2021-11-23 21:38:29 +01:00
/**
* Function used to replace a product id with another one .
*
* @ param DoliDB $db Database handler
* @ param int $origin_id Old product id
* @ param int $dest_id New product id
* @ return bool
*/
public static function replaceProduct ( DoliDB $db , $origin_id , $dest_id )
{
$tables = array (
'facturedet'
);
return CommonObject :: commonReplaceProduct ( $db , $origin_id , $dest_id , $tables );
}
2018-07-06 08:07:38 +02:00
/**
* Is the customer invoice delayed ?
*
* @ return bool
*/
public function hasDelay ()
{
global $conf ;
$now = dol_now ();
// Paid invoices have status STATUS_CLOSED
2021-02-23 21:09:01 +01:00
if ( $this -> statut != Facture :: STATUS_VALIDATED ) {
return false ;
}
2018-07-06 08:07:38 +02:00
2020-02-11 16:54:27 +01:00
$hasDelay = $this -> date_lim_reglement < ( $now - $conf -> facture -> client -> warning_delay );
2021-02-23 21:09:01 +01:00
if ( $hasDelay && ! empty ( $this -> retained_warranty ) && ! empty ( $this -> retained_warranty_date_limit )) {
2022-05-22 17:09:08 +02:00
$totalpaid = $this -> getSommePaiement ();
$totalpaid = floatval ( $totalpaid );
2020-09-08 21:27:28 +02:00
$RetainedWarrantyAmount = $this -> getRetainedWarrantyAmount ();
2022-05-22 17:09:08 +02:00
if ( $totalpaid >= 0 && $RetainedWarrantyAmount >= 0 ) {
if (( $totalpaid < $this -> total_ttc - $RetainedWarrantyAmount ) && $this -> date_lim_reglement < ( $now - $conf -> facture -> client -> warning_delay )) {
2020-09-08 21:27:28 +02:00
$hasDelay = 1 ;
2022-05-22 17:09:08 +02:00
} elseif ( $totalpaid < $this -> total_ttc && $this -> retained_warranty_date_limit < ( $now - $conf -> facture -> client -> warning_delay )) {
2020-09-08 21:27:28 +02:00
$hasDelay = 1 ;
} else {
$hasDelay = 0 ;
}
}
2020-02-11 16:54:27 +01:00
}
return $hasDelay ;
2018-07-06 08:07:38 +02:00
}
2019-06-04 14:00:18 +02:00
2020-02-19 11:54:55 +01:00
/**
* Currently used for documents generation : to know if retained warranty need to be displayed
* @ return bool
*/
2020-02-25 23:02:13 +01:00
public function displayRetainedWarranty ()
2020-02-19 12:07:42 +01:00
{
2020-02-19 11:54:55 +01:00
global $conf ;
2020-04-01 12:12:30 +02:00
// TODO : add a flag on invoices to store this conf : INVOICE_RETAINED_WARRANTY_LIMITED_TO_FINAL_SITUATION
2020-02-19 11:54:55 +01:00
2021-11-15 04:26:14 +01:00
// note : we don't need to test INVOICE_USE_RETAINED_WARRANTY because if $this->retained_warranty is not empty it's because it was set when this conf was active
2020-02-19 11:54:55 +01:00
$displayWarranty = false ;
2020-04-23 18:55:10 +02:00
if ( ! empty ( $this -> retained_warranty )) {
2020-02-19 11:54:55 +01:00
$displayWarranty = true ;
2020-04-01 12:12:30 +02:00
if ( $this -> type == Facture :: TYPE_SITUATION && ! empty ( $conf -> global -> INVOICE_RETAINED_WARRANTY_LIMITED_TO_FINAL_SITUATION )) {
2020-02-19 11:54:55 +01:00
// Check if this situation invoice is 100% for real
$displayWarranty = false ;
if ( ! empty ( $this -> situation_final )) {
$displayWarranty = true ;
} elseif ( ! empty ( $this -> lines ) && $this -> status == Facture :: STATUS_DRAFT ) {
// $object->situation_final need validation to be done so this test is need for draft
$displayWarranty = true ;
foreach ( $this -> lines as $i => $line ) {
if ( $line -> product_type < 2 && $line -> situation_percent < 100 ) {
$displayWarranty = false ;
break ;
}
}
}
}
}
return $displayWarranty ;
}
2019-06-04 14:00:18 +02:00
2018-10-04 11:09:16 +02:00
/**
2020-02-11 16:54:27 +01:00
* @ param int $rounding Minimum number of decimal to show . If 0 , no change , if - 1 , we use min ( $conf -> global -> MAIN_MAX_DECIMALS_UNIT , $conf -> global -> MAIN_MAX_DECIMALS_TOT )
2022-09-08 15:18:52 +02:00
* @ return float or - 1 if not available
2018-10-04 11:09:16 +02:00
*/
2020-02-11 16:54:27 +01:00
public function getRetainedWarrantyAmount ( $rounding = - 1 )
2019-06-24 14:36:06 +02:00
{
2020-02-11 16:54:27 +01:00
global $conf ;
2020-09-08 21:27:28 +02:00
if ( empty ( $this -> retained_warranty )) {
return - 1 ;
}
$retainedWarrantyAmount = 0 ;
// Billed - retained warranty
2021-02-23 21:09:01 +01:00
if ( $this -> type == Facture :: TYPE_SITUATION && ! empty ( $conf -> global -> INVOICE_RETAINED_WARRANTY_LIMITED_TO_FINAL_SITUATION )) {
2020-09-08 21:27:28 +02:00
$displayWarranty = true ;
// Check if this situation invoice is 100% for real
if ( ! empty ( $this -> lines )) {
foreach ( $this -> lines as $i => $line ) {
if ( $line -> product_type < 2 && $line -> situation_percent < 100 ) {
$displayWarranty = false ;
break ;
}
}
}
2021-02-23 21:09:01 +01:00
if ( $displayWarranty && ! empty ( $this -> situation_final )) {
2020-09-08 21:27:28 +02:00
$this -> fetchPreviousNextSituationInvoice ();
$TPreviousIncoice = $this -> tab_previous_situation_invoice ;
$total2BillWT = 0 ;
foreach ( $TPreviousIncoice as & $fac ) {
$total2BillWT += $fac -> total_ttc ;
}
$total2BillWT += $this -> total_ttc ;
$retainedWarrantyAmount = $total2BillWT * $this -> retained_warranty / 100 ;
} else {
return - 1 ;
}
} else {
// Because one day retained warranty could be used on standard invoices
$retainedWarrantyAmount = $this -> total_ttc * $this -> retained_warranty / 100 ;
}
2019-09-03 16:23:39 +02:00
2020-02-21 17:53:37 +01:00
if ( $rounding < 0 ) {
$rounding = min ( $conf -> global -> MAIN_MAX_DECIMALS_UNIT , $conf -> global -> MAIN_MAX_DECIMALS_TOT );
2020-02-19 11:54:55 +01:00
}
2020-04-23 18:55:10 +02:00
if ( $rounding > 0 ) {
2020-02-19 11:54:55 +01:00
return round ( $retainedWarrantyAmount , $rounding );
2020-02-11 16:54:27 +01:00
}
2020-09-08 21:27:28 +02:00
return $retainedWarrantyAmount ;
2018-10-04 11:09:16 +02:00
}
2019-09-03 16:23:39 +02:00
2018-08-08 17:36:39 +02:00
/**
* Change the retained warranty
*
* @ param float $value value of retained warranty
* @ return int > 0 if OK , < 0 if KO
*/
2019-06-24 14:36:06 +02:00
public function setRetainedWarranty ( $value )
2018-08-08 17:36:39 +02:00
{
2020-09-08 21:27:28 +02:00
dol_syslog ( get_class ( $this ) . '::setRetainedWarranty(' . $value . ')' );
2021-08-27 23:36:06 +02:00
2021-02-23 21:09:01 +01:00
if ( $this -> statut >= 0 ) {
2020-09-08 21:27:28 +02:00
$fieldname = 'retained_warranty' ;
$sql = 'UPDATE ' . MAIN_DB_PREFIX . $this -> table_element ;
2021-08-27 23:36:06 +02:00
$sql .= " SET " . $fieldname . " = " . (( float ) $value );
2021-03-14 12:20:23 +01:00
$sql .= ' WHERE rowid=' . (( int ) $this -> id );
2020-09-08 21:27:28 +02:00
2021-02-23 21:09:01 +01:00
if ( $this -> db -> query ( $sql )) {
2020-09-08 21:27:28 +02:00
$this -> retained_warranty = floatval ( $value );
return 1 ;
} else {
dol_syslog ( get_class ( $this ) . '::setRetainedWarranty Erreur ' . $sql . ' - ' . $this -> db -> error ());
$this -> error = $this -> db -> error ();
return - 1 ;
}
} else {
dol_syslog ( get_class ( $this ) . '::setRetainedWarranty, status of the object is incompatible' );
$this -> error = 'Status of the object is incompatible ' . $this -> statut ;
return - 2 ;
}
2018-08-08 17:36:39 +02:00
}
2019-09-03 16:23:39 +02:00
2018-08-08 17:36:39 +02:00
/**
* Change the retained_warranty_date_limit
*
2019-06-24 14:36:06 +02:00
* @ param int $timestamp date limit of retained warranty in timestamp format
* @ param string $dateYmd date limit of retained warranty in Y m d format
2018-08-08 17:36:39 +02:00
* @ return int > 0 if OK , < 0 if KO
*/
2019-06-24 14:36:06 +02:00
public function setRetainedWarrantyDateLimit ( $timestamp , $dateYmd = false )
2018-08-08 17:36:39 +02:00
{
2020-09-08 21:27:28 +02:00
if ( ! $timestamp && $dateYmd ) {
$timestamp = $this -> db -> jdate ( $dateYmd );
}
dol_syslog ( get_class ( $this ) . '::setRetainedWarrantyDateLimit(' . $timestamp . ')' );
2021-02-23 21:09:01 +01:00
if ( $this -> statut >= 0 ) {
2020-09-08 21:27:28 +02:00
$fieldname = 'retained_warranty_date_limit' ;
$sql = 'UPDATE ' . MAIN_DB_PREFIX . $this -> table_element ;
2021-08-28 00:55:51 +02:00
$sql .= " SET " . $fieldname . " = " . ( strval ( $timestamp ) != '' ? " ' " . $this -> db -> idate ( $timestamp ) . " ' " : 'null' );
$sql .= ' WHERE rowid = ' . (( int ) $this -> id );
2020-09-08 21:27:28 +02:00
2021-02-23 21:09:01 +01:00
if ( $this -> db -> query ( $sql )) {
2020-09-08 21:27:28 +02:00
$this -> retained_warranty_date_limit = $timestamp ;
return 1 ;
} else {
dol_syslog ( get_class ( $this ) . '::setRetainedWarrantyDateLimit Erreur ' . $sql . ' - ' . $this -> db -> error ());
$this -> error = $this -> db -> error ();
return - 1 ;
}
} else {
dol_syslog ( get_class ( $this ) . '::setRetainedWarrantyDateLimit, status of the object is incompatible' );
$this -> error = 'Status of the object is incompatible ' . $this -> statut ;
return - 2 ;
}
2018-08-08 17:36:39 +02:00
}
2021-04-19 12:48:08 +02:00
/**
* Send reminders by emails for ivoices that are due
* CAN BE A CRON TASK
*
* @ param int $nbdays Delay after due date ( or before if delay is negative )
* @ param string $paymentmode '' or 'all' by default ( no filter ), or 'LIQ' , 'CHQ' , CB ' , ...
* @ param int | string $template Name ( or id ) of email template ( Must be a template of type 'facture_send' )
* @ return int 0 if OK , <> 0 if KO ( this function is used also by cron so only 0 is OK )
*/
2021-04-27 03:25:49 +02:00
public function sendEmailsRemindersOnInvoiceDueDate ( $nbdays = 0 , $paymentmode = 'all' , $template = '' )
2021-04-19 12:48:08 +02:00
{
global $conf , $langs , $user ;
$error = 0 ;
$this -> output = '' ;
$this -> error = '' ;
$nbMailSend = 0 ;
$errorsMsg = array ();
2021-05-04 13:33:18 +02:00
$langs -> load ( " bills " );
2022-06-11 09:46:28 +02:00
if ( ! isModEnabled ( 'facture' )) { // Should not happen. If module disabled, cron job should not be visible.
2021-04-27 03:25:49 +02:00
$this -> output .= $langs -> trans ( 'ModuleNotEnabled' , $langs -> transnoentitiesnoconv ( " Facture " ));
2021-04-19 12:48:08 +02:00
return 0 ;
}
/* if ( empty ( $conf -> global -> FACTURE_REMINDER_EMAIL )) {
$langs -> load ( " bills " );
2021-04-27 03:25:49 +02:00
$this -> output .= $langs -> trans ( 'EventRemindersByEmailNotEnabled' , $langs -> transnoentitiesnoconv ( " Facture " ));
2021-04-19 12:48:08 +02:00
return 0 ;
}
*/
require_once DOL_DOCUMENT_ROOT . '/core/lib/date.lib.php' ;
require_once DOL_DOCUMENT_ROOT . '/core/class/html.formmail.class.php' ;
2021-05-04 11:06:24 +02:00
require_once DOL_DOCUMENT_ROOT . '/core/class/CMailFile.class.php' ;
2021-04-19 12:48:08 +02:00
$formmail = new FormMail ( $this -> db );
$now = dol_now ();
2021-05-04 13:33:18 +02:00
$tmpidate = dol_get_first_hour ( dol_time_plus_duree ( $now , $nbdays , 'd' ), 'gmt' );
2021-04-19 12:48:08 +02:00
$tmpinvoice = new Facture ( $this -> db );
dol_syslog ( __METHOD__ , LOG_DEBUG );
2021-11-15 04:26:14 +01:00
// Select all action comm reminder
2021-04-19 12:48:08 +02:00
$sql = " SELECT rowid as id FROM " . MAIN_DB_PREFIX . " facture as f " ;
if ( ! empty ( $paymentmode ) && $paymentmode != 'all' ) {
$sql .= " , " . MAIN_DB_PREFIX . " c_paiement as cp " ;
}
$sql .= " WHERE f.paye = 0 " ;
2022-07-07 19:10:46 +02:00
$sql .= " AND f.fk_statut = " . self :: STATUS_VALIDATED ;
2021-05-04 13:33:18 +02:00
$sql .= " AND f.date_lim_reglement = ' " . $this -> db -> idate ( $tmpidate , 'gmt' ) . " ' " ;
2021-04-19 12:48:08 +02:00
$sql .= " AND f.entity IN ( " . getEntity ( 'facture' ) . " ) " ;
if ( ! empty ( $paymentmode ) && $paymentmode != 'all' ) {
$sql .= " AND f.fk_mode_reglement = cp.id AND cp.code = ' " . $this -> db -> escape ( $paymentmode ) . " ' " ;
}
// TODO Add filter to check there is no payment started
$sql .= $this -> db -> order ( " date_lim_reglement " , " ASC " );
2021-05-04 13:33:18 +02:00
2021-04-19 12:48:08 +02:00
$resql = $this -> db -> query ( $sql );
2021-05-04 13:33:18 +02:00
$stmpidate = dol_print_date ( $tmpidate , 'day' , 'gmt' );
2021-05-11 10:30:46 +02:00
$this -> output .= $langs -> transnoentitiesnoconv ( " SearchUnpaidInvoicesWithDueDate " , $stmpidate );
if ( ! empty ( $paymentmode ) && $paymentmode != 'all' ) {
$this -> output .= ' (' . $langs -> transnoentitiesnoconv ( " PaymentMode " ) . ' ' . $paymentmode . ')' ;
}
$this -> output .= '<br>' ;
2021-04-27 03:25:49 +02:00
2021-04-19 12:48:08 +02:00
if ( $resql ) {
while ( $obj = $this -> db -> fetch_object ( $resql )) {
if ( ! $error ) {
// Load event
$res = $tmpinvoice -> fetch ( $obj -> id );
if ( $res > 0 ) {
$tmpinvoice -> fetch_thirdparty ();
$outputlangs = new Translate ( '' , $conf );
if ( $tmpinvoice -> thirdparty -> default_lang ) {
$outputlangs -> setDefaultLang ( $tmpinvoice -> thirdparty -> default_lang );
2021-05-04 13:33:18 +02:00
$outputlangs -> loadLangs ( array ( " main " , " bills " ));
2021-04-19 12:48:08 +02:00
} else {
$outputlangs = $langs ;
}
// Select email template
$arraymessage = $formmail -> getEMailTemplate ( $this -> db , 'facture_send' , $user , $outputlangs , ( is_numeric ( $template ) ? $template : 0 ), 1 , ( is_numeric ( $template ) ? '' : $template ));
if ( is_numeric ( $arraymessage ) && $arraymessage <= 0 ) {
2021-05-04 13:33:18 +02:00
$langs -> load ( " errors " );
$this -> output .= $langs -> trans ( 'ErrorFailedToFindEmailTemplate' , $template );
2021-04-19 12:48:08 +02:00
return 0 ;
}
// PREPARE EMAIL
$errormesg = '' ;
// Make substitution in email content
2021-05-04 13:33:18 +02:00
$substitutionarray = getCommonSubstitutionArray ( $outputlangs , 0 , '' , $tmpinvoice );
2021-04-19 12:48:08 +02:00
2021-05-04 13:33:18 +02:00
complete_substitutions_array ( $substitutionarray , $outputlangs , $tmpinvoice );
2021-04-19 12:48:08 +02:00
2021-05-04 18:04:09 +02:00
// Topic
$sendTopic = make_substitutions ( empty ( $arraymessage -> topic ) ? $outputlangs -> transnoentitiesnoconv ( 'InformationMessage' ) : $arraymessage -> topic , $substitutionarray , $outputlangs , 1 );
2021-04-19 12:48:08 +02:00
// Content
2021-05-04 13:33:18 +02:00
$content = $outputlangs -> transnoentitiesnoconv ( $arraymessage -> content );
$sendContent = make_substitutions ( $content , $substitutionarray , $outputlangs , 1 );
2021-04-19 12:48:08 +02:00
// Recipient
2022-05-18 12:40:44 +02:00
$to = '' ;
2021-04-19 12:48:08 +02:00
$res = $tmpinvoice -> fetch_thirdparty ();
$recipient = $tmpinvoice -> thirdparty ;
if ( $res > 0 ) {
if ( ! empty ( $recipient -> email )) {
$to = $recipient -> email ;
} else {
2022-05-02 12:57:13 +02:00
$errormesg = " Failed to send remind to thirdparty id= " . $tmpinvoice -> socid . " . No email defined for user. " ;
2021-04-19 12:48:08 +02:00
$error ++ ;
}
} else {
2022-05-02 12:57:13 +02:00
$errormesg = " Failed to load recipient with thirdparty id= " . $tmpinvoice -> socid ;
2021-04-19 12:48:08 +02:00
$error ++ ;
}
// Sender
$from = $conf -> global -> MAIN_MAIL_EMAIL_FROM ;
if ( empty ( $from )) {
$errormesg = " Failed to get sender into global setup MAIN_MAIL_EMAIL_FROM " ;
$error ++ ;
}
2022-05-18 12:40:44 +02:00
if ( ! $error && $to ) {
2022-07-08 14:11:13 +02:00
$this -> db -> begin ();
2021-04-19 12:48:08 +02:00
// Errors Recipient
$errors_to = $conf -> global -> MAIN_MAIL_ERRORS_TO ;
$trackid = 'inv' . $tmpinvoice -> id ;
2022-07-08 14:11:13 +02:00
$sendcontext = 'standard' ;
2021-04-19 12:48:08 +02:00
// Mail Creation
2022-07-08 14:11:13 +02:00
$cMailFile = new CMailFile ( $sendTopic , $to , $from , $sendContent , array (), array (), array (), '' , " " , 0 , 1 , $errors_to , '' , $trackid , '' , $sendcontext , '' );
2021-04-19 12:48:08 +02:00
// Sending Mail
if ( $cMailFile -> sendfile ()) {
$nbMailSend ++ ;
2022-07-08 14:11:13 +02:00
// Add a line into event table
require_once DOL_DOCUMENT_ROOT . '/comm/action/class/actioncomm.class.php' ;
// Insert record of emails sent
$actioncomm = new ActionComm ( $this -> db );
$actioncomm -> type_code = 'AC_OTH_AUTO' ; // Event insert into agenda automatically
$actioncomm -> socid = $tmpinvoice -> thirdparty -> id ; // To link to a company
$actioncomm -> contact_id = 0 ;
$actioncomm -> code = 'AC_EMAIL' ;
$actioncomm -> label = 'sendEmailsRemindersOnInvoiceDueDateOK' ;
$actioncomm -> note_private = $sendContent ;
$actioncomm -> fk_project = $tmpinvoice -> fk_project ;
$actioncomm -> datep = dol_now ();
$actioncomm -> datef = $actioncomm -> datep ;
$actioncomm -> percentage = - 1 ; // Not applicable
$actioncomm -> authorid = $user -> id ; // User saving action
$actioncomm -> userownerid = $user -> id ; // Owner of action
// Fields when action is an email (content should be added into note)
$actioncomm -> email_msgid = $cMailFile -> msgid ;
$actioncomm -> email_from = $from ;
$actioncomm -> email_sender = '' ;
$actioncomm -> email_to = $to ;
//$actioncomm->email_tocc = $sendtocc;
//$actioncomm->email_tobcc = $sendtobcc;
//$actioncomm->email_subject = $subject;
$actioncomm -> errors_to = $errors_to ;
//$actioncomm->extraparams = $extraparams;
$actioncomm -> create ( $user );
2021-04-19 12:48:08 +02:00
} else {
$errormesg = $cMailFile -> error . ' : ' . $to ;
$error ++ ;
2022-07-08 14:11:13 +02:00
// Add a line into event table
require_once DOL_DOCUMENT_ROOT . '/comm/action/class/actioncomm.class.php' ;
// Insert record of emails sent
$actioncomm = new ActionComm ( $this -> db );
$actioncomm -> type_code = 'AC_OTH_AUTO' ; // Event insert into agenda automatically
$actioncomm -> socid = $tmpinvoice -> thirdparty -> id ; // To link to a company
$actioncomm -> contact_id = 0 ;
$actioncomm -> code = 'AC_EMAIL' ;
$actioncomm -> label = 'sendEmailsRemindersOnInvoiceDueDateKO' ;
$actioncomm -> note_private = $errormesg ;
$actioncomm -> fk_project = $tmpinvoice -> fk_project ;
$actioncomm -> datep = dol_now ();
$actioncomm -> datef = $actioncomm -> datep ;
$actioncomm -> percentage = - 1 ; // Not applicable
$actioncomm -> authorid = $user -> id ; // User saving action
$actioncomm -> userownerid = $user -> id ; // Owner of action
// Fields when action is an email (content should be added into note)
$actioncomm -> email_msgid = $cMailFile -> msgid ;
$actioncomm -> email_from = $from ;
$actioncomm -> email_sender = '' ;
$actioncomm -> email_to = $to ;
//$actioncomm->email_tocc = $sendtocc;
//$actioncomm->email_tobcc = $sendtobcc;
//$actioncomm->email_subject = $subject;
$actioncomm -> errors_to = $errors_to ;
//$actioncomm->extraparams = $extraparams;
$actioncomm -> create ( $user );
2021-04-19 12:48:08 +02:00
}
2022-07-08 14:11:13 +02:00
$this -> db -> commit (); // We always commit
2021-04-19 12:48:08 +02:00
}
if ( $errormesg ) {
$errorsMsg [] = $errormesg ;
}
} else {
$errorsMsg [] = 'Failed to fetch record invoice with ID = ' . $obj -> id ;
$error ++ ;
}
}
}
} else {
$error ++ ;
}
if ( ! $error ) {
2021-04-27 03:25:49 +02:00
$this -> output .= 'Nb of emails sent : ' . $nbMailSend ;
2021-04-19 12:48:08 +02:00
return 0 ;
} else {
$this -> error = 'Nb of emails sent : ' . $nbMailSend . ', ' . ( ! empty ( $errorsMsg )) ? join ( ', ' , $errorsMsg ) : $error ;
return $error ;
}
}
2022-03-01 16:18:34 +01:00
/**
* See if current invoice date is posterior to the last invoice date among validated invoices of same type .
2022-07-08 14:11:13 +02:00
*
2022-05-12 14:42:55 +02:00
* @ param boolean $allow_validated_drafts return true if the invoice has been validated before returning to DRAFT state .
2022-07-08 14:11:13 +02:00
* @ return array return array
2022-03-01 16:18:34 +01:00
*/
2022-05-12 14:42:55 +02:00
public function willBeLastOfSameType ( $allow_validated_drafts = false )
2022-03-01 16:18:34 +01:00
{
// get date of last validated invoices of same type
2022-03-09 09:34:50 +01:00
$sql = " SELECT datef " ;
$sql .= " FROM " . MAIN_DB_PREFIX . " facture " ;
$sql .= " WHERE type = " . ( int ) $this -> type ;
$sql .= " AND date_valid IS NOT NULL " ;
$sql .= " ORDER BY datef DESC LIMIT 1 " ;
2022-03-01 16:18:34 +01:00
$result = $this -> db -> query ( $sql );
if ( $result ) {
// compare with current validation date
if ( $this -> db -> num_rows ( $result )) {
$obj = $this -> db -> fetch_object ( $result );
$last_date = $this -> db -> jdate ( $obj -> datef );
$invoice_date = $this -> date ;
2022-05-12 14:42:55 +02:00
$is_last_of_same_type = $invoice_date >= $last_date ;
if ( $allow_validated_drafts ) {
$is_last_of_same_type = $is_last_of_same_type || ( ! strpos ( $this -> ref , 'PROV' ) && $this -> status == self :: STATUS_DRAFT );
}
2022-07-08 14:11:13 +02:00
return array ( $is_last_of_same_type , $last_date );
2022-03-01 16:18:34 +01:00
} else {
// element is first of type to be validated
2022-07-08 14:11:13 +02:00
return array ( true );
2022-03-01 16:18:34 +01:00
}
} else {
dol_print_error ( $this -> db );
}
}
2018-07-06 08:07:38 +02:00
}
2018-07-05 11:52:41 +02:00
2018-07-06 08:07:38 +02:00
/**
* Class to manage invoice lines .
* Saved into database table llx_facturedet
*/
class FactureLigne extends CommonInvoiceLine
{
2020-09-08 21:27:28 +02:00
/**
2018-08-23 17:07:27 +02:00
* @ var string ID to identify managed object
*/
2019-11-08 10:53:31 +01:00
public $element = 'facturedet' ;
2018-09-02 21:08:57 +02:00
2020-09-08 21:27:28 +02:00
/**
2018-08-22 18:34:50 +02:00
* @ var string Name of table without prefix where object is stored
*/
2019-11-08 10:53:31 +01:00
public $table_element = 'facturedet' ;
2018-07-06 08:07:38 +02:00
2018-10-09 15:38:42 +02:00
public $oldline ;
2018-07-06 08:07:38 +02:00
//! From llx_facturedet
//! Id facture
2018-10-09 15:38:42 +02:00
public $fk_facture ;
2018-07-06 08:07:38 +02:00
//! Id parent line
2018-10-09 15:38:42 +02:00
public $fk_parent_line ;
2020-10-12 19:33:00 +02:00
2018-07-06 08:07:38 +02:00
//! Description ligne
2018-10-09 15:38:42 +02:00
public $desc ;
2020-09-04 19:32:42 +02:00
public $ref_ext ; // External reference of the line
2018-07-06 08:07:38 +02:00
2019-11-08 10:53:31 +01:00
public $localtax1_type ; // Local tax 1 type
public $localtax2_type ; // Local tax 2 type
public $fk_remise_except ; // Link to line into llx_remise_except
2018-10-09 15:38:42 +02:00
public $rang = 0 ;
2018-07-06 08:07:38 +02:00
2018-10-09 15:38:42 +02:00
public $fk_fournprice ;
public $pa_ht ;
public $marge_tx ;
public $marque_tx ;
2018-07-06 08:07:38 +02:00
2019-11-07 14:40:26 +01:00
public $remise_percent ;
2019-11-08 10:53:31 +01:00
public $special_code ; // Liste d'options non cumulabels:
2018-07-06 08:07:38 +02:00
// 1: frais de port
// 2: ecotaxe
// 3: ??
2018-10-09 15:38:42 +02:00
public $origin ;
public $origin_id ;
2018-07-06 08:07:38 +02:00
2018-10-09 15:38:42 +02:00
public $fk_code_ventilation = 0 ;
2018-07-06 08:07:38 +02:00
2018-10-09 15:38:42 +02:00
public $date_start ;
public $date_end ;
2018-07-06 08:07:38 +02:00
2018-10-09 15:38:42 +02:00
public $skip_update_total ; // Skip update price total for special lines
2018-07-06 08:07:38 +02:00
/**
* @ var int Situation advance percentage
*/
public $situation_percent ;
/**
* @ var int Previous situation line id reference
*/
public $fk_prev_id ;
// Multicurrency
2018-10-09 15:38:42 +02:00
public $fk_multicurrency ;
public $multicurrency_code ;
public $multicurrency_subprice ;
public $multicurrency_total_ht ;
public $multicurrency_total_tva ;
public $multicurrency_total_ttc ;
2018-07-06 08:07:38 +02:00
/**
* Load invoice line from database
*
* @ param int $rowid id of invoice line to get
* @ return int < 0 if KO , > 0 if OK
*/
2020-09-08 21:27:28 +02:00
public function fetch ( $rowid )
2018-07-06 08:07:38 +02:00
{
$sql = 'SELECT fd.rowid, fd.fk_facture, fd.fk_parent_line, fd.fk_product, fd.product_type, fd.label as custom_label, fd.description, fd.price, fd.qty, fd.vat_src_code, fd.tva_tx,' ;
2020-09-04 19:32:42 +02:00
$sql .= ' fd.localtax1_tx, fd. localtax2_tx, fd.remise, fd.remise_percent, fd.fk_remise_except, fd.subprice, fd.ref_ext,' ;
2019-11-08 10:53:31 +01:00
$sql .= ' fd.date_start as date_start, fd.date_end as date_end, fd.fk_product_fournisseur_price as fk_fournprice, fd.buy_price_ht as pa_ht,' ;
$sql .= ' fd.info_bits, fd.special_code, fd.total_ht, fd.total_tva, fd.total_ttc, fd.total_localtax1, fd.total_localtax2, fd.rang,' ;
$sql .= ' fd.fk_code_ventilation,' ;
$sql .= ' fd.fk_unit, fd.fk_user_author, fd.fk_user_modif,' ;
$sql .= ' fd.situation_percent, fd.fk_prev_id,' ;
$sql .= ' fd.multicurrency_subprice,' ;
$sql .= ' fd.multicurrency_total_ht,' ;
$sql .= ' fd.multicurrency_total_tva,' ;
$sql .= ' fd.multicurrency_total_ttc,' ;
2020-10-12 19:33:00 +02:00
$sql .= ' p.ref as product_ref, p.label as product_label, p.description as product_desc' ;
2019-11-08 10:53:31 +01:00
$sql .= ' FROM ' . MAIN_DB_PREFIX . 'facturedet as fd' ;
$sql .= ' LEFT JOIN ' . MAIN_DB_PREFIX . 'product as p ON fd.fk_product = p.rowid' ;
2021-03-29 15:32:09 +02:00
$sql .= ' WHERE fd.rowid = ' . (( int ) $rowid );
2018-07-06 08:07:38 +02:00
$result = $this -> db -> query ( $sql );
2021-02-23 21:09:01 +01:00
if ( $result ) {
2018-07-06 08:07:38 +02:00
$objp = $this -> db -> fetch_object ( $result );
2019-11-08 10:53:31 +01:00
$this -> rowid = $objp -> rowid ;
$this -> id = $objp -> rowid ;
$this -> fk_facture = $objp -> fk_facture ;
$this -> fk_parent_line = $objp -> fk_parent_line ;
2018-07-06 08:07:38 +02:00
$this -> label = $objp -> custom_label ;
$this -> desc = $objp -> description ;
2019-11-08 10:53:31 +01:00
$this -> qty = $objp -> qty ;
$this -> subprice = $objp -> subprice ;
2020-09-04 19:32:42 +02:00
$this -> ref_ext = $objp -> ref_ext ;
2019-11-08 10:53:31 +01:00
$this -> vat_src_code = $objp -> vat_src_code ;
$this -> tva_tx = $objp -> tva_tx ;
2018-07-06 08:07:38 +02:00
$this -> localtax1_tx = $objp -> localtax1_tx ;
$this -> localtax2_tx = $objp -> localtax2_tx ;
2019-11-08 10:53:31 +01:00
$this -> remise_percent = $objp -> remise_percent ;
$this -> fk_remise_except = $objp -> fk_remise_except ;
2018-07-06 08:07:38 +02:00
$this -> fk_product = $objp -> fk_product ;
2019-11-08 10:53:31 +01:00
$this -> product_type = $objp -> product_type ;
2018-07-06 08:07:38 +02:00
$this -> date_start = $this -> db -> jdate ( $objp -> date_start );
$this -> date_end = $this -> db -> jdate ( $objp -> date_end );
$this -> info_bits = $objp -> info_bits ;
2019-11-08 10:53:31 +01:00
$this -> tva_npr = ( $objp -> info_bits & 1 == 1 ) ? 1 : 0 ;
$this -> special_code = $objp -> special_code ;
2018-07-06 08:07:38 +02:00
$this -> total_ht = $objp -> total_ht ;
$this -> total_tva = $objp -> total_tva ;
$this -> total_localtax1 = $objp -> total_localtax1 ;
$this -> total_localtax2 = $objp -> total_localtax2 ;
$this -> total_ttc = $objp -> total_ttc ;
2019-11-08 10:53:31 +01:00
$this -> fk_code_ventilation = $objp -> fk_code_ventilation ;
2018-07-06 08:07:38 +02:00
$this -> rang = $objp -> rang ;
2019-11-08 10:53:31 +01:00
$this -> fk_fournprice = $objp -> fk_fournprice ;
2018-07-06 08:07:38 +02:00
$marginInfos = getMarginInfos ( $objp -> subprice , $objp -> remise_percent , $objp -> tva_tx , $objp -> localtax1_tx , $objp -> localtax2_tx , $this -> fk_fournprice , $objp -> pa_ht );
$this -> pa_ht = $marginInfos [ 0 ];
$this -> marge_tx = $marginInfos [ 1 ];
$this -> marque_tx = $marginInfos [ 2 ];
2019-11-08 10:53:31 +01:00
$this -> ref = $objp -> product_ref ; // deprecated
2020-10-12 19:33:00 +02:00
2020-10-31 14:32:18 +01:00
$this -> product_ref = $objp -> product_ref ;
2020-10-12 19:33:00 +02:00
$this -> product_label = $objp -> product_label ;
2018-07-06 08:07:38 +02:00
$this -> product_desc = $objp -> product_desc ;
2020-10-12 19:33:00 +02:00
2020-10-31 14:32:18 +01:00
$this -> fk_unit = $objp -> fk_unit ;
2018-07-06 08:07:38 +02:00
$this -> fk_user_modif = $objp -> fk_user_modif ;
2019-11-08 10:53:31 +01:00
$this -> fk_user_author = $objp -> fk_user_author ;
2018-07-06 08:07:38 +02:00
$this -> situation_percent = $objp -> situation_percent ;
$this -> fk_prev_id = $objp -> fk_prev_id ;
$this -> multicurrency_subprice = $objp -> multicurrency_subprice ;
$this -> multicurrency_total_ht = $objp -> multicurrency_total_ht ;
2019-11-08 10:53:31 +01:00
$this -> multicurrency_total_tva = $objp -> multicurrency_total_tva ;
$this -> multicurrency_total_ttc = $objp -> multicurrency_total_ttc ;
2018-07-06 08:07:38 +02:00
$this -> db -> free ( $result );
return 1 ;
2020-05-21 15:05:19 +02:00
} else {
2020-09-08 21:27:28 +02:00
$this -> error = $this -> db -> lasterror ();
2018-07-06 08:07:38 +02:00
return - 1 ;
}
}
/**
* Insert line into database
*
* @ param int $notrigger 1 no triggers
* @ param int $noerrorifdiscountalreadylinked 1 = Do not make error if lines is linked to a discount and discount already linked to another
* @ return int < 0 if KO , > 0 if OK
*/
2020-09-08 21:27:28 +02:00
public function insert ( $notrigger = 0 , $noerrorifdiscountalreadylinked = 0 )
2018-07-06 08:07:38 +02:00
{
2019-11-08 10:53:31 +01:00
global $langs , $user , $conf ;
2018-07-06 08:07:38 +02:00
2019-11-08 10:53:31 +01:00
$error = 0 ;
2018-07-05 11:52:41 +02:00
2020-09-08 21:27:28 +02:00
$pa_ht_isemptystring = ( empty ( $this -> pa_ht ) && $this -> pa_ht == '' ); // If true, we can use a default value. If this->pa_ht = '0', we must use '0'.
2016-06-30 17:28:13 +02:00
2020-09-08 21:27:28 +02:00
dol_syslog ( get_class ( $this ) . " ::insert rang= " . $this -> rang , LOG_DEBUG );
2018-07-06 08:07:38 +02:00
// Clean parameters
2019-11-08 10:53:31 +01:00
$this -> desc = trim ( $this -> desc );
2021-02-23 21:09:01 +01:00
if ( empty ( $this -> tva_tx )) {
$this -> tva_tx = 0 ;
}
if ( empty ( $this -> localtax1_tx )) {
$this -> localtax1_tx = 0 ;
}
if ( empty ( $this -> localtax2_tx )) {
$this -> localtax2_tx = 0 ;
}
if ( empty ( $this -> localtax1_type )) {
$this -> localtax1_type = 0 ;
}
if ( empty ( $this -> localtax2_type )) {
$this -> localtax2_type = 0 ;
}
if ( empty ( $this -> total_localtax1 )) {
$this -> total_localtax1 = 0 ;
}
if ( empty ( $this -> total_localtax2 )) {
$this -> total_localtax2 = 0 ;
}
if ( empty ( $this -> rang )) {
$this -> rang = 0 ;
}
if ( empty ( $this -> remise_percent )) {
$this -> remise_percent = 0 ;
}
if ( empty ( $this -> info_bits )) {
$this -> info_bits = 0 ;
}
if ( empty ( $this -> subprice )) {
$this -> subprice = 0 ;
}
if ( empty ( $this -> ref_ext )) {
$this -> ref_ext = '' ;
}
if ( empty ( $this -> special_code )) {
$this -> special_code = 0 ;
}
if ( empty ( $this -> fk_parent_line )) {
$this -> fk_parent_line = 0 ;
}
if ( empty ( $this -> fk_prev_id )) {
$this -> fk_prev_id = 0 ;
}
if ( ! isset ( $this -> situation_percent ) || $this -> situation_percent > 100 || ( string ) $this -> situation_percent == '' ) {
$this -> situation_percent = 100 ;
}
if ( empty ( $this -> pa_ht )) {
$this -> pa_ht = 0 ;
}
if ( empty ( $this -> multicurrency_subprice )) {
$this -> multicurrency_subprice = 0 ;
}
if ( empty ( $this -> multicurrency_total_ht )) {
$this -> multicurrency_total_ht = 0 ;
}
if ( empty ( $this -> multicurrency_total_tva )) {
$this -> multicurrency_total_tva = 0 ;
}
if ( empty ( $this -> multicurrency_total_ttc )) {
$this -> multicurrency_total_ttc = 0 ;
}
2018-07-06 08:07:38 +02:00
// if buy price not defined, define buyprice as configured in margin admin
2021-02-23 21:09:01 +01:00
if ( $this -> pa_ht == 0 && $pa_ht_isemptystring ) {
if (( $result = $this -> defineBuyPrice ( $this -> subprice , $this -> remise_percent , $this -> fk_product )) < 0 ) {
2018-07-06 08:07:38 +02:00
return $result ;
2020-05-21 15:05:19 +02:00
} else {
2018-07-06 08:07:38 +02:00
$this -> pa_ht = $result ;
}
}
// Check parameters
2021-02-23 21:09:01 +01:00
if ( $this -> product_type < 0 ) {
2019-11-08 10:53:31 +01:00
$this -> error = 'ErrorProductTypeMustBe0orMore' ;
2018-07-06 08:07:38 +02:00
return - 1 ;
}
2021-07-04 21:02:02 +02:00
if ( ! empty ( $this -> fk_product ) && $this -> fk_product > 0 ) {
2018-07-06 08:07:38 +02:00
// Check product exists
2019-11-08 10:53:31 +01:00
$result = Product :: isExistingObject ( 'product' , $this -> fk_product );
2021-02-23 21:09:01 +01:00
if ( $result <= 0 ) {
2019-11-08 10:53:31 +01:00
$this -> error = 'ErrorProductIdDoesNotExists' ;
2019-05-27 16:40:06 +02:00
dol_syslog ( get_class ( $this ) . " ::insert Error " . $this -> error , LOG_ERR );
2018-07-06 08:07:38 +02:00
return - 1 ;
}
}
$this -> db -> begin ();
2021-11-15 04:26:14 +01:00
// Update line in database
2018-07-06 08:07:38 +02:00
$sql = 'INSERT INTO ' . MAIN_DB_PREFIX . 'facturedet' ;
2019-11-08 10:53:31 +01:00
$sql .= ' (fk_facture, fk_parent_line, label, description, qty,' ;
$sql .= ' vat_src_code, tva_tx, localtax1_tx, localtax2_tx, localtax1_type, localtax2_type,' ;
2020-09-04 19:32:42 +02:00
$sql .= ' fk_product, product_type, remise_percent, subprice, ref_ext, fk_remise_except,' ;
2019-11-08 10:53:31 +01:00
$sql .= ' date_start, date_end, fk_code_ventilation, ' ;
$sql .= ' rang, special_code, fk_product_fournisseur_price, buy_price_ht,' ;
$sql .= ' info_bits, total_ht, total_tva, total_ttc, total_localtax1, total_localtax2,' ;
$sql .= ' situation_percent, fk_prev_id,' ;
$sql .= ' fk_unit, fk_user_author, fk_user_modif,' ;
$sql .= ' fk_multicurrency, multicurrency_code, multicurrency_subprice, multicurrency_total_ht, multicurrency_total_tva, multicurrency_total_ttc' ;
$sql .= ')' ;
$sql .= " VALUES ( " . $this -> fk_facture . " , " ;
$sql .= " " . ( $this -> fk_parent_line > 0 ? $this -> fk_parent_line : " null " ) . " , " ;
$sql .= " " . ( ! empty ( $this -> label ) ? " ' " . $this -> db -> escape ( $this -> label ) . " ' " : " null " ) . " , " ;
$sql .= " ' " . $this -> db -> escape ( $this -> desc ) . " ', " ;
$sql .= " " . price2num ( $this -> qty ) . " , " ;
2020-09-08 21:27:28 +02:00
$sql .= " " . ( empty ( $this -> vat_src_code ) ? " '' " : " ' " . $this -> db -> escape ( $this -> vat_src_code ) . " ' " ) . " , " ;
2019-11-08 10:53:31 +01:00
$sql .= " " . price2num ( $this -> tva_tx ) . " , " ;
$sql .= " " . price2num ( $this -> localtax1_tx ) . " , " ;
$sql .= " " . price2num ( $this -> localtax2_tx ) . " , " ;
$sql .= " ' " . $this -> db -> escape ( $this -> localtax1_type ) . " ', " ;
$sql .= " ' " . $this -> db -> escape ( $this -> localtax2_type ) . " ', " ;
2021-07-04 21:02:02 +02:00
$sql .= ' ' . (( ! empty ( $this -> fk_product ) && $this -> fk_product > 0 ) ? $this -> fk_product : " null " ) . ',' ;
2019-11-08 10:53:31 +01:00
$sql .= " " . (( int ) $this -> product_type ) . " , " ;
$sql .= " " . price2num ( $this -> remise_percent ) . " , " ;
$sql .= " " . price2num ( $this -> subprice ) . " , " ;
2020-09-04 19:32:42 +02:00
$sql .= " ' " . $this -> db -> escape ( $this -> ref_ext ) . " ', " ;
2019-11-08 10:53:31 +01:00
$sql .= ' ' . ( ! empty ( $this -> fk_remise_except ) ? $this -> fk_remise_except : " null " ) . ',' ;
$sql .= " " . ( ! empty ( $this -> date_start ) ? " ' " . $this -> db -> idate ( $this -> date_start ) . " ' " : " null " ) . " , " ;
$sql .= " " . ( ! empty ( $this -> date_end ) ? " ' " . $this -> db -> idate ( $this -> date_end ) . " ' " : " null " ) . " , " ;
2021-08-27 23:36:06 +02:00
$sql .= ' ' . (( int ) $this -> fk_code_ventilation ) . ',' ;
$sql .= ' ' . (( int ) $this -> rang ) . ',' ;
$sql .= ' ' . (( int ) $this -> special_code ) . ',' ;
2019-11-08 10:53:31 +01:00
$sql .= ' ' . ( ! empty ( $this -> fk_fournprice ) ? $this -> fk_fournprice : " null " ) . ',' ;
$sql .= ' ' . price2num ( $this -> pa_ht ) . ',' ;
$sql .= " ' " . $this -> db -> escape ( $this -> info_bits ) . " ', " ;
$sql .= " " . price2num ( $this -> total_ht ) . " , " ;
$sql .= " " . price2num ( $this -> total_tva ) . " , " ;
$sql .= " " . price2num ( $this -> total_ttc ) . " , " ;
$sql .= " " . price2num ( $this -> total_localtax1 ) . " , " ;
$sql .= " " . price2num ( $this -> total_localtax2 );
2021-08-27 23:36:06 +02:00
$sql .= " , " . (( float ) $this -> situation_percent );
2019-11-08 10:53:31 +01:00
$sql .= " , " . ( ! empty ( $this -> fk_prev_id ) ? $this -> fk_prev_id : " null " );
$sql .= " , " . ( ! $this -> fk_unit ? 'NULL' : $this -> fk_unit );
2021-08-27 23:36:06 +02:00
$sql .= " , " . (( int ) $user -> id );
$sql .= " , " . (( int ) $user -> id );
2019-11-08 10:53:31 +01:00
$sql .= " , " . ( int ) $this -> fk_multicurrency ;
$sql .= " , ' " . $this -> db -> escape ( $this -> multicurrency_code ) . " ' " ;
$sql .= " , " . price2num ( $this -> multicurrency_subprice );
$sql .= " , " . price2num ( $this -> multicurrency_total_ht );
$sql .= " , " . price2num ( $this -> multicurrency_total_tva );
$sql .= " , " . price2num ( $this -> multicurrency_total_ttc );
$sql .= ')' ;
2018-07-06 08:07:38 +02:00
dol_syslog ( get_class ( $this ) . " ::insert " , LOG_DEBUG );
2019-11-08 10:53:31 +01:00
$resql = $this -> db -> query ( $sql );
2021-02-23 21:09:01 +01:00
if ( $resql ) {
2019-11-08 10:53:31 +01:00
$this -> id = $this -> db -> last_insert_id ( MAIN_DB_PREFIX . 'facturedet' );
$this -> rowid = $this -> id ; // For backward compatibility
2018-07-06 08:07:38 +02:00
2021-02-23 21:09:01 +01:00
if ( ! $error ) {
2020-09-08 21:27:28 +02:00
$result = $this -> insertExtraFields ();
2021-02-23 21:09:01 +01:00
if ( $result < 0 ) {
2020-09-08 21:27:28 +02:00
$error ++ ;
}
}
2013-06-16 21:31:21 +02:00
2021-11-15 04:26:14 +01:00
// If fk_remise_except is defined, the discount is linked to the invoice
// which flags it as "consumed".
2021-02-23 21:09:01 +01:00
if ( $this -> fk_remise_except ) {
2019-11-08 10:53:31 +01:00
$discount = new DiscountAbsolute ( $this -> db );
$result = $discount -> fetch ( $this -> fk_remise_except );
2021-02-23 21:09:01 +01:00
if ( $result >= 0 ) {
2018-07-06 08:07:38 +02:00
// Check if discount was found
2021-02-23 21:09:01 +01:00
if ( $result > 0 ) {
2020-09-08 21:27:28 +02:00
// Check if discount not already affected to another invoice
2021-02-23 21:09:01 +01:00
if ( $discount -> fk_facture_line > 0 ) {
if ( empty ( $noerrorifdiscountalreadylinked )) {
2020-09-08 21:27:28 +02:00
$this -> error = $langs -> trans ( " ErrorDiscountAlreadyUsed " , $discount -> id );
dol_syslog ( get_class ( $this ) . " ::insert Error " . $this -> error , LOG_ERR );
$this -> db -> rollback ();
return - 3 ;
}
2020-05-21 15:05:19 +02:00
} else {
2019-11-08 10:53:31 +01:00
$result = $discount -> link_to_invoice ( $this -> rowid , 0 );
2021-02-23 21:09:01 +01:00
if ( $result < 0 ) {
2019-11-08 10:53:31 +01:00
$this -> error = $discount -> error ;
2018-07-06 08:07:38 +02:00
dol_syslog ( get_class ( $this ) . " ::insert Error " . $this -> error , LOG_ERR );
$this -> db -> rollback ();
return - 3 ;
}
}
2020-05-21 15:05:19 +02:00
} else {
2019-11-08 10:53:31 +01:00
$this -> error = $langs -> trans ( " ErrorADiscountThatHasBeenRemovedIsIncluded " );
2018-07-06 08:07:38 +02:00
dol_syslog ( get_class ( $this ) . " ::insert Error " . $this -> error , LOG_ERR );
$this -> db -> rollback ();
return - 3 ;
}
2020-05-21 15:05:19 +02:00
} else {
2019-11-08 10:53:31 +01:00
$this -> error = $discount -> error ;
2018-07-06 08:07:38 +02:00
dol_syslog ( get_class ( $this ) . " ::insert Error " . $this -> error , LOG_ERR );
$this -> db -> rollback ();
return - 3 ;
}
}
2021-02-23 21:09:01 +01:00
if ( ! $notrigger ) {
2020-09-08 21:27:28 +02:00
// Call trigger
$result = $this -> call_trigger ( 'LINEBILL_INSERT' , $user );
2021-02-23 21:09:01 +01:00
if ( $result < 0 ) {
2018-07-06 08:07:38 +02:00
$this -> db -> rollback ();
return - 2 ;
}
2020-09-08 21:27:28 +02:00
// End call triggers
2018-07-06 08:07:38 +02:00
}
$this -> db -> commit ();
return $this -> id ;
2020-05-21 15:05:19 +02:00
} else {
2019-11-08 10:53:31 +01:00
$this -> error = $this -> db -> lasterror ();
2018-07-06 08:07:38 +02:00
$this -> db -> rollback ();
return - 2 ;
}
}
/**
* Update line into database
*
* @ param User $user User object
* @ param int $notrigger Disable triggers
* @ return int < 0 if KO , > 0 if OK
*/
2020-09-08 21:27:28 +02:00
public function update ( $user = '' , $notrigger = 0 )
2018-07-06 08:07:38 +02:00
{
2019-11-08 10:53:31 +01:00
global $user , $conf ;
2018-07-06 08:07:38 +02:00
2019-11-08 10:53:31 +01:00
$error = 0 ;
2018-07-06 08:07:38 +02:00
$pa_ht_isemptystring = ( empty ( $this -> pa_ht ) && $this -> pa_ht == '' ); // If true, we can use a default value. If this->pa_ht = '0', we must use '0'.
// Clean parameters
2019-11-08 10:53:31 +01:00
$this -> desc = trim ( $this -> desc );
2021-02-23 21:09:01 +01:00
if ( empty ( $this -> ref_ext )) {
$this -> ref_ext = '' ;
}
if ( empty ( $this -> tva_tx )) {
$this -> tva_tx = 0 ;
}
if ( empty ( $this -> localtax1_tx )) {
$this -> localtax1_tx = 0 ;
}
if ( empty ( $this -> localtax2_tx )) {
$this -> localtax2_tx = 0 ;
}
if ( empty ( $this -> localtax1_type )) {
$this -> localtax1_type = 0 ;
}
if ( empty ( $this -> localtax2_type )) {
$this -> localtax2_type = 0 ;
}
if ( empty ( $this -> total_localtax1 )) {
$this -> total_localtax1 = 0 ;
}
if ( empty ( $this -> total_localtax2 )) {
$this -> total_localtax2 = 0 ;
}
if ( empty ( $this -> remise_percent )) {
$this -> remise_percent = 0 ;
}
if ( empty ( $this -> info_bits )) {
$this -> info_bits = 0 ;
}
if ( empty ( $this -> special_code )) {
$this -> special_code = 0 ;
}
if ( empty ( $this -> product_type )) {
$this -> product_type = 0 ;
}
if ( empty ( $this -> fk_parent_line )) {
$this -> fk_parent_line = 0 ;
}
if ( ! isset ( $this -> situation_percent ) || $this -> situation_percent > 100 || ( string ) $this -> situation_percent == '' ) {
$this -> situation_percent = 100 ;
}
if ( empty ( $this -> pa_ht )) {
$this -> pa_ht = 0 ;
}
if ( empty ( $this -> multicurrency_subprice )) {
$this -> multicurrency_subprice = 0 ;
}
if ( empty ( $this -> multicurrency_total_ht )) {
$this -> multicurrency_total_ht = 0 ;
}
if ( empty ( $this -> multicurrency_total_tva )) {
$this -> multicurrency_total_tva = 0 ;
}
if ( empty ( $this -> multicurrency_total_ttc )) {
$this -> multicurrency_total_ttc = 0 ;
}
2018-07-06 08:07:38 +02:00
// Check parameters
2021-02-23 21:09:01 +01:00
if ( $this -> product_type < 0 ) {
return - 1 ;
}
2018-07-06 08:07:38 +02:00
2021-03-24 21:49:45 +01:00
// if buy price not provided, define buyprice as configured in margin admin
2021-02-23 21:09:01 +01:00
if ( $this -> pa_ht == 0 && $pa_ht_isemptystring ) {
2021-03-24 21:49:45 +01:00
// We call defineBuyPrice only if data was not provided (if input was '0', we will not go here and value will remaine '0')
$result = $this -> defineBuyPrice ( $this -> subprice , $this -> remise_percent , $this -> fk_product );
if ( $result < 0 ) {
2018-07-06 08:07:38 +02:00
return $result ;
2020-05-21 15:05:19 +02:00
} else {
2018-07-06 08:07:38 +02:00
$this -> pa_ht = $result ;
}
}
$this -> db -> begin ();
2018-07-05 11:52:41 +02:00
2020-09-14 04:30:04 +02:00
// Update line in database
$sql = " UPDATE " . MAIN_DB_PREFIX . " facturedet SET " ;
$sql .= " description=' " . $this -> db -> escape ( $this -> desc ) . " ' " ;
$sql .= " , ref_ext=' " . $this -> db -> escape ( $this -> ref_ext ) . " ' " ;
$sql .= " , label= " . ( ! empty ( $this -> label ) ? " ' " . $this -> db -> escape ( $this -> label ) . " ' " : " null " );
2021-12-19 20:43:24 +01:00
$sql .= " , subprice= " . price2num ( $this -> subprice );
$sql .= " , remise_percent= " . price2num ( $this -> remise_percent );
2021-02-23 21:09:01 +01:00
if ( $this -> fk_remise_except ) {
$sql .= " , fk_remise_except= " . $this -> fk_remise_except ;
} else {
$sql .= " , fk_remise_except=null " ;
}
2019-11-08 10:53:31 +01:00
$sql .= " , vat_src_code = ' " . ( empty ( $this -> vat_src_code ) ? '' : $this -> db -> escape ( $this -> vat_src_code )) . " ' " ;
2021-12-19 20:43:24 +01:00
$sql .= " , tva_tx= " . price2num ( $this -> tva_tx );
$sql .= " , localtax1_tx= " . price2num ( $this -> localtax1_tx );
$sql .= " , localtax2_tx= " . price2num ( $this -> localtax2_tx );
2019-11-08 10:53:31 +01:00
$sql .= " , localtax1_type=' " . $this -> db -> escape ( $this -> localtax1_type ) . " ' " ;
$sql .= " , localtax2_type=' " . $this -> db -> escape ( $this -> localtax2_type ) . " ' " ;
2020-09-08 21:27:28 +02:00
$sql .= " , qty= " . price2num ( $this -> qty );
$sql .= " , date_start= " . ( ! empty ( $this -> date_start ) ? " ' " . $this -> db -> idate ( $this -> date_start ) . " ' " : " null " );
$sql .= " , date_end= " . ( ! empty ( $this -> date_end ) ? " ' " . $this -> db -> idate ( $this -> date_end ) . " ' " : " null " );
$sql .= " , product_type= " . $this -> product_type ;
$sql .= " , info_bits=' " . $this -> db -> escape ( $this -> info_bits ) . " ' " ;
$sql .= " , special_code=' " . $this -> db -> escape ( $this -> special_code ) . " ' " ;
2021-02-23 21:09:01 +01:00
if ( empty ( $this -> skip_update_total )) {
2020-09-08 21:27:28 +02:00
$sql .= " , total_ht= " . price2num ( $this -> total_ht );
$sql .= " , total_tva= " . price2num ( $this -> total_tva );
$sql .= " , total_ttc= " . price2num ( $this -> total_ttc );
$sql .= " , total_localtax1= " . price2num ( $this -> total_localtax1 );
$sql .= " , total_localtax2= " . price2num ( $this -> total_localtax2 );
}
2019-11-08 10:53:31 +01:00
$sql .= " , fk_product_fournisseur_price= " . ( ! empty ( $this -> fk_fournprice ) ? " ' " . $this -> db -> escape ( $this -> fk_fournprice ) . " ' " : " null " );
2021-06-14 15:37:02 +02:00
$sql .= " , buy_price_ht= " . (( $this -> pa_ht || $this -> pa_ht === 0 || $this -> pa_ht === '0' ) ? price2num ( $this -> pa_ht ) : " null " ); // $this->pa_ht should always be defined (set to 0 or to sell price depending on option)
2019-11-08 10:53:31 +01:00
$sql .= " , fk_parent_line= " . ( $this -> fk_parent_line > 0 ? $this -> fk_parent_line : " null " );
2021-02-23 21:09:01 +01:00
if ( ! empty ( $this -> rang )) {
2021-06-09 15:36:47 +02:00
$sql .= " , rang= " . (( int ) $this -> rang );
2021-02-23 21:09:01 +01:00
}
2021-12-19 20:43:24 +01:00
$sql .= " , situation_percent = " . (( float ) $this -> situation_percent );
$sql .= " , fk_unit = " . ( ! $this -> fk_unit ? 'NULL' : $this -> fk_unit );
$sql .= " , fk_user_modif = " . (( int ) $user -> id );
2018-07-06 08:07:38 +02:00
// Multicurrency
2021-12-19 20:43:24 +01:00
$sql .= " , multicurrency_subprice= " . price2num ( $this -> multicurrency_subprice );
$sql .= " , multicurrency_total_ht= " . price2num ( $this -> multicurrency_total_ht );
$sql .= " , multicurrency_total_tva= " . price2num ( $this -> multicurrency_total_tva );
$sql .= " , multicurrency_total_ttc= " . price2num ( $this -> multicurrency_total_ttc );
2018-07-06 08:07:38 +02:00
2021-06-09 15:36:47 +02:00
$sql .= " WHERE rowid = " . (( int ) $this -> rowid );
2018-07-06 08:07:38 +02:00
dol_syslog ( get_class ( $this ) . " ::update " , LOG_DEBUG );
2019-11-08 10:53:31 +01:00
$resql = $this -> db -> query ( $sql );
2021-02-23 21:09:01 +01:00
if ( $resql ) {
if ( ! $error ) {
2020-09-08 21:27:28 +02:00
$this -> id = $this -> rowid ;
$result = $this -> insertExtraFields ();
2021-02-23 21:09:01 +01:00
if ( $result < 0 ) {
2020-09-08 21:27:28 +02:00
$error ++ ;
}
}
2018-07-06 08:07:38 +02:00
2021-02-23 21:09:01 +01:00
if ( ! $error && ! $notrigger ) {
2020-09-08 21:27:28 +02:00
// Call trigger
2022-04-02 10:31:58 +02:00
$result = $this -> call_trigger ( 'LINEBILL_MODIFY' , $user );
2021-02-23 21:09:01 +01:00
if ( $result < 0 ) {
2018-07-06 08:07:38 +02:00
$this -> db -> rollback ();
return - 2 ;
}
2020-09-08 21:27:28 +02:00
// End call triggers
2018-07-06 08:07:38 +02:00
}
$this -> db -> commit ();
return 1 ;
2020-05-21 15:05:19 +02:00
} else {
2019-11-08 10:53:31 +01:00
$this -> error = $this -> db -> error ();
2018-07-06 08:07:38 +02:00
$this -> db -> rollback ();
return - 2 ;
}
}
/**
2022-01-13 19:19:36 +01:00
* Delete line in database
2020-09-08 21:27:28 +02:00
*
2022-01-13 19:19:36 +01:00
* @ param User $tmpuser User that deletes
* @ param bool $notrigger false = launch triggers after , true = disable triggers
* @ return int < 0 if KO , > 0 if OK
2018-07-06 08:07:38 +02:00
*/
2022-01-13 19:19:36 +01:00
public function delete ( $tmpuser = null , $notrigger = false )
2018-07-06 08:07:38 +02:00
{
global $user ;
$this -> db -> begin ();
// Call trigger
2022-01-13 19:19:36 +01:00
if ( empty ( $notrigger )) {
$result = $this -> call_trigger ( 'LINEBILL_DELETE' , $user );
if ( $result < 0 ) {
$this -> db -> rollback ();
return - 1 ;
}
2018-07-06 08:07:38 +02:00
}
// End call triggers
2020-09-08 21:27:28 +02:00
// extrafields
$result = $this -> deleteExtraFields ();
2021-02-23 21:09:01 +01:00
if ( $result < 0 ) {
2020-09-08 21:27:28 +02:00
$this -> db -> rollback ();
return - 1 ;
}
2018-07-06 08:07:38 +02:00
2021-08-23 19:33:24 +02:00
$sql = " DELETE FROM " . MAIN_DB_PREFIX . " facturedet WHERE rowid = " . (( int ) $this -> rowid );
2022-01-13 19:19:36 +01:00
2021-02-23 21:09:01 +01:00
if ( $this -> db -> query ( $sql )) {
2018-07-06 08:07:38 +02:00
$this -> db -> commit ();
return 1 ;
2020-05-21 15:05:19 +02:00
} else {
2019-11-08 10:53:31 +01:00
$this -> error = $this -> db -> error () . " sql= " . $sql ;
2018-07-06 08:07:38 +02:00
$this -> db -> rollback ();
return - 1 ;
}
}
2020-09-08 21:27:28 +02:00
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2018-07-06 08:07:38 +02:00
/**
2020-09-08 21:27:28 +02:00
* Update DB line fields total_xxx
2018-09-03 17:05:44 +02:00
* Used by migration
2018-07-06 08:07:38 +02:00
*
* @ return int < 0 if KO , > 0 if OK
*/
2020-09-08 21:27:28 +02:00
public function update_total ()
2018-07-06 08:07:38 +02:00
{
2020-09-08 21:27:28 +02:00
// phpcs:enable
2018-07-06 08:07:38 +02:00
$this -> db -> begin ();
dol_syslog ( get_class ( $this ) . " ::update_total " , LOG_DEBUG );
// Clean parameters
2021-02-23 21:09:01 +01:00
if ( empty ( $this -> total_localtax1 )) {
$this -> total_localtax1 = 0 ;
}
if ( empty ( $this -> total_localtax2 )) {
$this -> total_localtax2 = 0 ;
}
2018-07-06 08:07:38 +02:00
2021-11-15 04:26:14 +01:00
// Update line in database
2018-07-06 08:07:38 +02:00
$sql = " UPDATE " . MAIN_DB_PREFIX . " facturedet SET " ;
2019-11-08 10:53:31 +01:00
$sql .= " total_ht= " . price2num ( $this -> total_ht ) . " " ;
$sql .= " ,total_tva= " . price2num ( $this -> total_tva ) . " " ;
$sql .= " ,total_localtax1= " . price2num ( $this -> total_localtax1 ) . " " ;
$sql .= " ,total_localtax2= " . price2num ( $this -> total_localtax2 ) . " " ;
$sql .= " ,total_ttc= " . price2num ( $this -> total_ttc ) . " " ;
2021-08-23 19:33:24 +02:00
$sql .= " WHERE rowid = " . (( int ) $this -> rowid );
2018-07-06 08:07:38 +02:00
dol_syslog ( get_class ( $this ) . " ::update_total " , LOG_DEBUG );
2019-11-08 10:53:31 +01:00
$resql = $this -> db -> query ( $sql );
2021-02-23 21:09:01 +01:00
if ( $resql ) {
2018-07-06 08:07:38 +02:00
$this -> db -> commit ();
return 1 ;
2020-05-21 15:05:19 +02:00
} else {
2019-11-08 10:53:31 +01:00
$this -> error = $this -> db -> error ();
2018-07-06 08:07:38 +02:00
$this -> db -> rollback ();
return - 2 ;
}
}
2020-09-08 21:27:28 +02:00
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2018-07-06 08:07:38 +02:00
/**
* Returns situation_percent of the previous line .
* Warning : If invoice is a replacement invoice , this -> fk_prev_id is id of the replaced line .
*
* @ param int $invoiceid Invoice id
2018-09-27 09:25:37 +02:00
* @ param bool $include_credit_note Include credit note or not
2018-07-06 08:07:38 +02:00
* @ return int >= 0
*/
2020-09-08 21:27:28 +02:00
public function get_prev_progress ( $invoiceid , $include_credit_note = true )
2018-07-06 08:07:38 +02:00
{
2020-09-08 21:27:28 +02:00
// phpcs:enable
2019-09-03 13:43:44 +02:00
global $invoicecache ;
2018-07-06 08:07:38 +02:00
if ( is_null ( $this -> fk_prev_id ) || empty ( $this -> fk_prev_id ) || $this -> fk_prev_id == " " ) {
return 0 ;
} else {
2020-09-08 21:27:28 +02:00
// If invoice is not a situation invoice, this->fk_prev_id is used for something else
2019-09-03 13:43:44 +02:00
if ( ! isset ( $invoicecache [ $invoiceid ])) {
2019-11-08 10:53:31 +01:00
$invoicecache [ $invoiceid ] = new Facture ( $this -> db );
2019-09-03 13:43:44 +02:00
$invoicecache [ $invoiceid ] -> fetch ( $invoiceid );
}
2021-02-23 21:09:01 +01:00
if ( $invoicecache [ $invoiceid ] -> type != Facture :: TYPE_SITUATION ) {
return 0 ;
}
2018-07-06 08:07:38 +02:00
2021-09-30 15:59:47 +02:00
$sql = " SELECT situation_percent FROM " . MAIN_DB_PREFIX . " facturedet WHERE rowid = " . (( int ) $this -> fk_prev_id );
2018-07-06 08:07:38 +02:00
$resql = $this -> db -> query ( $sql );
2022-05-18 23:40:42 +02:00
if ( $resql && $this -> db -> num_rows ( $resql ) > 0 ) {
2018-07-06 08:07:38 +02:00
$res = $this -> db -> fetch_array ( $resql );
2018-10-01 00:20:47 +02:00
2018-09-24 16:12:00 +02:00
$returnPercent = floatval ( $res [ 'situation_percent' ]);
2018-10-01 00:20:47 +02:00
2019-11-08 10:53:31 +01:00
if ( $include_credit_note ) {
2020-09-08 21:27:28 +02:00
$sql = 'SELECT fd.situation_percent FROM ' . MAIN_DB_PREFIX . 'facturedet fd' ;
$sql .= ' JOIN ' . MAIN_DB_PREFIX . 'facture f ON (f.rowid = fd.fk_facture) ' ;
2021-09-30 15:59:47 +02:00
$sql .= " WHERE fd.fk_prev_id = " . (( int ) $this -> fk_prev_id );
$sql .= " AND f.situation_cycle_ref = " . (( int ) $invoicecache [ $invoiceid ] -> situation_cycle_ref ); // Prevent cycle outed
$sql .= " AND f.type = " . Facture :: TYPE_CREDIT_NOTE ;
2020-09-08 21:27:28 +02:00
$res = $this -> db -> query ( $sql );
if ( $res ) {
while ( $obj = $this -> db -> fetch_object ( $res )) {
$returnPercent = $returnPercent + floatval ( $obj -> situation_percent );
}
} else {
dol_print_error ( $this -> db );
}
2018-09-24 16:12:00 +02:00
}
2018-10-01 00:20:47 +02:00
2018-09-24 16:12:00 +02:00
return $returnPercent ;
2018-07-06 08:07:38 +02:00
} else {
$this -> error = $this -> db -> error ();
2019-11-08 10:53:31 +01:00
dol_syslog ( get_class ( $this ) . " ::select Error " . $this -> error , LOG_ERR );
2018-07-06 08:07:38 +02:00
$this -> db -> rollback ();
return - 1 ;
}
}
}
2014-11-14 16:43:49 +01:00
}