2012-07-11 16:13:41 +00:00
< ? php
2024-11-11 16:38:41 +00:00
/* Copyright ( C ) 2012 Regis Houssin < regis . houssin @ inodbox . com >
* Copyright ( C ) 2012 Cédric Salvador < csalvador @ gpcsolutions . fr >
* Copyright ( C ) 2012 - 2014 Raphaël Doursenaud < rdoursenaud @ gpcsolutions . fr >
2023-10-18 00:33:14 +00:00
* Copyright ( C ) 2023 Nick Fragoulis
2026-04-27 13:40:05 +00:00
* Copyright ( C ) 2024 - 2026 Frédéric France < frederic . france @ free . fr >
2026-04-20 10:38:14 +00:00
* Copyright ( C ) 2024 - 2026 MDW < mdeweerd @ users . noreply . github . com >
2026-01-05 12:28:09 +00:00
* Copyright ( C ) 2024 - 2026 Alexandre Spangaro < alexandre @ inovea - conseil . com >
2012-07-11 16:13:41 +00: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
2013-01-16 14:36:08 +00:00
* the Free Software Foundation ; either version 3 of the License , or
2012-07-11 16:13:41 +00:00
* ( 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 19:55:30 +00:00
* along with this program . If not , see < https :// www . gnu . org / licenses />.
2012-07-11 16:13:41 +00:00
*/
/**
* \file htdocs / core / class / commoninvoice . class . php
* \ingroup core
2024-10-13 14:45:42 +00:00
* \brief File of the superclass of invoice classes ( customer and supplier )
2012-07-11 16:13:41 +00:00
*/
2020-04-10 08:59:32 +00:00
require_once DOL_DOCUMENT_ROOT . '/core/class/commonobject.class.php' ;
2020-09-16 00:50:18 +00:00
require_once DOL_DOCUMENT_ROOT . '/core/class/commonincoterm.class.php' ;
2012-07-11 16:13:41 +00:00
/**
2024-10-13 14:45:42 +00:00
* Superclass for invoice classes
2012-07-11 16:13:41 +00:00
*/
abstract class CommonInvoice extends CommonObject
{
2020-09-16 00:50:18 +00:00
use CommonIncoterm ;
2023-11-24 09:10:24 +00:00
/**
* @ var string Label used as ref for template invoices
*/
public $title ;
2023-04-26 09:41:02 +00:00
/**
* @ var int Type of invoice ( See TYPE_XXX constants )
*/
public $type = self :: TYPE_STANDARD ;
/**
2025-11-08 13:01:19 +00:00
* @ var ? int Sub type of invoice ( A subtype code coming from llx_invoice_subtype table , we store the rowid . May be used by some countries like Greece )
2023-04-26 09:41:02 +00:00
*/
public $subtype ;
2023-12-11 17:22:35 +00:00
/**
* @ var int Thirdparty ID
2024-10-13 14:45:42 +00:00
* @ deprecated Use $socid
2023-12-11 17:22:35 +00:00
* @ see $socid
*/
public $fk_soc ;
2023-09-10 15:30:00 +00:00
/**
* @ var int Thirdparty ID
*/
public $socid ;
2024-10-13 14:45:42 +00:00
/**
* @ var int < 0 , 1 >
*/
2023-09-22 07:07:04 +00:00
public $paye ;
2023-09-10 15:30:00 +00:00
/**
* Invoice date ( date )
*
2024-10-13 14:45:42 +00:00
* @ var int
2023-09-10 15:30:00 +00:00
*/
public $date ;
2024-01-18 22:28:42 +00:00
/**
* @ var int Deadline for payment
*/
2023-12-11 17:22:35 +00:00
public $date_lim_reglement ;
2024-10-13 14:45:42 +00:00
/**
2025-09-04 13:36:54 +00:00
* @ var ? int Payment term ID
2024-10-13 14:45:42 +00:00
*/
2023-09-10 15:30:00 +00:00
public $cond_reglement_id ; // Id in llx_c_paiement
2024-10-13 14:45:42 +00:00
/**
2025-09-04 13:36:54 +00:00
* @ var string | int Code in llx_c_paiement
2024-10-13 14:45:42 +00:00
*/
2023-09-10 15:30:00 +00:00
public $cond_reglement_code ; // Code in llx_c_paiement
2024-10-13 14:45:42 +00:00
/**
2025-09-04 13:36:54 +00:00
* @ var string Label in llx_c_paiement
2024-10-13 14:45:42 +00:00
*/
2023-09-10 15:30:00 +00:00
public $cond_reglement_label ;
2024-10-13 14:45:42 +00:00
/**
2025-09-04 13:36:54 +00:00
* @ var string Label for doc in llx_c_paiement
2024-10-13 14:45:42 +00:00
*/
public $cond_reglement_doc ;
2023-09-10 15:30:00 +00:00
2024-10-13 14:45:42 +00:00
/**
2025-09-04 13:36:54 +00:00
* @ var ? int Payment method ID ( cheque , cash , ... )
2024-10-13 14:45:42 +00:00
*/
2023-09-10 15:30:00 +00:00
public $mode_reglement_id ;
2024-10-13 14:45:42 +00:00
/**
* @ var string Code in llx_c_paiement
*/
public $mode_reglement_code ;
2023-09-10 15:30:00 +00:00
2023-11-06 15:00:24 +00:00
/**
* @ var string
*/
public $mode_reglement ;
2025-06-11 16:17:56 +00:00
/**
* @ var float
*/
public $total_ht ;
/**
* @ var float
*/
public $total_tva ;
/**
* @ var float
*/
public $total_localtax1 ;
/**
* @ var float
*/
public $total_localtax2 ;
/**
* @ var float
*/
public $total_ttc ;
/**
* @ var float | null
*/
public $revenuestamp ;
2024-10-13 14:45:42 +00:00
/**
* @ var float
*/
2025-08-12 02:08:20 +00:00
public $totalpaid ;
2024-10-13 14:45:42 +00:00
/**
* @ var int | float
*/
2025-08-12 02:08:20 +00:00
public $totaldeposits ;
2024-10-13 14:45:42 +00:00
/**
* @ var int | float
*/
2025-08-12 02:08:20 +00:00
public $totalcreditnotes ;
2025-08-11 17:36:44 +00:00
2024-10-13 14:45:42 +00:00
/**
2024-12-30 15:50:22 +00:00
* @ var int | float | string May be used for status
2024-10-13 14:45:42 +00:00
*/
2023-09-10 15:30:00 +00:00
public $remaintopay ;
2024-12-30 15:50:22 +00:00
/**
* @ var int May be used for status
*/
public $nbofopendirectdebitorcredittransfer ;
2023-09-10 15:30:00 +00:00
2025-01-19 12:18:36 +00:00
/**
2025-01-19 12:30:09 +00:00
* @ var int [] return of getListIdAvoirFromInvoice ()
2025-01-19 12:18:36 +00:00
*/
2025-01-20 05:53:03 +00:00
public $creditnote_ids ;
2025-01-19 12:18:36 +00:00
2023-11-07 16:58:35 +00:00
/**
* @ var int
*/
public $stripechargedone ;
/**
* @ var int
*/
public $stripechargeerror ;
2025-08-17 14:10:14 +00:00
/**
* @ var string Can be used to store a payment reference that must be unique for the invoice ( not commonly used )
*/
public $payment_reference ;
/**
* @ var int 1 if a dispute has been open on one payment of invoice , keep null or 0 if not
*/
2025-08-17 15:43:20 +00:00
public $dispute_status = 0 ;
2025-08-17 14:10:14 +00:00
2023-11-07 16:58:35 +00:00
/**
* Payment description
* @ var string
*/
public $description ;
/**
* @ var string
* @ deprecated
* @ see $ref_customer
*/
public $ref_client ;
/**
* @ var int Situation cycle reference number
*/
public $situation_cycle_ref ;
2026-05-08 23:16:35 +00:00
/**
* @ var int Populated by setRetainedWarrantyPaymentTerms ()
*/
public $retained_warranty_fk_cond_reglement ;
2023-09-10 15:30:00 +00:00
/**
2025-04-09 16:01:58 +00:00
* ! Closing after partial payment : CLOSECODE_DISCOUNTVAT , CLOSECODE_BADDEBT , CLOSECODE_BANKCHARGE , CLOSECODE_OTHER
* ! Closing when no payment : CLOSECODE_ABANDONED , CLOSECODE_REPLACED
2023-09-10 15:30:00 +00:00
* @ var string Close code
*/
public $close_code ;
/**
* ! Comment if paid without full payment
* @ var string Close note
*/
public $close_note ;
2023-11-18 23:52:16 +00:00
/**
2024-01-31 20:12:21 +00:00
* ! Populated by payment modules like Stripe
* @ var string [] Messages returned by an online payment module
2023-11-18 23:52:16 +00:00
*/
public $postactionmessages ;
2020-10-27 18:46:07 +00:00
/**
* Standard invoice
*/
const TYPE_STANDARD = 0 ;
/**
* Replacement invoice
*/
const TYPE_REPLACEMENT = 1 ;
/**
* Credit note invoice
*/
const TYPE_CREDIT_NOTE = 2 ;
/**
* Deposit invoice
*/
const TYPE_DEPOSIT = 3 ;
/**
* Proforma invoice .
2024-08-06 23:20:43 +00:00
* @ deprecated Remove this . A " proforma invoice " is an order with a look of invoice , not an invoice !
2020-10-27 18:46:07 +00:00
*/
const TYPE_PROFORMA = 4 ;
/**
* Situation invoice
*/
const TYPE_SITUATION = 5 ;
2015-01-20 16:55:20 +00:00
2015-04-03 03:18:47 +00:00
/**
2018-10-04 07:33:30 +00:00
* Draft status
2015-04-03 03:18:47 +00: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
2024-01-13 18:48:20 +00:00
* If paid completely , this -> close_code will be null
2015-04-03 03:18:47 +00: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 ;
2017-06-09 07:25:15 +00:00
2026-01-21 17:23:03 +00:00
const CLOSECODE_DISCOUNTVAT = 'discount_vat' ; // Abandoned (the remain to pay) - escompte
const CLOSECODE_BADDEBT = 'badcustomer' ; // Abandoned (the remain to pay) - bad customer
const CLOSECODE_BANKCHARGE = 'bankcharge' ; // Abandoned (the remain to pay) - bank charge
const CLOSECODE_WITHHOLDINGTAX = 'withholdingtax' ; // Abandoned (the remain to pay) - source tax
const CLOSECODE_OTHER = 'other' ; // Abandoned (the remain to pay) - other
const CLOSECODE_ABANDONED = 'abandon' ; // Abandoned (no payment at all) - other
const CLOSECODE_REPLACED = 'replaced' ; // Abandoned (no payment at all) - replacedby another invoice (feature disabled by default)
2025-04-09 17:07:31 +00:00
2026-02-03 17:40:36 +00:00
const ARRAY_OF_DISPUTE_STATUS = array (
0 => array ( 'label' => " None " ),
1 => array ( 'label' => " DisputeOpen " ),
8 => array ( 'label' => " DisputeLost " ),
9 => array ( 'label' => " DisputeWon " )
);
2022-04-07 17:16:50 +00:00
2017-02-16 23:19:28 +00:00
/**
2017-05-05 15:27:16 +00:00
* Return remain amount to pay . Property -> id and -> total_ttc must be set .
* This does not include open direct debit requests .
2017-02-16 23:19:28 +00:00
*
* @ param int $multicurrency Return multicurrency_amount instead of amount
2024-10-13 14:45:42 +00:00
* @ return float | string Remain of amount to pay
2017-02-16 23:19:28 +00:00
*/
2019-02-25 21:27:04 +00:00
public function getRemainToPay ( $multicurrency = 0 )
2017-02-16 23:19:28 +00:00
{
2020-10-27 18:46:07 +00:00
$alreadypaid = 0.0 ;
$alreadypaid += $this -> getSommePaiement ( $multicurrency );
$alreadypaid += $this -> getSumDepositsUsed ( $multicurrency );
$alreadypaid += $this -> getSumCreditNotesUsed ( $multicurrency );
2025-03-03 10:39:18 +00:00
if (( int ) $multicurrency > 0 ) {
2025-03-03 10:24:33 +00:00
$totalamount = $this -> multicurrency_total_ttc ;
} else {
$totalamount = $this -> total_ttc ;
}
$remaintopay = price2num ( $totalamount - $alreadypaid , 'MT' );
2024-09-28 09:10:57 +00:00
if ( $this -> status == self :: STATUS_CLOSED && $this -> close_code == 'discount_vat' ) { // If invoice closed with discount for anticipated payment
2020-10-27 18:46:07 +00:00
$remaintopay = 0.0 ;
}
return $remaintopay ;
2017-02-16 23:19:28 +00:00
}
2012-07-11 16:13:41 +00:00
/**
2020-01-01 17:43:46 +00:00
* Return amount of payments already done . This must include ONLY the record into the payment table .
2024-09-28 11:05:24 +00:00
* Payments done using discounts , credit notes , etc are not included .
2025-08-12 02:08:20 +00:00
* This also set -> totalpaid and -> totalpaid_multicurrency
2012-07-11 16:13:41 +00:00
*
2024-10-13 14:45:42 +00:00
* @ param int <- 1 , 1 > $multicurrency Return multicurrency_amount instead of amount . - 1 = Return both .
* @ return float | int | array { alreadypaid : float , alreadypaid_multicurrency : float } Amount of payment already done , < 0 and set -> error if KO
2023-10-26 11:31:20 +00:00
* @ see getSumDepositsUsed (), getSumCreditNotesUsed ()
2012-07-11 16:13:41 +00:00
*/
2019-02-25 21:27:04 +00:00
public function getSommePaiement ( $multicurrency = 0 )
2012-07-11 16:13:41 +00:00
{
2020-04-10 08:59:32 +00:00
$table = 'paiement_facture' ;
$field = 'fk_facture' ;
2021-02-23 21:03:23 +00:00
if ( $this -> element == 'facture_fourn' || $this -> element == 'invoice_supplier' ) {
2020-04-10 08:59:32 +00:00
$table = 'paiementfourn_facturefourn' ;
$field = 'fk_facturefourn' ;
2012-07-11 16:13:41 +00:00
}
2022-01-27 11:52:13 +00:00
$sql = " SELECT sum(amount) as amount, sum(multicurrency_amount) as multicurrency_amount " ;
$sql .= " FROM " . $this -> db -> prefix () . $table ;
2026-04-14 14:38:13 +00:00
$sql .= " WHERE " . $this -> db -> sanitize ( $field ) . " = " . (( int ) $this -> id );
2012-07-11 16:13:41 +00:00
2014-06-12 09:31:53 +00:00
dol_syslog ( get_class ( $this ) . " ::getSommePaiement " , LOG_DEBUG );
2022-09-15 01:08:33 +00:00
2020-04-10 08:59:32 +00:00
$resql = $this -> db -> query ( $sql );
2021-02-23 21:03:23 +00:00
if ( $resql ) {
2012-07-11 16:13:41 +00:00
$obj = $this -> db -> fetch_object ( $resql );
2022-04-07 17:16:50 +00:00
2012-07-11 16:13:41 +00:00
$this -> db -> free ( $resql );
2022-09-15 01:08:33 +00:00
if ( $obj ) {
2023-02-13 20:08:53 +00:00
if ( $multicurrency < 0 ) {
2025-08-12 02:08:20 +00:00
$this -> totalpaid = $obj -> amount ;
$this -> totalpaid_multicurrency = $obj -> multicurrency_amount ;
2024-03-12 23:29:19 +00:00
return array ( 'alreadypaid' => ( float ) $obj -> amount , 'alreadypaid_multicurrency' => ( float ) $obj -> multicurrency_amount );
2023-02-13 20:08:53 +00:00
} elseif ( $multicurrency ) {
2025-08-12 02:08:20 +00:00
$this -> totalpaid_multicurrency = $obj -> multicurrency_amount ;
2022-09-15 01:08:33 +00:00
return ( float ) $obj -> multicurrency_amount ;
} else {
2025-08-12 02:08:20 +00:00
$this -> totalpaid = $obj -> amount ;
2022-09-15 01:08:33 +00:00
return ( float ) $obj -> amount ;
}
2021-02-23 21:03:23 +00:00
} else {
2022-09-15 01:08:33 +00:00
return 0 ;
2021-02-23 21:03:23 +00:00
}
2020-05-21 13:05:19 +00:00
} else {
2020-04-10 08:59:32 +00:00
$this -> error = $this -> db -> lasterror ();
2012-07-11 16:13:41 +00:00
return - 1 ;
}
}
2017-06-09 07:25:15 +00:00
2017-01-23 19:54:52 +00:00
/**
2023-10-26 11:31:20 +00:00
* Return amount ( with tax ) of all deposits invoices used by invoice .
* Should always be empty , except if option FACTURE_DEPOSITS_ARE_JUST_PAYMENTS is on for sale invoices ( not recommended ),
* of FACTURE_SUPPLIER_DEPOSITS_ARE_JUST_PAYMENTS is on for purchase invoices ( not recommended ) .
2017-01-23 19:54:52 +00:00
*
2023-10-26 11:31:20 +00:00
* @ param int $multicurrency Return multicurrency_amount instead of amount
2023-12-06 14:46:39 +00:00
* @ return float Return integer < 0 and set -> error if KO , Sum of deposits amount otherwise
2023-10-26 11:31:20 +00:00
* @ see getSommePaiement (), getSumCreditNotesUsed ()
2017-01-23 19:54:52 +00:00
*/
2019-02-25 21:27:04 +00:00
public function getSumDepositsUsed ( $multicurrency = 0 )
2017-01-23 19:54:52 +00:00
{
2022-06-17 15:59:33 +00:00
/* if ( $this -> element == 'facture_fourn' || $this -> element == 'invoice_supplier' ) {
2022-10-12 09:52:33 +00:00
// FACTURE_SUPPLIER_DEPOSITS_ARE_JUST_PAYMENTS was never supported for purchase invoice, so we can return 0 with no need of SQL for this case.
2020-10-27 18:46:07 +00:00
return 0.0 ;
2022-06-17 15:59:33 +00:00
} */
2020-10-27 18:46:07 +00:00
require_once DOL_DOCUMENT_ROOT . '/core/class/discount.class.php' ;
$discountstatic = new DiscountAbsolute ( $this -> db );
$result = $discountstatic -> getSumDepositsUsed ( $this , $multicurrency );
2021-12-16 11:33:45 +00:00
2020-10-27 18:46:07 +00:00
if ( $result >= 0 ) {
2022-04-07 17:16:50 +00:00
if ( $multicurrency ) {
2025-08-12 02:08:20 +00:00
$this -> totaldeposits_multicurrency = $result ;
2022-04-07 17:16:50 +00:00
} else {
2025-08-12 02:08:20 +00:00
$this -> totaldeposits = $result ;
2022-04-07 17:16:50 +00:00
}
2020-10-27 18:46:07 +00:00
return $result ;
} else {
$this -> error = $discountstatic -> error ;
return - 1 ;
}
2017-01-23 19:54:52 +00:00
}
2017-02-16 23:19:28 +00:00
2017-01-23 19:54:52 +00:00
/**
2023-10-26 11:31:20 +00:00
* Return amount ( with tax ) of all credit notes invoices + excess received used by invoice
2017-01-23 19:54:52 +00:00
*
2023-10-26 11:31:20 +00:00
* @ param int $multicurrency Return multicurrency_amount instead of amount
2025-06-21 14:16:47 +00:00
* @ return float | string Return string 'Error...' and set -> error if KO , Sum of credit notes and deposits amount otherwise
2023-10-26 11:31:20 +00:00
* @ see getSommePaiement (), getSumDepositsUsed ()
2017-01-23 19:54:52 +00:00
*/
2019-02-25 21:27:04 +00:00
public function getSumCreditNotesUsed ( $multicurrency = 0 )
2017-01-23 19:54:52 +00:00
{
2020-10-27 18:46:07 +00:00
require_once DOL_DOCUMENT_ROOT . '/core/class/discount.class.php' ;
$discountstatic = new DiscountAbsolute ( $this -> db );
$result = $discountstatic -> getSumCreditNotesUsed ( $this , $multicurrency );
2025-06-21 14:16:47 +00:00
if ( is_numeric ( $result )) {
2022-04-07 17:16:50 +00:00
if ( $multicurrency ) {
2025-08-12 02:08:20 +00:00
$this -> totalcreditnotes_multicurrency = $result ;
2022-04-07 17:16:50 +00:00
} else {
2025-08-12 02:08:20 +00:00
$this -> totalcreditnotes = $result ;
2022-04-07 17:16:50 +00:00
}
2020-10-27 18:46:07 +00:00
return $result ;
} else {
$this -> error = $discountstatic -> error ;
2025-06-21 14:16:47 +00:00
return $result ;
2020-10-27 18:46:07 +00:00
}
2017-01-23 19:54:52 +00:00
}
2017-06-09 07:25:15 +00:00
2019-04-12 08:16:13 +00:00
/**
* Return amount ( with tax ) of all converted amount for this credit note
*
* @ param int $multicurrency Return multicurrency_amount instead of amount
2023-12-06 14:46:39 +00:00
* @ return float Return integer < 0 if KO , Sum of credit notes and deposits amount otherwise
2019-04-12 08:16:13 +00:00
*/
2019-08-27 01:41:02 +00:00
public function getSumFromThisCreditNotesNotUsed ( $multicurrency = 0 )
2019-04-12 08:16:13 +00:00
{
2020-10-27 18:46:07 +00:00
require_once DOL_DOCUMENT_ROOT . '/core/class/discount.class.php' ;
$discountstatic = new DiscountAbsolute ( $this -> db );
$result = $discountstatic -> getSumFromThisCreditNotesNotUsed ( $this , $multicurrency );
if ( $result >= 0 ) {
return $result ;
} else {
$this -> error = $discountstatic -> error ;
return - 1 ;
}
2017-01-23 19:54:52 +00:00
}
2017-06-09 07:25:15 +00:00
2012-07-11 16:13:41 +00:00
/**
2019-10-19 16:33:06 +00:00
* Returns array of credit note ids from the invoice
2012-07-11 16:13:41 +00:00
*
2024-10-13 14:45:42 +00:00
* @ return int [] Array of credit note ids
2012-07-11 16:13:41 +00:00
*/
2019-02-25 21:27:04 +00:00
public function getListIdAvoirFromInvoice ()
2012-07-11 16:13:41 +00:00
{
2020-04-10 08:59:32 +00:00
$idarray = array ();
2012-07-11 16:13:41 +00:00
2022-01-27 11:52:13 +00:00
$sql = " SELECT rowid " ;
2022-01-27 09:19:35 +00:00
$sql .= " FROM " . $this -> db -> prefix () . $this -> table_element ;
2021-09-30 13:59:47 +00:00
$sql .= " WHERE fk_facture_source = " . (( int ) $this -> id );
2025-08-15 16:43:58 +00:00
$sql .= " AND type = " . self :: TYPE_CREDIT_NOTE ;
2020-04-10 08:59:32 +00:00
$resql = $this -> db -> query ( $sql );
2021-02-23 21:03:23 +00:00
if ( $resql ) {
2012-07-11 16:13:41 +00:00
$num = $this -> db -> num_rows ( $resql );
$i = 0 ;
2021-02-23 21:03:23 +00:00
while ( $i < $num ) {
2012-07-11 16:13:41 +00:00
$row = $this -> db -> fetch_row ( $resql );
2020-04-10 08:59:32 +00:00
$idarray [] = $row [ 0 ];
2012-07-11 16:13:41 +00:00
$i ++ ;
}
2020-05-21 13:05:19 +00:00
} else {
2012-07-11 16:13:41 +00:00
dol_print_error ( $this -> db );
}
2025-01-20 05:53:03 +00:00
$this -> creditnote_ids = $idarray ;
2012-07-11 16:13:41 +00:00
return $idarray ;
}
/**
2019-10-19 16:33:06 +00:00
* Returns the id of the invoice that replaces it
2012-07-11 16:13:41 +00:00
*
2019-10-19 16:33:06 +00:00
* @ param string $option status filter ( '' , 'validated' , ... )
2023-12-06 14:46:39 +00:00
* @ return int Return integer < 0 si KO , 0 if no invoice replaces it , id of invoice otherwise
2012-07-11 16:13:41 +00:00
*/
2019-02-25 21:27:04 +00:00
public function getIdReplacingInvoice ( $option = '' )
2012-07-11 16:13:41 +00:00
{
2022-01-27 11:52:13 +00:00
$sql = " SELECT rowid " ;
2022-01-27 09:19:35 +00:00
$sql .= " FROM " . $this -> db -> prefix () . $this -> table_element ;
2021-09-30 13:59:47 +00:00
$sql .= " WHERE fk_facture_source = " . (( int ) $this -> id );
2022-01-27 11:52:13 +00:00
$sql .= " AND type < 2 " ;
2021-02-23 21:03:23 +00:00
if ( $option == 'validated' ) {
$sql .= ' AND fk_statut = 1' ;
}
2012-07-11 16:13:41 +00:00
// PROTECTION BAD DATA
2019-10-19 16:33:06 +00:00
// In case the database is corrupted and there is a valid replectement invoice
// and another no, priority is given to the valid one.
// Should not happen (unless concurrent access and 2 people have created a
// replacement invoice for the same invoice at the same time)
2022-01-27 11:52:13 +00:00
$sql .= " ORDER BY fk_statut DESC " ;
2012-07-11 16:13:41 +00:00
2020-04-10 08:59:32 +00:00
$resql = $this -> db -> query ( $sql );
2021-02-23 21:03:23 +00:00
if ( $resql ) {
2012-07-11 16:13:41 +00:00
$obj = $this -> db -> fetch_object ( $resql );
2021-02-23 21:03:23 +00:00
if ( $obj ) {
2019-10-19 16:33:06 +00:00
// If there is any
2012-07-11 16:13:41 +00:00
return $obj -> rowid ;
2020-05-21 13:05:19 +00:00
} else {
2019-10-19 16:33:06 +00:00
// If no invoice replaces it
2012-07-11 16:13:41 +00:00
return 0 ;
}
2020-05-21 13:05:19 +00:00
} else {
2012-07-11 16:13:41 +00:00
return - 1 ;
}
}
2024-12-30 15:50:22 +00:00
/**
* Return list of open direct debit or credit transfer
*
2024-12-30 21:19:17 +00:00
* @ param 'bank-transfer' | 'direct-debit' $type 'bank-transfer' or 'direct-debit'
* @ return array < array { id : int , invoiceid : int , date : '' | int , amount : float } > Array with list of payments
2024-12-30 15:50:22 +00:00
*/
public function getListOfOpenDirectDebitOrCreditTransfer ( $type )
{
$listofopendirectdebitorcredittransfer = array ();
// TODO Add a cache to store array of open requests for each invoice ID
$sql = " SELECT pfd.rowid, pfd.traite, pfd.date_demande as date_demande, pfd.date_traite as date_traite, pfd.amount " ;
$sql .= " FROM " . MAIN_DB_PREFIX . " prelevement_demande as pfd " ;
if ( $type == 'bank-transfer' ) {
$sql .= " WHERE fk_facture_fourn = " . (( int ) $this -> id );
} else {
$sql .= " WHERE fk_facture = " . (( int ) $this -> id );
}
$sql .= " AND pfd.traite = 0 " ;
$sql .= " AND pfd.type = 'ban' " ;
$sql .= " ORDER BY pfd.date_demande DESC " ;
$resql = $this -> db -> query ( $sql );
2024-12-30 16:54:31 +00:00
$num = 0 ;
2024-12-30 15:50:22 +00:00
if ( $resql ) {
$num = $this -> db -> num_rows ( $resql );
$i = 0 ;
while ( $i < $num ) {
$obj = $this -> db -> fetch_object ( $resql );
if ( $obj ) {
$listofopendirectdebitorcredittransfer [] = array (
2024-12-30 21:19:17 +00:00
'id' => ( int ) $obj -> rowid ,
2024-12-30 15:50:22 +00:00
'invoiceid' => ( int ) $this -> id ,
'date' => $this -> db -> jdate ( $obj -> date_demande ),
2024-12-30 21:19:17 +00:00
'amount' => ( float ) $obj -> amount
2024-12-30 15:50:22 +00:00
);
}
$i ++ ;
}
} else {
$this -> error = $this -> db -> lasterror ();
}
$this -> nbofopendirectdebitorcredittransfer = $num ;
return $listofopendirectdebitorcredittransfer ;
}
2026-05-08 23:16:35 +00:00
/**
* Change the retained warranty payments terms
*
* @ param int $id Id of new payment terms
* @ return int > 0 if OK , < 0 if KO
*/
public function setRetainedWarrantyPaymentTerms ( $id )
{
dol_syslog ( get_class ( $this ) . '::setRetainedWarrantyPaymentTerms(' . $id . ')' );
if ( $this -> status >= 0 || $this -> element == 'societe' ) {
$fieldname = 'retained_warranty_fk_cond_reglement' ;
$sql = 'UPDATE ' . $this -> db -> prefix () . $this -> table_element ;
$sql .= " SET " . $this -> db -> sanitize ( $fieldname ) . " = " . (( int ) $id );
$sql .= ' WHERE rowid=' . (( int ) $this -> id );
if ( $this -> db -> query ( $sql )) {
$this -> retained_warranty_fk_cond_reglement = $id ;
return 1 ;
} else {
dol_syslog ( get_class ( $this ) . '::setRetainedWarrantyPaymentTerms Error ' . $sql . ' - ' . $this -> db -> error ());
$this -> error = $this -> db -> error ();
return - 1 ;
}
} else {
dol_syslog ( get_class ( $this ) . '::setRetainedWarrantyPaymentTerms, status of the object is incompatible' );
$this -> error = 'Status of the object is incompatible ' . $this -> status ;
return - 2 ;
}
}
2018-02-26 08:45:15 +00:00
/**
* Return list of payments
*
2024-03-17 13:24:07 +00:00
* @ see $error Empty string '' if no error .
*
2024-09-29 18:32:09 +00:00
* @ param string $filtertype 1 to filter on type of payment == 'PRE' for the payment lines
* @ param int $multicurrency Return multicurrency_amount instead of amount
* @ param int $mode 0 = payments + discount , 1 = payments only
2024-06-26 15:25:15 +00:00
* @ return array < array { amount : int | float , date : int , num : string , ref : string , ref_ext ? : string , fk_bank_line ? : int , type : string } > Array with list of payments
2018-02-26 08:45:15 +00:00
*/
2024-09-29 18:32:09 +00:00
public function getListOfPayments ( $filtertype = '' , $multicurrency = 0 , $mode = 0 )
2018-02-26 08:45:15 +00:00
{
2020-04-10 08:59:32 +00:00
$retarray = array ();
2024-09-29 18:32:09 +00:00
$this -> error = '' ; // By default no error, list can be empty.
2018-02-26 08:45:15 +00:00
2020-04-10 08:59:32 +00:00
$table = 'paiement_facture' ;
$table2 = 'paiement' ;
2026-04-14 17:23:50 +00:00
2020-04-10 08:59:32 +00:00
$field = 'fk_facture' ;
$field2 = 'fk_paiement' ;
2026-04-14 17:23:50 +00:00
$field3 = 'p.ref_ext' ;
$field4 = 'p.fk_bank' ; // Bank line id
2020-04-10 08:59:32 +00:00
$sharedentity = 'facture' ;
2026-04-14 17:23:50 +00:00
2021-02-23 21:03:23 +00:00
if ( $this -> element == 'facture_fourn' || $this -> element == 'invoice_supplier' ) {
2020-04-10 08:59:32 +00:00
$table = 'paiementfourn_facturefourn' ;
$table2 = 'paiementfourn' ;
2026-04-14 17:23:50 +00:00
2020-04-10 08:59:32 +00:00
$field = 'fk_facturefourn' ;
$field2 = 'fk_paiementfourn' ;
2020-10-31 13:32:18 +00:00
$field3 = '' ;
2026-04-14 17:23:50 +00:00
2020-04-10 08:59:32 +00:00
$sharedentity = 'facture_fourn' ;
2018-02-26 08:45:15 +00:00
}
2024-09-29 18:32:09 +00:00
// List of payments
if ( empty ( $mode ) || $mode == 1 ) {
2026-04-20 10:38:14 +00:00
$sql = " SELECT p.ref, pf.amount, pf.multicurrency_amount, p.fk_paiement, p.datep, p.num_paiement as num, t.code " . ( $field3 ? " , " . $this -> db -> sanitize ( $field3 ) : " " ) . ( " , " . $this -> db -> sanitize ( $field4 ));
2024-09-29 18:32:09 +00:00
$sql .= " FROM " . $this -> db -> prefix () . $table . " as pf, " . $this -> db -> prefix () . $table2 . " as p, " . $this -> db -> prefix () . " c_paiement as t " ;
2026-04-14 17:23:50 +00:00
$sql .= " WHERE pf. " . $this -> db -> sanitize ( $field ) . " = " . (( int ) $this -> id );
$sql .= " AND pf. " . $this -> db -> sanitize ( $field2 ) . " = p.rowid " ;
2024-09-29 18:32:09 +00:00
$sql .= ' AND p.fk_paiement = t.id' ;
$sql .= ' AND p.entity IN (' . getEntity ( $sharedentity ) . ')' ;
if ( $filtertype ) {
$sql .= " AND t.code='PRE' " ;
}
2018-02-26 08:45:15 +00:00
2024-09-29 18:32:09 +00:00
dol_syslog ( get_class ( $this ) . " ::getListOfPayments filtertype= " . $filtertype . " multicurrency= " . $multicurrency . " mode= " . $mode , LOG_DEBUG );
$resql = $this -> db -> query ( $sql );
if ( $resql ) {
$num = $this -> db -> num_rows ( $resql );
$i = 0 ;
while ( $i < $num ) {
$obj = $this -> db -> fetch_object ( $resql );
if ( $multicurrency ) {
$tmp = array ( 'amount' => $obj -> multicurrency_amount , 'type' => $obj -> code , 'typeline' => 'payment' , 'date' => $obj -> datep , 'num' => $obj -> num , 'ref' => $obj -> ref );
} else {
$tmp = array ( 'amount' => $obj -> amount , 'type' => $obj -> code , 'typeline' => 'payment' , 'date' => $obj -> datep , 'num' => $obj -> num , 'ref' => $obj -> ref );
}
if ( ! empty ( $field3 )) {
$tmp [ 'ref_ext' ] = $obj -> ref_ext ;
}
if ( ! empty ( $field4 )) {
$tmp [ 'fk_bank_line' ] = $obj -> fk_bank ;
}
$retarray [] = $tmp ;
$i ++ ;
2023-01-29 00:31:44 +00:00
}
2024-09-29 18:32:09 +00:00
$this -> db -> free ( $resql );
} else {
$this -> error = $this -> db -> lasterror ();
dol_print_error ( $this -> db );
return array ();
2018-02-26 08:45:15 +00:00
}
2024-09-29 18:32:09 +00:00
}
2019-12-31 16:10:36 +00:00
2024-09-29 18:32:09 +00:00
// Look for credit notes and discounts and deposits
if ( empty ( $mode ) || $mode == 2 ) {
2019-12-31 16:07:56 +00:00
$sql = '' ;
2021-02-23 21:03:23 +00:00
if ( $this -> element == 'facture' || $this -> element == 'invoice' ) {
2021-09-30 13:59:47 +00:00
$sql = " SELECT rc.amount_ttc as amount, rc.multicurrency_amount_ttc as multicurrency_amount, rc.datec as date, f.ref as ref, rc.description as type " ;
2022-01-27 09:19:35 +00:00
$sql .= ' FROM ' . $this -> db -> prefix () . 'societe_remise_except as rc, ' . $this -> db -> prefix () . 'facture as f' ;
2021-08-27 21:36:06 +00:00
$sql .= ' WHERE rc.fk_facture_source=f.rowid AND rc.fk_facture = ' . (( int ) $this -> id );
2020-04-10 08:59:32 +00:00
$sql .= ' AND (f.type = 2 OR f.type = 0 OR f.type = 3)' ; // Find discount coming from credit note or excess received or deposits (payments from deposits are always null except if FACTURE_DEPOSITS_ARE_JUST_PAYMENTS is set)
2021-02-23 21:03:23 +00:00
} elseif ( $this -> element == 'facture_fourn' || $this -> element == 'invoice_supplier' ) {
2021-09-30 13:59:47 +00:00
$sql = " SELECT rc.amount_ttc as amount, rc.multicurrency_amount_ttc as multicurrency_amount, rc.datec as date, f.ref as ref, rc.description as type " ;
2022-01-27 09:19:35 +00:00
$sql .= ' FROM ' . $this -> db -> prefix () . 'societe_remise_except as rc, ' . $this -> db -> prefix () . 'facture_fourn as f' ;
2021-08-27 21:36:06 +00:00
$sql .= ' WHERE rc.fk_invoice_supplier_source=f.rowid AND rc.fk_invoice_supplier = ' . (( int ) $this -> id );
2022-10-12 09:52:33 +00:00
$sql .= ' AND (f.type = 2 OR f.type = 0 OR f.type = 3)' ; // Find discount coming from credit note or excess received or deposits (payments from deposits are always null except if FACTURE_SUPPLIER_DEPOSITS_ARE_JUST_PAYMENTS is set)
2019-12-31 00:08:25 +00:00
}
2019-12-31 00:13:42 +00:00
2019-12-31 16:06:30 +00:00
if ( $sql ) {
2020-04-10 08:59:32 +00:00
$resql = $this -> db -> query ( $sql );
2021-02-23 21:03:23 +00:00
if ( $resql ) {
2019-12-31 16:06:30 +00:00
$num = $this -> db -> num_rows ( $resql );
2020-04-10 08:59:32 +00:00
$i = 0 ;
2021-02-23 21:03:23 +00:00
while ( $i < $num ) {
2019-12-31 16:06:30 +00:00
$obj = $this -> db -> fetch_object ( $resql );
2019-12-31 16:07:07 +00:00
if ( $multicurrency ) {
2024-09-29 18:16:41 +00:00
$retarray [] = array ( 'amount' => $obj -> multicurrency_amount , 'type' => $obj -> type , 'typeline' => 'discount' , 'date' => $obj -> date , 'num' => '0' , 'ref' => $obj -> ref );
2020-05-21 13:05:19 +00:00
} else {
2024-09-29 18:16:41 +00:00
$retarray [] = array ( 'amount' => $obj -> amount , 'type' => $obj -> type , 'typeline' => 'discount' , 'date' => $obj -> date , 'num' => '' , 'ref' => $obj -> ref );
2019-12-31 16:06:30 +00:00
}
$i ++ ;
}
2020-05-21 13:05:19 +00:00
} else {
2019-12-31 16:06:30 +00:00
$this -> error = $this -> db -> lasterror ();
dol_print_error ( $this -> db );
return array ();
2019-12-31 00:08:25 +00:00
}
$this -> db -> free ( $resql );
2024-09-29 18:32:09 +00:00
} else {
$this -> error = $this -> db -> lasterror ();
dol_print_error ( $this -> db );
return array ();
2019-12-31 00:08:25 +00:00
}
2018-02-26 08:45:15 +00:00
}
2024-09-29 18:32:09 +00:00
return $retarray ;
2018-02-26 08:45:15 +00:00
}
2026-01-01 11:26:35 +00:00
/**
* Return if an invoice can be set back to draft .
* Rule is :
* If invoice is draft and has a temporary ref -> yes ( 1 )
* If invoice is transferred in bookkeeping -> no ( - 1 )
* If invoice has a definitive ref , is not last in a situation cycle -> no ( - 3 )
* If there is one payment -> no ( - 4 )
* If already sent by email -> no ( - 5 )
* If already printed -> no ( - 6 )
* If running a LNE version and customer invoice was validated -> no ( - 7 )
* Otherwise -> yes ( 2 )
*
* @ return int Return integer <= 0 if no , > 0 if yes
*/
public function isEditable ()
{
2026-03-16 09:40:19 +00:00
// phpcs:enable
global $hookmanager , $action ;
// We check if invoice is a temporary number (PROVxxxx)
$tmppart = substr ( $this -> ref , 1 , 4 );
if ( $this -> status == self :: STATUS_DRAFT && $tmppart === 'PROV' ) { // If draft invoice and ref not yet defined
return 1 ;
}
2026-01-01 11:26:35 +00:00
2026-03-16 09:40:19 +00:00
/*
if ( getDolGlobalInt ( 'INVOICE_CAN_NEVER_BE_REMOVED' )) {
return 0 ;
}
*/
// If not a draft invoice and not temporary invoice
if ( $tmppart !== 'PROV' ) {
2026-04-20 10:38:14 +00:00
if ( $this instanceof Facture ) {
2026-03-16 09:40:19 +00:00
/* @var Facture $this */
// If sent by email, we refuse
if (( int ) $this -> email_sent_counter > 0 ) {
return - 5 ;
}
// If printed, we refuse
if (( int ) $this -> pos_print_counter > 0 ) {
return - 6 ;
}
include_once DOL_DOCUMENT_ROOT . '/blockedlog/lib/blockedlog.lib.php' ;
2026-05-27 13:47:29 +00:00
if ( isALNERunningVersion () && ! empty ( $this -> module_source )) {
$this -> error = 'Action to modify an invoice from an external module like the Point Of Sale is not allowed' ;
2026-03-16 09:40:19 +00:00
return - 7 ;
2026-05-27 14:09:42 +00:00
// Note, edit status to draft is also blocked by the trigger of blockedlog module for action BILL_UNVALIDATE that do a test on isEditable().
2026-03-16 09:40:19 +00:00
}
}
// If in accountancy, we refuse
$ventilExportCompta = $this -> getVentilExportCompta ();
if ( $ventilExportCompta != 0 ) {
return - 1 ;
}
// Get last number of validated invoice
if ( $this -> element != 'invoice_supplier' ) {
/*
if ( empty ( $this -> thirdparty )) {
$this -> fetch_thirdparty (); // We need to have this->thirdparty defined, in case of the numbering rule uses tags that depend on thirdparty (like {t} tag).
}
$maxref = $this -> getNextNumRef ( $this -> thirdparty , 'last' );
// $maxref can be '' (means not found) if there is no invoice yet, but also if there is no invoice for the new period when there is a reset at each period
// If invoice to delete is not the last one, we refuse
if ( $maxref != '' && $maxref != $this -> ref ) {
return - 2 ;
}
*/
// TODO If there is payment in bookkeeping, check the payment is not dispatched in accounting and return -2.
// ...
// If invoice is situation type, we refuse if it is not the last in situation cycle
if ( ! getDolGlobalString ( 'INVOICE_SITUATION_CAN_BE_REMOVED_EVEN_IF_NOT_LAST' ) && $this -> situation_cycle_ref && method_exists ( $this , 'is_last_in_cycle' )) {
$last = $this -> is_last_in_cycle ();
if ( ! $last ) {
return - 3 ;
}
}
}
2026-01-01 11:26:35 +00:00
2026-03-16 09:40:19 +00:00
// Test if there is at least one payment. If yes, we refuse.
if ( $this -> getSommePaiement () > 0 ) {
return - 4 ;
}
$parameters = array ();
$reshook = $hookmanager -> executeHooks ( 'isEditable' , $parameters , $this , $action );
if ( ! empty ( $hookmanager -> resArray [ 'result' ])) {
$this -> error = $hookmanager -> resArray [ 'error' ];
if ( ! empty ( $hookmanager -> resArray [ 'errors' ])) {
2026-03-20 16:11:10 +00:00
$this -> errors = array_merge ( $this -> errors , $hookmanager -> resArray [ 'errors' ]);
}
if ( ! in_array ( $this -> error , $this -> errors )) {
$this -> errors [] = $this -> error ;
2026-03-16 09:40:19 +00:00
}
return $hookmanager -> resArray [ 'result' ];
}
}
return 2 ;
2026-01-01 11:26:35 +00:00
}
2018-02-26 08:45:15 +00:00
2026-02-17 13:50:08 +00:00
/**
* Return if an invoice can be replaced by a Replacement invoice ( also called " Correction invoice " ) .
*
* @ return int Return integer <= 0 if no , > 0 if yes
*/
public function isReplacable ()
{
global $hookmanager , $action ;
// We check if invoice is a temporary number (PROVxxxx)
$tmppart = substr ( $this -> ref , 1 , 4 );
if ( $this -> status == self :: STATUS_DRAFT ) { // If draft invoice, no
return - 1 ;
}
// If not a draft invoice and not temporary invoice
if ( $tmppart !== 'PROV' ) {
// If in accountancy, we refuse
$ventilExportCompta = $this -> getVentilExportCompta ();
if ( $ventilExportCompta != 0 ) {
return - 1 ;
}
// If invoice is situation type, we refuse if it is not the last in situation cycle
if ( ! getDolGlobalString ( 'INVOICE_SITUATION_CAN_BE_REMOVED_EVEN_IF_NOT_LAST' ) && $this -> situation_cycle_ref && method_exists ( $this , 'is_last_in_cycle' )) {
$last = $this -> is_last_in_cycle ();
if ( ! $last ) {
return - 3 ;
}
}
// Test if there is at least one payment. If yes, we refuse to delete.
if ( $this -> getSommePaiement () > 0 ) {
return - 4 ;
}
include_once DOL_DOCUMENT_ROOT . '/blockedlog/lib/blockedlog.lib.php' ;
if ( isALNERunningVersion ()) {
2026-07-09 21:20:58 +00:00
$this -> error = 'Action not allowed on a certified version (or candidate for certification)' ;
2026-02-17 13:50:08 +00:00
return - 7 ;
}
$parameters = array ();
2026-03-20 16:16:05 +00:00
$reshook = $hookmanager -> executeHooks ( 'isReplacable' , $parameters , $this , $action );
2026-02-17 13:50:08 +00:00
if ( ! empty ( $hookmanager -> resArray [ 'result' ])) {
$this -> error = $hookmanager -> resArray [ 'error' ];
if ( ! empty ( $hookmanager -> resArray [ 'errors' ])) {
2026-02-17 15:01:39 +00:00
$this -> errors = array_merge ( $this -> errors , $hookmanager -> resArray [ 'errors' ]);
2026-02-17 13:50:08 +00:00
}
2026-03-20 16:16:05 +00:00
if ( ! in_array ( $this -> error , $this -> errors )) {
$this -> errors [] = $this -> error ;
}
2026-02-17 13:56:03 +00:00
return $hookmanager -> resArray [ 'result' ];
2026-02-17 13:50:08 +00:00
}
return 1 ;
}
return 0 ;
}
2020-10-27 18:46:07 +00:00
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2017-12-05 09:01:30 +00:00
/**
* Return if an invoice can be deleted
* Rule is :
2018-10-29 13:41:00 +00:00
* If invoice is draft and has a temporary ref -> yes ( 1 )
2025-03-15 10:10:02 +00:00
* If hidden option INVOICE_CAN_NEVER_BE_REMOVED is 1 -> no ( 0 )
* If invoice is transferred in bookkeeping -> no ( - 1 )
2025-12-01 17:56:18 +00:00
* If invoice has a definitive ref , is not last in ref -> no ( - 2 )
* If invoice has a definitive ref , is not last in a situation cycle -> no ( - 3 )
* If there is one payment -> no ( - 4 )
* If already sent by email -> no ( - 5 )
* If already printed -> no ( - 6 )
2026-01-01 11:26:35 +00:00
* If running a LNE version and customer invoice was validated -> no ( - 7 )
2026-02-12 15:01:54 +00:00
* Other value ( may be returned by a hook - 10 , - 11 , ... )
2018-10-29 13:41:00 +00:00
* Otherwise -> yes ( 2 )
2017-12-05 09:01:30 +00:00
*
2023-12-06 14:46:39 +00:00
* @ return int Return integer <= 0 if no , > 0 if yes
2017-12-05 09:01:30 +00:00
*/
2020-10-27 18:46:07 +00:00
public function is_erasable ()
{
// phpcs:enable
2026-02-12 15:01:54 +00:00
global $hookmanager , $action ;
2017-12-05 09:01:30 +00:00
// We check if invoice is a temporary number (PROVxxxx)
$tmppart = substr ( $this -> ref , 1 , 4 );
2024-09-28 09:10:57 +00:00
if ( $this -> status == self :: STATUS_DRAFT && $tmppart === 'PROV' ) { // If draft invoice and ref not yet defined
2017-12-05 09:01:30 +00:00
return 1 ;
}
2025-03-15 10:10:02 +00:00
if ( getDolGlobalInt ( 'INVOICE_CAN_NEVER_BE_REMOVED' )) {
2021-02-23 21:03:23 +00:00
return 0 ;
}
2017-12-05 09:01:30 +00:00
// If not a draft invoice and not temporary invoice
2021-02-23 21:03:23 +00:00
if ( $tmppart !== 'PROV' ) {
2026-04-20 10:38:14 +00:00
if ( $this instanceof Facture ) {
2025-12-01 17:56:18 +00:00
/* @var Facture $this */
// If sent by email, we refuse
if (( int ) $this -> email_sent_counter > 0 ) {
return - 5 ;
}
// If printed, we refuse
if (( int ) $this -> pos_print_counter > 0 ) {
return - 6 ;
}
2026-01-01 11:26:35 +00:00
include_once DOL_DOCUMENT_ROOT . '/blockedlog/lib/blockedlog.lib.php' ;
if ( isALNERunningVersion ()) {
2026-07-09 21:20:58 +00:00
$this -> error = 'Action not allowed on the certified version (or candidate for certification)' ;
2026-01-01 11:26:35 +00:00
return - 7 ;
}
2025-12-01 17:56:18 +00:00
}
// If in accountancy, we refuse
2017-12-05 09:01:30 +00:00
$ventilExportCompta = $this -> getVentilExportCompta ();
2021-02-23 21:03:23 +00:00
if ( $ventilExportCompta != 0 ) {
return - 1 ;
}
2017-12-05 09:01:30 +00:00
// Get last number of validated invoice
2021-02-23 21:03:23 +00:00
if ( $this -> element != 'invoice_supplier' ) {
if ( empty ( $this -> thirdparty )) {
2025-12-01 17:56:18 +00:00
$this -> fetch_thirdparty (); // We need to have this->thirdparty defined, in case of the numbering rule uses tags that depend on thirdparty (like {t} tag).
2021-02-23 21:03:23 +00:00
}
2019-01-27 10:55:16 +00:00
$maxref = $this -> getNextNumRef ( $this -> thirdparty , 'last' );
2026-01-02 15:15:52 +00:00
// $maxref can be '' (means not found) if there is no invoice yet, but also if there is no invoice for the new period when there is a reset at each period
2017-12-05 09:01:30 +00:00
2025-12-01 17:56:18 +00:00
// If invoice to delete is not the last one, we refuse
if ( $maxref != '' && $maxref != $this -> ref ) {
2021-02-23 21:03:23 +00:00
return - 2 ;
}
2017-12-05 09:01:30 +00:00
2025-03-15 10:10:02 +00:00
// TODO If there is payment in bookkeeping, check the payment is not dispatched in accounting and return -2.
2017-12-05 09:01:30 +00:00
// ...
2026-02-17 13:50:08 +00:00
// If invoice is situation type, we refuse if it is not the last in situation cycle
2025-12-01 17:56:18 +00:00
if ( ! getDolGlobalString ( 'INVOICE_SITUATION_CAN_BE_REMOVED_EVEN_IF_NOT_LAST' ) && $this -> situation_cycle_ref && method_exists ( $this , 'is_last_in_cycle' )) {
2017-12-05 09:01:30 +00:00
$last = $this -> is_last_in_cycle ();
2021-02-23 21:03:23 +00:00
if ( ! $last ) {
return - 3 ;
}
2017-12-05 09:01:30 +00:00
}
}
2026-03-16 09:40:19 +00:00
// Test if there is at least one payment. If yes, we refuse.
2025-12-01 17:56:18 +00:00
if ( $this -> getSommePaiement () > 0 ) {
return - 4 ;
}
2026-02-12 15:01:54 +00:00
$parameters = array ();
2026-03-16 09:40:19 +00:00
$reshook = $hookmanager -> executeHooks ( 'isErasable' , $parameters , $this , $action );
2026-02-12 15:01:54 +00:00
if ( ! empty ( $hookmanager -> resArray [ 'result' ])) {
$this -> error = $hookmanager -> resArray [ 'error' ];
if ( ! empty ( $hookmanager -> resArray [ 'errors' ])) {
2026-02-17 15:01:39 +00:00
$this -> errors = array_merge ( $this -> errors , $hookmanager -> resArray [ 'errors' ]);
2026-02-12 15:01:54 +00:00
}
2026-03-20 16:11:10 +00:00
if ( ! in_array ( $this -> error , $this -> errors )) {
$this -> errors [] = $this -> error ;
2026-02-12 15:01:54 +00:00
}
2026-02-17 13:56:03 +00:00
return $hookmanager -> resArray [ 'result' ];
2026-02-12 15:01:54 +00:00
}
2021-02-23 21:03:23 +00:00
}
2017-12-05 09:01:30 +00:00
2018-10-29 13:41:00 +00:00
return 2 ;
2017-12-05 09:01:30 +00:00
}
/**
2024-09-29 13:23:24 +00:00
* Return if an invoice was transferred into accountnancy .
* This is true if at least on line was transferred into table accounting_bookkeeping
2017-12-05 09:01:30 +00:00
*
2025-04-02 16:51:51 +00:00
* @ param int $mode 0 = Return nb of record , 1 = return the transaction ID ( piece_num )
* @ return int Return integer < 0 if KO , 0 = no , nb transaction = yes or ID transaction
2017-12-05 09:01:30 +00:00
*/
2025-04-02 16:51:51 +00:00
public function getVentilExportCompta ( $mode = 0 )
2017-12-05 09:01:30 +00:00
{
2026-04-20 20:17:42 +00:00
if ( ! isModEnabled ( 'accounting' )) {
return 0 ;
}
2017-12-05 09:01:30 +00:00
$alreadydispatched = 0 ;
$type = 'customer_invoice' ;
2021-02-23 21:03:23 +00:00
if ( $this -> element == 'invoice_supplier' ) {
$type = 'supplier_invoice' ;
}
2017-12-05 09:01:30 +00:00
2025-04-02 16:51:51 +00:00
$sql = " SELECT " . ( $mode ? 'DISTINCT piece_num' : 'COUNT(ab.rowid)' ) . " as nb " ;
$sql .= " FROM " . $this -> db -> prefix () . " accounting_bookkeeping as ab " ;
$sql .= " WHERE ab.doc_type = ' " . $this -> db -> escape ( $type ) . " ' AND ab.fk_doc = " . (( int ) $this -> id );
2024-09-29 13:23:24 +00:00
2017-12-05 09:01:30 +00:00
$resql = $this -> db -> query ( $sql );
2021-02-23 21:03:23 +00:00
if ( $resql ) {
2017-12-05 09:01:30 +00:00
$obj = $this -> db -> fetch_object ( $resql );
2021-02-23 21:03:23 +00:00
if ( $obj ) {
2017-12-05 09:01:30 +00:00
$alreadydispatched = $obj -> nb ;
}
2020-05-21 13:05:19 +00:00
} else {
2017-12-05 09:01:30 +00:00
$this -> error = $this -> db -> lasterror ();
return - 1 ;
}
2021-02-23 21:03:23 +00:00
if ( $alreadydispatched ) {
2025-04-02 16:51:51 +00:00
return $alreadydispatched ;
2017-12-05 09:01:30 +00:00
}
return 0 ;
}
2023-08-24 12:55:23 +00:00
/**
* Return next reference of invoice not already used ( or last reference )
*
* @ param Societe $soc Thirdparty object
* @ param string $mode 'next' for next value or 'last' for last value
* @ return string free ref or last ref
*/
public function getNextNumRef ( $soc , $mode = 'next' )
{
// TODO Must be implemented into main class
return '' ;
}
2017-12-05 09:01:30 +00:00
2012-07-11 16:13:41 +00:00
/**
2016-09-29 08:38:15 +00:00
* Return label of type of invoice
2012-07-11 16:13:41 +00:00
*
2022-09-15 01:08:33 +00:00
* @ param int $withbadge 1 = Add span for badge css , 2 = Add span and show short label
* @ return string Label of type of invoice
2012-07-11 16:13:41 +00:00
*/
2022-09-15 01:08:33 +00:00
public function getLibType ( $withbadge = 0 )
2012-07-11 16:13:41 +00:00
{
global $langs ;
2022-09-15 01:08:33 +00:00
$labellong = " Unknown " ;
2024-10-13 14:45:42 +00:00
$labelshort = " Unknown " ;
2021-02-23 21:03:23 +00:00
if ( $this -> type == CommonInvoice :: TYPE_STANDARD ) {
2022-09-15 01:08:33 +00:00
$labellong = " InvoiceStandard " ;
$labelshort = " InvoiceStandardShort " ;
2021-02-23 21:03:23 +00:00
} elseif ( $this -> type == CommonInvoice :: TYPE_REPLACEMENT ) {
2022-09-15 01:08:33 +00:00
$labellong = " InvoiceReplacement " ;
$labelshort = " InvoiceReplacementShort " ;
2021-02-23 21:03:23 +00:00
} elseif ( $this -> type == CommonInvoice :: TYPE_CREDIT_NOTE ) {
2022-09-15 01:08:33 +00:00
$labellong = " InvoiceAvoir " ;
$labelshort = " CreditNote " ;
2021-02-23 21:03:23 +00:00
} elseif ( $this -> type == CommonInvoice :: TYPE_DEPOSIT ) {
2022-09-15 01:08:33 +00:00
$labellong = " InvoiceDeposit " ;
$labelshort = " Deposit " ;
2024-08-06 23:20:43 +00:00
} elseif ( $this -> type == CommonInvoice :: TYPE_PROFORMA ) { // @phan-suppress-current-line PhanDeprecatedClassConstant
2022-09-15 01:08:33 +00:00
$labellong = " InvoiceProForma " ; // Not used.
$labelshort = " ProForma " ;
2021-02-23 21:03:23 +00:00
} elseif ( $this -> type == CommonInvoice :: TYPE_SITUATION ) {
2022-09-15 01:08:33 +00:00
$labellong = " InvoiceSituation " ;
$labelshort = " Situation " ;
}
$out = '' ;
if ( $withbadge ) {
$out .= '<span class="badgeneutral" title="' . dol_escape_htmltag ( $langs -> trans ( $labellong )) . '">' ;
}
$out .= $langs -> trans ( $withbadge == 2 ? $labelshort : $labellong );
if ( $withbadge ) {
$out .= '</span>' ;
2021-02-23 21:03:23 +00:00
}
2022-09-15 01:08:33 +00:00
return $out ;
2012-07-11 16:13:41 +00:00
}
2023-10-18 00:33:14 +00:00
/**
* Return label of invoice subtype
*
* @ param string $table table of invoice
2023-11-14 01:42:02 +00:00
* @ return string | int Label of invoice subtype or - 1 if error
2023-10-18 00:33:14 +00:00
*/
public function getSubtypeLabel ( $table = '' )
{
2023-11-14 13:43:54 +00:00
$subtypeLabel = '' ;
2023-10-18 00:33:14 +00:00
if ( $table === 'facture' || $table === 'facture_fourn' ) {
2023-11-18 23:52:16 +00:00
$sql = " SELECT s.label FROM " . $this -> db -> prefix () . $table . " AS f " ;
$sql .= " INNER JOIN " . $this -> db -> prefix () . " c_invoice_subtype AS s ON f.subtype = s.rowid " ;
2023-10-18 00:33:14 +00:00
$sql .= " WHERE f.ref = ' " . $this -> db -> escape ( $this -> ref ) . " ' " ;
2023-11-12 21:08:46 +00:00
} elseif ( $table === 'facture_rec' || $table === 'facture_fourn_rec' ) {
2023-11-18 23:52:16 +00:00
$sql = " SELECT s.label FROM " . $this -> db -> prefix () . $table . " AS f " ;
$sql .= " INNER JOIN " . $this -> db -> prefix () . " c_invoice_subtype AS s ON f.subtype = s.rowid " ;
$sql .= " WHERE f.titre = ' " . $this -> db -> escape ( $this -> title ) . " ' " ;
2023-11-14 13:43:54 +00:00
} else {
return - 1 ;
}
2023-11-12 21:08:46 +00:00
2023-11-14 13:43:54 +00:00
$resql = $this -> db -> query ( $sql );
if ( $resql ) {
while ( $obj = $this -> db -> fetch_object ( $resql )) {
$subtypeLabel = $obj -> label ;
2023-10-18 00:33:14 +00:00
}
2023-11-14 13:43:54 +00:00
} else {
dol_print_error ( $this -> db );
return - 1 ;
2023-10-18 00:33:14 +00:00
}
2023-11-14 01:42:02 +00:00
2023-11-14 13:43:54 +00:00
return $subtypeLabel ;
2023-10-18 00:33:14 +00:00
}
/**
* Retrieve a list of invoice subtype labels or codes .
*
2024-10-13 14:45:42 +00:00
* @ param int < 0 , 1 > $mode 0 = Return id + label , 1 = Return code + id
* @ return array < int , string >| array < string , int > Array of subtypes
2023-10-18 00:33:14 +00:00
*/
2023-10-18 01:33:36 +00:00
public function getArrayOfInvoiceSubtypes ( $mode = 0 )
2023-10-18 00:33:14 +00:00
{
2023-10-18 01:33:36 +00:00
global $mysoc ;
2023-10-18 00:33:14 +00:00
$effs = array ();
$sql = " SELECT rowid, code, label as label " ;
$sql .= " FROM " . MAIN_DB_PREFIX . 'c_invoice_subtype' ;
2023-10-18 01:33:36 +00:00
$sql .= " WHERE active = 1 AND fk_country = " . (( int ) $mysoc -> country_id ) . " AND entity IN( " . getEntity ( 'c_invoice_subtype' ) . " ) " ;
2023-10-18 00:33:14 +00:00
$sql .= " ORDER by rowid, code " ;
2024-04-08 10:02:31 +00:00
2023-10-18 01:33:36 +00:00
dol_syslog ( get_class ( $this ) . '::getArrayOfInvoiceSubtypes' , LOG_DEBUG );
2023-10-18 00:33:14 +00:00
$resql = $this -> db -> query ( $sql );
if ( $resql ) {
$num = $this -> db -> num_rows ( $resql );
$i = 0 ;
while ( $i < $num ) {
$objp = $this -> db -> fetch_object ( $resql );
if ( ! $mode ) {
$key = $objp -> rowid ;
$effs [ $key ] = $objp -> label ;
} else {
$key = $objp -> code ;
$effs [ $key ] = $objp -> rowid ;
}
$i ++ ;
}
$this -> db -> free ( $resql );
}
return $effs ;
}
2012-07-11 16:13:41 +00:00
/**
* Return label of object status
*
2025-01-27 20:22:52 +00:00
* @ param int $mode 0 = long label , 1 = short label , 2 = Picto + short label , 3 = Picto , 4 = Picto + long label , 5 = short label + picto , 6 = Long label + picto
* @ param int | float $alreadypaid 0 = No payment already done , > 0 = Some payments were already done ( we recommend to put here float amount paid if you have it , 1 otherwise )
* @ return string Label of status
2012-07-11 16:13:41 +00:00
*/
2019-02-25 21:27:04 +00:00
public function getLibStatut ( $mode = 0 , $alreadypaid = - 1 )
2012-07-11 16:13:41 +00:00
{
2025-04-09 17:07:31 +00:00
$moreparams = array (
'nbofopendirectdebitorcredittransfer' => $this -> nbofopendirectdebitorcredittransfer ,
'close_code' => $this -> close_code ,
'close_note' => $this -> close_note ,
2025-09-03 16:27:40 +00:00
'dispute_status' => $this -> dispute_status
2025-04-09 17:07:31 +00:00
);
return $this -> LibStatut ( $this -> paye , $this -> status , $mode , $alreadypaid , $this -> type , $moreparams );
2012-07-11 16:13:41 +00:00
}
2020-10-27 18:46:07 +00:00
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2012-07-11 16:13:41 +00:00
/**
2017-11-25 10:10:52 +00:00
* Return label of a status
2012-07-11 16:13:41 +00:00
*
2025-05-15 11:12:06 +00:00
* @ param int $paye Field to 1 if invoice is closed ( TODO Detect this using $status instead of using this param ) .
2025-04-09 17:07:31 +00:00
* @ param int $status ID status
2024-12-30 16:51:53 +00:00
* @ param int < 0 , 6 > $mode 0 = long label , 1 = short label , 2 = Picto + short label , 3 = Picto , 4 = Picto + long label , 5 = short label + picto , 6 = long label + picto
2025-01-27 20:22:52 +00:00
* @ param int | float $alreadypaid 0 = No payment already done , > 0 = Some payments were already done ( we recommend to put here float amount paid if you have it , - 1 otherwise )
2024-12-30 16:51:53 +00:00
* @ param int $type Type invoice . If - 1 , we use $this -> type
2025-04-09 17:42:45 +00:00
* @ param int | array < string , int | string > $moreparams More params . Example : array ( 'nbofopendirectdebitorcredittransfer' => x ) for nb of open direct debit or credit transfer
2024-12-30 16:51:53 +00:00
* @ return string Label of status
2012-07-11 16:13:41 +00:00
*/
2025-04-09 17:07:31 +00:00
public function LibStatut ( $paye , $status , $mode = 0 , $alreadypaid = - 1 , $type = - 1 , $moreparams = array ())
2012-07-11 16:13:41 +00:00
{
2020-10-27 18:46:07 +00:00
// phpcs:enable
2022-11-08 15:21:32 +00:00
global $langs , $hookmanager ;
2012-07-11 16:13:41 +00:00
$langs -> load ( 'bills' );
2021-02-23 21:03:23 +00:00
if ( $type == - 1 ) {
$type = $this -> type ;
}
2020-11-06 10:52:48 +00:00
2025-04-09 17:07:31 +00:00
// For backward compatibility
if ( is_int ( $moreparams )) {
$moreparams = array ( 'nbofopendirectdebitorcredittransfer' => ( int ) $moreparams );
}
$nbofopendirectdebitorcredittransfer = 0 ;
foreach ( $moreparams as $moreparamkey => $moreparamvalue ) {
if ( $moreparamkey == 'nbofopendirectdebitorcredittransfer' ) {
$nbofopendirectdebitorcredittransfer = $moreparamvalue ;
}
}
2020-04-10 08:59:32 +00:00
$statusType = 'status0' ;
$prefix = 'Short' ;
if ( ! $paye ) {
2020-10-27 18:46:07 +00:00
if ( $status == 0 ) {
$labelStatus = $langs -> transnoentitiesnoconv ( 'BillStatusDraft' );
$labelStatusShort = $langs -> transnoentitiesnoconv ( 'Bill' . $prefix . 'StatusDraft' );
} elseif (( $status == 3 || $status == 2 ) && $alreadypaid <= 0 ) {
2022-08-13 10:03:41 +00:00
if ( $status == 3 ) {
$labelStatus = $langs -> transnoentitiesnoconv ( 'BillStatusCanceled' );
$labelStatusShort = $langs -> transnoentitiesnoconv ( 'Bill' . $prefix . 'StatusCanceled' );
} else {
$labelStatus = $langs -> transnoentitiesnoconv ( 'BillStatusClosedUnpaid' );
$labelStatusShort = $langs -> transnoentitiesnoconv ( 'Bill' . $prefix . 'StatusClosedUnpaid' );
}
2020-10-27 18:46:07 +00:00
$statusType = 'status5' ;
} elseif (( $status == 3 || $status == 2 ) && $alreadypaid > 0 ) {
$labelStatus = $langs -> transnoentitiesnoconv ( 'BillStatusClosedPaidPartially' );
$labelStatusShort = $langs -> transnoentitiesnoconv ( 'Bill' . $prefix . 'StatusClosedPaidPartially' );
$statusType = 'status9' ;
2024-12-30 15:50:22 +00:00
} elseif ( $alreadypaid == 0 && $nbofopendirectdebitorcredittransfer == 0 ) {
2020-10-27 18:46:07 +00:00
$labelStatus = $langs -> transnoentitiesnoconv ( 'BillStatusNotPaid' );
$labelStatusShort = $langs -> transnoentitiesnoconv ( 'Bill' . $prefix . 'StatusNotPaid' );
$statusType = 'status1' ;
} else {
$labelStatus = $langs -> transnoentitiesnoconv ( 'BillStatusStarted' );
$labelStatusShort = $langs -> transnoentitiesnoconv ( 'Bill' . $prefix . 'StatusStarted' );
$statusType = 'status3' ;
}
2020-05-21 13:05:19 +00:00
} else {
2020-10-27 18:46:07 +00:00
$statusType = 'status6' ;
if ( $type == self :: TYPE_CREDIT_NOTE ) {
$labelStatus = $langs -> transnoentitiesnoconv ( 'BillStatusPaidBackOrConverted' ); // credit note
$labelStatusShort = $langs -> transnoentitiesnoconv ( 'Bill' . $prefix . 'StatusPaidBackOrConverted' ); // credit note
} elseif ( $type == self :: TYPE_DEPOSIT ) {
$labelStatus = $langs -> transnoentitiesnoconv ( 'BillStatusConverted' ); // deposit invoice
$labelStatusShort = $langs -> transnoentitiesnoconv ( 'Bill' . $prefix . 'StatusConverted' ); // deposit invoice
} else {
$labelStatus = $langs -> transnoentitiesnoconv ( 'BillStatusPaid' );
$labelStatusShort = $langs -> transnoentitiesnoconv ( 'Bill' . $prefix . 'StatusPaid' );
}
2012-07-11 16:13:41 +00:00
}
2019-03-15 22:00:50 +00:00
2025-10-16 23:55:11 +00:00
$paramsBadge = array ( 'badgeParams' => array ( 'attr' => array (
'data-status-element' => $this -> element ,
'data-already-paid' => $alreadypaid > 0 ? 1 : 0 ,
'data-status' => ( int ) $status
)));
2022-11-08 15:24:05 +00:00
$parameters = array (
'status' => $status ,
'mode' => $mode ,
'paye' => $paye ,
'alreadypaid' => $alreadypaid ,
2025-10-16 23:55:11 +00:00
'type' => $type ,
2026-04-20 10:38:14 +00:00
'paramsBadge' => & $paramsBadge
2022-11-08 15:24:05 +00:00
);
$reshook = $hookmanager -> executeHooks ( 'LibStatut' , $parameters , $this ); // Note that $action and $object may have been modified by hook
if ( $reshook > 0 ) {
2022-11-08 15:21:32 +00:00
return $hookmanager -> resPrint ;
}
2025-04-20 11:21:48 +00:00
if ( ! empty ( $moreparams [ 'close_code' ])) {
2025-04-09 17:07:31 +00:00
$titlestringtoshow = '' ;
if ( $moreparams [ 'close_code' ] == self :: CLOSECODE_DISCOUNTVAT ) {
$titlestringtoshow = $langs -> trans ( " HelpEscompte " );
} elseif ( $moreparams [ 'close_code' ] == self :: CLOSECODE_BADDEBT ) {
$titlestringtoshow = $langs -> trans ( " ConfirmClassifyPaidPartiallyReasonBadCustomer " );
} elseif ( $moreparams [ 'close_code' ] == self :: CLOSECODE_BANKCHARGE ) {
$titlestringtoshow = $langs -> trans ( " ConfirmClassifyPaidPartiallyReasonBankCharge " );
} elseif ( $moreparams [ 'close_code' ] == self :: CLOSECODE_WITHHOLDINGTAX ) {
$titlestringtoshow = $langs -> trans ( " ConfirmClassifyPaidPartiallyReasonWithholdingTax " );
} elseif ( $moreparams [ 'close_code' ] == self :: CLOSECODE_OTHER ) {
$titlestringtoshow = $langs -> trans ( " Other " );
}
//$paramsbutton = array('badgeParams' => array('attr' => array('title' => 'rrrr')));
2025-10-16 23:55:11 +00:00
$paramsBadge [ 'badgeParams' ][ 'attr' ][ 'title' ] = $titlestringtoshow ;
2025-04-09 17:07:31 +00:00
}
2025-10-09 16:18:49 +00:00
if ( isset ( $moreparams [ 'dispute_status' ]) && $moreparams [ 'dispute_status' ]) {
2026-01-16 15:28:07 +00:00
$labelStatus .= ' - ' ;
2026-01-16 15:51:15 +00:00
if ( $moreparams [ 'dispute_status' ] == 8 ) {
$labelStatus .= $langs -> trans ( " DisputeLost " );
} elseif ( $moreparams [ 'dispute_status' ] == 9 ) {
$labelStatus .= $langs -> trans ( " DisputeWon " );
2026-01-16 15:28:07 +00:00
} else {
$labelStatus .= $langs -> trans ( " DisputeOpen " );
2026-01-16 15:29:26 +00:00
$statusType = 'status8' ;
2026-01-16 15:28:07 +00:00
}
2025-10-08 14:35:17 +00:00
}
2025-10-16 23:55:11 +00:00
$statusbadge = dolGetStatus ( $labelStatus , $labelStatusShort , '' , $statusType , $mode , '' , $paramsBadge );
2025-09-03 16:27:40 +00:00
return $statusbadge ;
2012-07-11 16:13:41 +00:00
}
2014-06-14 10:53:02 +00:00
2020-10-27 18:46:07 +00:00
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2014-06-14 10:53:02 +00:00
/**
2019-10-19 16:33:06 +00:00
* Returns an invoice payment deadline based on the invoice settlement
* conditions and billing date .
2014-06-14 10:53:02 +00:00
*
2024-01-31 20:12:21 +00:00
* @ param int $cond_reglement Condition of payment ( code or id ) to use . If 0 , we use current condition .
* @ return int | string Date limit of payment if OK , < 0 or string if KO
2014-06-14 10:53:02 +00:00
*/
2020-10-27 18:46:07 +00:00
public function calculate_date_lim_reglement ( $cond_reglement = 0 )
2014-06-14 10:53:02 +00:00
{
2020-10-27 18:46:07 +00:00
// phpcs:enable
2021-02-23 21:03:23 +00:00
if ( ! $cond_reglement ) {
$cond_reglement = $this -> cond_reglement_code ;
}
if ( ! $cond_reglement ) {
$cond_reglement = $this -> cond_reglement_id ;
}
2023-02-21 11:14:34 +00:00
if ( ! $cond_reglement ) {
return $this -> date ;
}
2014-06-14 10:53:02 +00:00
2020-04-10 08:59:32 +00:00
$cdr_nbjour = 0 ;
2020-10-27 18:46:07 +00:00
$cdr_type = 0 ;
$cdr_decalage = 0 ;
2014-06-14 10:53:02 +00:00
2022-01-27 11:52:13 +00:00
$sqltemp = " SELECT c.type_cdr, c.nbjour, c.decalage " ;
$sqltemp .= " FROM " . $this -> db -> prefix () . " c_payment_term as c " ;
2021-02-23 21:03:23 +00:00
if ( is_numeric ( $cond_reglement )) {
2021-04-24 18:18:11 +00:00
$sqltemp .= " WHERE c.rowid= " . (( int ) $cond_reglement );
2021-02-23 21:03:23 +00:00
} else {
2020-04-10 08:59:32 +00:00
$sqltemp .= " WHERE c.entity IN ( " . getEntity ( 'c_payment_term' ) . " ) " ;
2021-04-24 18:18:11 +00:00
$sqltemp .= " AND c.code = ' " . $this -> db -> escape ( $cond_reglement ) . " ' " ;
2018-03-07 16:32:57 +00:00
}
2014-06-14 10:53:02 +00:00
2014-07-02 19:29:07 +00:00
dol_syslog ( get_class ( $this ) . '::calculate_date_lim_reglement' , LOG_DEBUG );
2020-04-10 08:59:32 +00:00
$resqltemp = $this -> db -> query ( $sqltemp );
2021-02-23 21:03:23 +00:00
if ( $resqltemp ) {
if ( $this -> db -> num_rows ( $resqltemp )) {
2014-06-14 10:53:02 +00:00
$obj = $this -> db -> fetch_object ( $resqltemp );
$cdr_nbjour = $obj -> nbjour ;
2016-10-04 13:45:23 +00:00
$cdr_type = $obj -> type_cdr ;
2014-06-14 10:53:02 +00:00
$cdr_decalage = $obj -> decalage ;
}
2020-05-21 13:05:19 +00:00
} else {
2020-04-10 08:59:32 +00:00
$this -> error = $this -> db -> error ();
2014-06-14 10:53:02 +00:00
return - 1 ;
}
$this -> db -> free ( $resqltemp );
2026-02-17 14:32:16 +00:00
/* Define date limit */
2014-06-14 10:53:02 +00:00
2019-10-19 16:33:06 +00:00
// 0 : adding the number of days
2021-02-23 21:03:23 +00:00
if ( $cdr_type == 0 ) {
2018-10-04 14:06:26 +00:00
$datelim = $this -> date + ( $cdr_nbjour * 3600 * 24 );
2014-06-14 10:53:02 +00:00
2018-10-04 14:06:26 +00:00
$datelim += ( $cdr_decalage * 3600 * 24 );
2021-03-01 19:37:16 +00:00
} elseif ( $cdr_type == 1 ) {
// 1 : application of the "end of the month" rule
2018-10-04 14:06:26 +00:00
$datelim = $this -> date + ( $cdr_nbjour * 3600 * 24 );
2020-04-10 08:59:32 +00:00
$mois = date ( 'm' , $datelim );
$annee = date ( 'Y' , $datelim );
2021-02-23 21:03:23 +00:00
if ( $mois == 12 ) {
2014-06-14 10:53:02 +00:00
$mois = 1 ;
$annee += 1 ;
2020-05-21 13:05:19 +00:00
} else {
2014-06-14 10:53:02 +00:00
$mois += 1 ;
}
2019-10-19 16:33:06 +00:00
// We move at the beginning of the next month, and we take a day off
2020-04-10 08:59:32 +00:00
$datelim = dol_mktime ( 12 , 0 , 0 , $mois , 1 , $annee );
2014-06-14 10:53:02 +00:00
$datelim -= ( 3600 * 24 );
2018-10-04 14:06:26 +00:00
$datelim += ( $cdr_decalage * 3600 * 24 );
2021-03-01 19:37:16 +00:00
} elseif ( $cdr_type == 2 && ! empty ( $cdr_decalage )) {
// 2 : application of the rule, the N of the current or next month
2020-10-27 18:46:07 +00:00
include_once DOL_DOCUMENT_ROOT . '/core/lib/date.lib.php' ;
2018-10-04 14:06:26 +00:00
$datelim = $this -> date + ( $cdr_nbjour * 3600 * 24 );
2017-06-09 07:25:15 +00:00
2024-08-16 18:13:02 +00:00
$date_piece = dol_mktime ( 0 , 0 , 0 , ( int ) date ( 'm' , $datelim ), ( int ) date ( 'd' , $datelim ), ( int ) date ( 'Y' , $datelim )); // Sans les heures minutes et secondes
$date_lim_current = dol_mktime ( 0 , 0 , 0 , ( int ) date ( 'm' , $datelim ), ( int ) $cdr_decalage , ( int ) date ( 'Y' , $datelim )); // Sans les heures minutes et secondes
$date_lim_next = dol_time_plus_duree (( int ) $date_lim_current , 1 , 'm' ); // Add 1 month
2017-06-09 07:25:15 +00:00
2016-10-04 13:45:23 +00:00
$diff = $date_piece - $date_lim_current ;
2017-06-09 07:25:15 +00:00
2026-01-07 19:21:07 +00:00
if ( $diff <= 0 ) {
2021-02-23 21:03:23 +00:00
$datelim = $date_lim_current ;
} else {
$datelim = $date_lim_next ;
}
2020-06-27 00:00:42 +00:00
} else {
return 'Bad value for type_cdr in database for record cond_reglement = ' . $cond_reglement ;
}
2014-06-14 10:53:02 +00:00
return $datelim ;
}
2020-06-24 17:59:06 +00:00
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
/**
* Create a withdrawal request for a direct debit order or a credit transfer order .
* Use the remain to pay excluding all existing open direct debit requests .
*
2024-10-30 22:15:33 +00:00
* @ param User $fuser User asking the direct debit transfer
* @ param float $amount Amount we request direct debit for
* @ param string $type 'direct-debit' or 'bank-transfer'
* @ param string $sourcetype Source ( 'facture' or 'supplier_invoice' )
* @ param int $checkduplicateamongall 0 = Default ( check among open requests only to find if request already exists ) . 1 = Check also among requests completely processed and cancel if at least 1 request exists whatever is its status .
* @ param int $ribId If defined , will use this ID to get the RIB . Otherwise , the default RIB will be taken .
* @ return int Return integer < 0 if KO , 0 if a request already exists , > 0 if OK
2020-06-24 17:59:06 +00:00
*/
2024-10-30 22:15:33 +00:00
public function demande_prelevement ( User $fuser , float $amount = 0 , string $type = 'direct-debit' , string $sourcetype = 'facture' , int $checkduplicateamongall = 0 , int $ribId = 0 )
2020-06-24 17:59:06 +00:00
{
// phpcs:enable
global $conf ;
$error = 0 ;
dol_syslog ( get_class ( $this ) . " ::demande_prelevement " , LOG_DEBUG );
2023-08-10 10:57:31 +00:00
if ( $this -> status > self :: STATUS_DRAFT && $this -> paye == 0 ) {
2020-06-24 17:59:06 +00:00
require_once DOL_DOCUMENT_ROOT . '/societe/class/companybankaccount.class.php' ;
$bac = new CompanyBankAccount ( $this -> db );
2024-10-30 22:15:33 +00:00
$bac -> fetch ( $ribId , '' , $this -> socid );
2020-06-24 17:59:06 +00:00
2026-02-24 17:06:31 +00:00
// Option to allow multiple partial requests
// If WITHDRAW_STRICT_CHECK_AMOUNT is enabled, we check the sum of amounts instead of just counting requests
if ( getDolGlobalString ( 'WITHDRAW_STRICT_CHECK_AMOUNT' )) {
// Calculate sum of amounts already requested instead of just counting requests
// This allows multiple partial requests as long as the total doesn't exceed the remain to pay
$total_already_requested = 0 ;
// Step 1: Get pending requests with no transfer receipt yet (traite = 0)
$sql = " SELECT COALESCE(SUM(amount), 0) as total_requested " ;
$sql .= " FROM " . $this -> db -> prefix () . " prelevement_demande " ;
if ( $type == 'bank-transfer' ) {
$sql .= " WHERE fk_facture_fourn = " . (( int ) $this -> id );
} else {
$sql .= " WHERE fk_facture = " . (( int ) $this -> id );
}
$sql .= " AND type = 'ban' " ; // To exclude record done for some online payments
$sql .= " AND traite = 0 " ; // Not yet in a transfer receipt
dol_syslog ( get_class ( $this ) . " ::demande_prelevement - get pending requests not yet in receipt " , LOG_DEBUG );
2026-04-20 10:38:14 +00:00
$resql = $this -> db -> query ( $sql );
2026-02-24 17:06:31 +00:00
if ( $resql ) {
$obj = $this -> db -> fetch_object ( $resql );
$total_already_requested += $obj ? ( float ) $obj -> total_requested : 0 ;
} else {
$this -> error = $this -> db -> error ();
dol_syslog ( get_class ( $this ) . '::demandeprelevement Error -2a' );
return - 2 ;
}
// Step 2: Get pending requests in transfer receipt but not yet credited
$sql = " SELECT COALESCE(SUM(pl.amount), 0) as total_requested " ;
$sql .= " FROM " . $this -> db -> prefix () . " prelevement_lignes as pl " ;
$sql .= " INNER JOIN " . $this -> db -> prefix () . " prelevement as p ON p.fk_prelevement_lignes = pl.rowid " ;
if ( $type == 'bank-transfer' ) {
$sql .= " WHERE p.fk_facture_fourn = " . (( int ) $this -> id );
} else {
$sql .= " WHERE p.fk_facture = " . (( int ) $this -> id );
}
$sql .= " AND (pl.statut IS NULL OR pl.statut = 0) " ; // Not yet processed (statut 2 = credited)
dol_syslog ( get_class ( $this ) . " ::demande_prelevement - get requests in non-credited receipts " , LOG_DEBUG );
$resql = $this -> db -> query ( $sql );
if ( $resql ) {
$obj = $this -> db -> fetch_object ( $resql );
$total_already_requested += $obj ? ( float ) $obj -> total_requested : 0 ;
// Calculate remain to pay
$totalpaid = $this -> getSommePaiement ();
$totalcreditnotes = $this -> getSumCreditNotesUsed ();
$totaldeposits = $this -> getSumDepositsUsed ();
$resteapayer = ( float ) price2num ( $this -> total_ttc - $totalpaid - $totalcreditnotes - $totaldeposits , 'MT' );
// Calculate remaining amount available for new requests
$remaining_for_request = ( float ) price2num ( $resteapayer - $total_already_requested , 'MT' );
// If no amount specified, use the remaining available
if ( empty ( $amount )) {
$amount = $remaining_for_request ;
}
// Check if there's still room for new requests
$can_create_request = ( $remaining_for_request > 0 && $amount <= $remaining_for_request );
} else {
$this -> error = $this -> db -> error ();
dol_syslog ( get_class ( $this ) . '::demandeprelevement Error -2b' );
return - 2 ;
}
2020-06-24 17:59:06 +00:00
} else {
2026-02-24 17:06:31 +00:00
// Original behavior: only check if a request already exists (count)
$sql = " SELECT count(rowid) as nb " ;
$sql .= " FROM " . $this -> db -> prefix () . " prelevement_demande " ;
if ( $type == 'bank-transfer' ) {
$sql .= " WHERE fk_facture_fourn = " . (( int ) $this -> id );
} else {
$sql .= " WHERE fk_facture = " . (( int ) $this -> id );
}
$sql .= " AND type = 'ban' " ; // To exclude record done for some online payments
if ( empty ( $checkduplicateamongall )) {
$sql .= " AND traite = 0 " ;
}
2020-06-24 17:59:06 +00:00
2026-02-24 17:06:31 +00:00
dol_syslog ( get_class ( $this ) . " ::demande_prelevement " , LOG_DEBUG );
2023-08-14 13:40:22 +00:00
2026-02-24 17:06:31 +00:00
$resql = $this -> db -> query ( $sql );
if ( $resql ) {
$obj = $this -> db -> fetch_object ( $resql );
$can_create_request = ( $obj && $obj -> nb == 0 );
// Calculate amount if not specified
2021-02-23 21:03:23 +00:00
if ( empty ( $amount )) {
2026-02-24 17:06:31 +00:00
$totalpaid = $this -> getSommePaiement ();
$totalcreditnotes = $this -> getSumCreditNotesUsed ();
$totaldeposits = $this -> getSumDepositsUsed ();
//print "totalpaid=".$totalpaid." totalcreditnotes=".$totalcreditnotes." totaldeposts=".$totaldeposits;
// We can also use bcadd to avoid pb with floating points
// For example print 239.2 - 229.3 - 9.9; does not return 0.
//$resteapayer=bcadd($this->total_ttc,$totalpaid,$conf->global->MAIN_MAX_DECIMALS_TOT);
//$resteapayer=bcadd($resteapayer,$totalavoir,$conf->global->MAIN_MAX_DECIMALS_TOT);
2022-05-22 15:09:08 +00:00
$amount = price2num ( $this -> total_ttc - $totalpaid - $totalcreditnotes - $totaldeposits , 'MT' );
2021-02-23 21:03:23 +00:00
}
2026-02-24 17:06:31 +00:00
$remaining_for_request = $amount ; // For error message compatibility
} else {
$this -> error = $this -> db -> error ();
dol_syslog ( get_class ( $this ) . '::demandeprelevement Error -2' );
return - 2 ;
}
}
// Common code for both modes
if ( $can_create_request ) {
$now = dol_now ();
if ( is_numeric ( $amount ) && $amount != 0 ) {
$sql = 'INSERT INTO ' . $this -> db -> prefix () . 'prelevement_demande(' ;
if ( $type == 'bank-transfer' ) {
$sql .= 'fk_facture_fourn, ' ;
2020-06-27 00:00:42 +00:00
} else {
2026-02-24 17:06:31 +00:00
$sql .= 'fk_facture, ' ;
2020-06-24 17:59:06 +00:00
}
2026-02-24 17:06:31 +00:00
$sql .= ' amount, date_demande, fk_user_demande, code_banque, code_guichet, number, cle_rib, sourcetype, type, entity' ;
if ( empty ( $bac -> id )) {
$sql .= ')' ;
} else {
$sql .= ', fk_societe_rib)' ;
2020-06-24 17:59:06 +00:00
}
2026-02-24 17:06:31 +00:00
$sql .= " VALUES ( " . (( int ) $this -> id );
$sql .= " , " . (( float ) price2num ( $amount ));
$sql .= " , ' " . $this -> db -> idate ( $now ) . " ' " ;
$sql .= " , " . (( int ) $fuser -> id );
$sql .= " , ' " . $this -> db -> escape ( $bac -> code_banque ) . " ' " ;
$sql .= " , ' " . $this -> db -> escape ( $bac -> code_guichet ) . " ' " ;
$sql .= " , ' " . $this -> db -> escape ( $bac -> number ) . " ' " ;
$sql .= " , ' " . $this -> db -> escape ( $bac -> cle_rib ) . " ' " ;
$sql .= " , ' " . $this -> db -> escape ( $sourcetype ) . " ' " ;
$sql .= " , 'ban' " ;
$sql .= " , " . (( int ) $conf -> entity );
if ( ! empty ( $bac -> id )) {
$sql .= " , ' " . $this -> db -> escape (( string ) $bac -> id ) . " ' " ;
}
$sql .= " ) " ;
dol_syslog ( get_class ( $this ) . " ::demande_prelevement " , LOG_DEBUG );
$resql = $this -> db -> query ( $sql );
if ( ! $resql ) {
$this -> error = $this -> db -> lasterror ();
dol_syslog ( get_class ( $this ) . '::demandeprelevement Erreur' );
$error ++ ;
2021-02-23 21:03:23 +00:00
}
2020-06-27 00:00:42 +00:00
} else {
2026-02-24 17:06:31 +00:00
$this -> error = 'WithdrawRequestErrorNilAmount' ;
dol_syslog ( get_class ( $this ) . '::demandeprelevement WithdrawRequestErrorNilAmount' );
$error ++ ;
}
if ( ! $error ) {
// Force payment mode of invoice to withdraw
$payment_mode_id = dol_getIdFromCode ( $this -> db , ( $type == 'bank-transfer' ? 'VIR' : 'PRE' ), 'c_paiement' , 'code' , 'id' , 1 );
if ( $payment_mode_id > 0 ) {
$result = $this -> setPaymentMethods ( $payment_mode_id );
}
2020-06-24 17:59:06 +00:00
}
2026-02-24 17:06:31 +00:00
if ( $error ) {
return - 1 ;
}
return 1 ;
2020-06-27 00:00:42 +00:00
} else {
2026-02-24 17:06:31 +00:00
// Updated error message for when amount exceeds remaining or request already exists
if ( getDolGlobalString ( 'WITHDRAW_STRICT_CHECK_AMOUNT' )) {
if ( $remaining_for_request <= 0 ) {
$this -> error = " AmountRequestedAlreadyReachesTotal " ;
} else {
$this -> error = " AmountExceedsRemainingToRequest " ;
}
} else {
$this -> error = " A request already exists " ;
}
return 0 ;
2020-06-24 17:59:06 +00:00
}
2020-06-27 00:00:42 +00:00
} else {
2020-06-24 17:59:06 +00:00
$this -> error = " Status of invoice does not allow this " ;
2023-08-10 10:57:31 +00:00
dol_syslog ( get_class ( $this ) . " ::demandeprelevement " . $this -> error . " $this->status , $this->paye , $this->mode_reglement_id " );
2020-06-24 17:59:06 +00:00
return - 3 ;
}
}
2022-09-09 02:10:48 +00:00
2023-08-03 22:13:29 +00:00
/**
* Create a payment with Stripe card
* Must take amount using Stripe and record an event into llx_actioncomm
* Record bank payment
* Send email to customer ?
*
* @ param User $fuser User asking the direct debit transfer
* @ param int $id Invoice ID with remain to pay
* @ param string $sourcetype Source ( 'facture' or 'supplier_invoice' )
2023-12-01 18:51:32 +00:00
* @ return int Return integer < 0 if KO , > 0 if OK
2023-08-03 22:13:29 +00:00
*/
public function makeStripeCardRequest ( $fuser , $id , $sourcetype = 'facture' )
{
// TODO See in sellyoursaas
2023-12-01 22:15:10 +00:00
return 0 ;
2023-08-03 22:13:29 +00:00
}
2022-09-09 02:10:48 +00:00
/**
2023-08-23 23:37:04 +00:00
* Create a direct debit order into prelevement_bons for a given prelevement_request , then
* Send the payment order to the service ( for a direct debit order or a credit transfer order ) and record an event in llx_actioncomm .
2022-09-09 02:10:48 +00:00
*
* @ param User $fuser User asking the direct debit transfer
2023-02-24 22:15:54 +00:00
* @ param int $did ID of unitary payment request to pay
2022-09-09 02:10:48 +00:00
* @ param string $type 'direct-debit' or 'bank-transfer'
* @ param string $sourcetype Source ( 'facture' or 'supplier_invoice' )
2023-08-23 23:37:04 +00:00
* @ param string $service 'StripeTest' , 'StripeLive' , ...
2023-08-25 19:57:16 +00:00
* @ param string $forcestripe To force another stripe env : 'cus_account@pk_...:sk_...'
2023-12-01 18:51:32 +00:00
* @ return int Return integer < 0 if KO , > 0 if OK
2022-09-09 02:10:48 +00:00
*/
2023-08-23 23:37:04 +00:00
public function makeStripeSepaRequest ( $fuser , $did , $type = 'direct-debit' , $sourcetype = 'facture' , $service = '' , $forcestripe = '' )
2022-09-09 02:10:48 +00:00
{
2023-08-03 22:13:29 +00:00
global $conf , $user , $langs ;
2022-09-09 02:10:48 +00:00
2023-11-27 10:24:19 +00:00
if ( $type != 'bank-transfer' && $type != 'credit-transfer' && ! getDolGlobalString ( 'STRIPE_SEPA_DIRECT_DEBIT' )) {
2023-03-04 11:16:38 +00:00
return 0 ;
}
2023-11-27 10:24:19 +00:00
if ( $type != 'direct-debit' && ! getDolGlobalString ( 'STRIPE_SEPA_CREDIT_TRANSFER' )) {
2022-09-09 02:10:48 +00:00
return 0 ;
}
2023-08-23 23:37:04 +00:00
// Set a default value for service if not provided
if ( empty ( $service )) {
$service = 'StripeTest' ;
2025-07-10 17:47:58 +00:00
if ( getDolGlobalString ( 'STRIPE_LIVE' ) /* && !GETPOST('forcesandbox', 'alpha')*/ ) {
2023-08-23 23:37:04 +00:00
$service = 'StripeLive' ;
}
}
2022-09-09 02:10:48 +00:00
$error = 0 ;
2023-08-25 17:18:23 +00:00
dol_syslog ( get_class ( $this ) . " ::makeStripeSepaRequest start did= " . $did . " type= " . $type . " service= " . $service . " sourcetype= " . $sourcetype . " forcestripe= " . $forcestripe , LOG_DEBUG );
2022-09-09 02:10:48 +00:00
2023-08-10 10:57:31 +00:00
if ( $this -> status > self :: STATUS_DRAFT && $this -> paye == 0 ) {
2023-02-27 14:58:15 +00:00
// Get the default payment mode for BAN payment of the third party
2022-09-09 02:10:48 +00:00
require_once DOL_DOCUMENT_ROOT . '/societe/class/companybankaccount.class.php' ;
2024-04-24 19:53:40 +00:00
$bac = new CompanyBankAccount ( $this -> db ); // Table societe_rib
2024-04-27 10:45:50 +00:00
$result = $bac -> fetch ( 0 , '' , $this -> socid , 1 , 'ban' );
2022-10-13 03:31:36 +00:00
if ( $result <= 0 || empty ( $bac -> id )) {
2025-09-11 23:52:18 +00:00
$this -> error = $langs -> trans ( " ThirdpartyHasNoDefaultBankAccount " );
2022-10-13 03:31:36 +00:00
$this -> errors [] = $this -> error ;
dol_syslog ( get_class ( $this ) . " ::makeStripeSepaRequest " . $this -> error );
return - 1 ;
}
2022-09-09 02:10:48 +00:00
2023-08-10 10:57:31 +00:00
// Load the pending payment request to process (with rowid=$did)
2023-12-14 13:48:22 +00:00
$sql = " SELECT rowid, date_demande, amount, fk_facture, fk_facture_fourn, fk_salary, fk_prelevement_bons " ;
2022-10-28 15:51:25 +00:00
$sql .= " FROM " . $this -> db -> prefix () . " prelevement_demande " ;
2022-10-13 03:31:36 +00:00
$sql .= " WHERE rowid = " . (( int ) $did );
2023-03-08 02:16:59 +00:00
if ( $type != 'bank-transfer' && $type != 'credit-transfer' ) {
2023-12-14 13:48:22 +00:00
$sql .= " AND fk_facture = " . (( int ) $this -> id ); // Add a protection to not pay another invoice than current one
2023-03-04 11:16:38 +00:00
}
2023-03-08 02:16:59 +00:00
if ( $type != 'direct-debit' ) {
2024-03-03 17:55:30 +00:00
if ( $sourcetype == 'salary' ) {
2023-12-14 13:48:22 +00:00
$sql .= " AND fk_salary = " . (( int ) $this -> id ); // Add a protection to not pay another salary than current one
} else {
$sql .= " AND fk_facture_fourn = " . (( int ) $this -> id ); // Add a protection to not pay another invoice than current one
}
2023-03-04 11:16:38 +00:00
}
2023-08-03 21:00:39 +00:00
$sql .= " AND traite = 0 " ; // To not process payment request that were already converted into a direct debit or credit transfer order (Note: fk_prelevement_bons is also empty when traite = 0)
2022-09-09 02:10:48 +00:00
2023-02-24 22:15:54 +00:00
dol_syslog ( get_class ( $this ) . " ::makeStripeSepaRequest load requests to process " , LOG_DEBUG );
2022-09-09 02:10:48 +00:00
$resql = $this -> db -> query ( $sql );
if ( $resql ) {
2022-10-13 03:31:36 +00:00
$obj = $this -> db -> fetch_object ( $resql );
if ( ! $obj ) {
dol_print_error ( $this -> db , 'CantFindRequestWithId' );
return - 2 ;
}
2022-09-09 02:10:48 +00:00
2023-02-24 22:15:54 +00:00
// amount to pay
2022-10-13 03:31:36 +00:00
$amount = $obj -> amount ;
2022-09-09 02:10:48 +00:00
2022-10-13 03:31:36 +00:00
if ( is_numeric ( $amount ) && $amount != 0 ) {
require_once DOL_DOCUMENT_ROOT . '/societe/class/companypaymentmode.class.php' ;
2023-02-24 22:15:54 +00:00
$companypaymentmode = new CompanyPaymentMode ( $this -> db ); // table societe_rib
2022-10-13 03:31:36 +00:00
$companypaymentmode -> fetch ( $bac -> id );
2022-09-09 02:10:48 +00:00
2022-10-13 03:31:36 +00:00
$this -> stripechargedone = 0 ;
$this -> stripechargeerror = 0 ;
2023-02-24 22:15:54 +00:00
2022-10-13 03:31:36 +00:00
$now = dol_now ();
2022-09-09 02:10:48 +00:00
2022-10-13 03:31:36 +00:00
$currency = $conf -> currency ;
2022-09-09 02:10:48 +00:00
2022-10-13 03:31:36 +00:00
$errorforinvoice = 0 ; // We reset the $errorforinvoice at each invoice loop
2022-09-09 02:10:48 +00:00
2022-10-13 03:31:36 +00:00
$this -> fetch_thirdparty ();
2022-09-09 02:10:48 +00:00
2024-01-17 23:42:43 +00:00
dol_syslog ( " makeStripeSepaRequest Process payment request amount= " . $amount . " thirdparty_id= " . $this -> thirdparty -> id . " , thirdparty_name= " . $this -> thirdparty -> name . " ban id= " . $bac -> id , LOG_DEBUG );
2022-09-09 02:10:48 +00:00
2023-02-24 22:15:54 +00:00
//$alreadypayed = $this->getSommePaiement();
//$amount_credit_notes_included = $this->getSumCreditNotesUsed();
//$amounttopay = $this->total_ttc - $alreadypayed - $amount_credit_notes_included;
$amounttopay = $amount ;
2022-09-09 02:10:48 +00:00
2022-10-13 03:31:36 +00:00
// Correct the amount according to unit of currency
// See https://support.stripe.com/questions/which-zero-decimal-currencies-does-stripe-support
$arrayzerounitcurrency = [ 'BIF' , 'CLP' , 'DJF' , 'GNF' , 'JPY' , 'KMF' , 'KRW' , 'MGA' , 'PYG' , 'RWF' , 'VND' , 'VUV' , 'XAF' , 'XOF' , 'XPF' ];
$amountstripe = $amounttopay ;
if ( ! in_array ( $currency , $arrayzerounitcurrency )) {
2024-08-07 00:53:45 +00:00
$amountstripe *= 100 ;
2022-10-13 03:31:36 +00:00
}
2022-09-09 02:10:48 +00:00
2023-03-04 11:16:38 +00:00
$fk_bank_account = getDolGlobalInt ( 'STRIPE_BANK_ACCOUNT_FOR_PAYMENTS' ); // Bank account used for SEPA direct debit or credit transfer. Must be the Stripe account in Dolibarr.
2023-02-27 14:58:15 +00:00
if ( ! ( $fk_bank_account > 0 )) {
$error ++ ;
$errorforinvoice ++ ;
2024-01-17 23:42:43 +00:00
dol_syslog ( " makeStripeSepaRequest Error no bank account defined for Stripe payments " , LOG_ERR );
2025-01-02 16:32:36 +00:00
$this -> error = " Error bank account for Stripe payments not defined into Stripe module " ;
$this -> errors [] = $this -> error ;
2023-02-27 14:58:15 +00:00
}
2023-02-24 22:15:54 +00:00
$this -> db -> begin ();
// Create a prelevement_bon
2023-05-12 09:20:25 +00:00
require_once DOL_DOCUMENT_ROOT . '/compta/prelevement/class/bonprelevement.class.php' ;
2023-02-24 22:15:54 +00:00
$bon = new BonPrelevement ( $this -> db );
2023-02-27 14:58:15 +00:00
if ( ! $error ) {
if ( empty ( $obj -> fk_prelevement_bons )) {
2023-08-10 10:57:31 +00:00
// This creates a record into llx_prelevement_bons and updates link with llx_prelevement_demande
2025-03-15 15:34:35 +00:00
$nbinvoices = $bon -> create ( '0' , '0' , 'real' , 'ALL' , 0 , 0 , $type , $did , $fk_bank_account );
2023-02-27 14:58:15 +00:00
if ( $nbinvoices <= 0 ) {
2023-02-24 22:15:54 +00:00
$error ++ ;
2023-02-27 14:58:15 +00:00
$errorforinvoice ++ ;
2024-01-17 23:42:43 +00:00
dol_syslog ( " makeStripeSepaRequest Error on BonPrelevement creation " , LOG_ERR );
2025-01-02 16:32:36 +00:00
$this -> error = " Error on BonPrelevement creation " ;
$this -> errors [] = $this -> error ;
2023-02-27 14:58:15 +00:00
}
/*
if ( ! $error ) {
// Update the direct debit payment request of the processed request to save the id of the prelevement_bon
$sql = " UPDATE " . MAIN_DB_PREFIX . " prelevement_demande SET " ;
$sql .= " fk_prelevement_bons = " . (( int ) $bon -> id );
$sql .= " WHERE rowid = " . (( int ) $did );
$result = $this -> db -> query ( $sql );
if ( $result < 0 ) {
$error ++ ;
2025-01-02 16:32:36 +00:00
$this -> error = " Error on updating fk_prelevement_bons to " . $bon -> id ;
$this -> errors [] = $this -> error ;
2023-02-27 14:58:15 +00:00
}
2023-02-24 22:15:54 +00:00
}
2023-02-27 14:58:15 +00:00
*/
} else {
$error ++ ;
$errorforinvoice ++ ;
2024-01-17 23:42:43 +00:00
dol_syslog ( " makeStripeSepaRequest Error Line already part of a bank payment order " , LOG_ERR );
2025-01-02 16:32:36 +00:00
$this -> error = " The line is already included into a bank payment order. Delete the bank payment order first. " ;
$this -> errors [] = $this -> error ;
2023-02-24 22:15:54 +00:00
}
}
2024-10-13 14:45:42 +00:00
$paymentintent = null ;
2023-02-27 14:58:15 +00:00
if ( ! $error ) {
if ( $amountstripe > 0 ) {
try {
2023-08-23 23:37:04 +00:00
global $savstripearrayofkeysbyenv ;
global $stripearrayofkeysbyenv ;
$servicestatus = 0 ;
if ( $service == 'StripeLive' ) {
$servicestatus = 1 ;
}
2023-02-27 14:58:15 +00:00
//var_dump($companypaymentmode);
2024-01-17 23:42:43 +00:00
dol_syslog ( " makeStripeSepaRequest We will try to pay with companypaymentmodeid= " . $companypaymentmode -> id . " stripe_card_ref= " . $companypaymentmode -> stripe_card_ref . " mode= " . $companypaymentmode -> status , LOG_DEBUG );
2022-09-09 02:10:48 +00:00
2023-02-27 14:58:15 +00:00
$thirdparty = new Societe ( $this -> db );
$resultthirdparty = $thirdparty -> fetch ( $this -> socid );
2022-09-09 02:10:48 +00:00
2023-02-27 14:58:15 +00:00
include_once DOL_DOCUMENT_ROOT . '/stripe/class/stripe.class.php' ; // This include the include of htdocs/stripe/config.php
// So it inits or erases the $stripearrayofkeysbyenv
$stripe = new Stripe ( $this -> db );
2022-10-13 03:31:36 +00:00
2023-12-04 11:04:36 +00:00
if ( empty ( $savstripearrayofkeysbyenv )) {
$savstripearrayofkeysbyenv = $stripearrayofkeysbyenv ;
}
2023-02-27 14:58:15 +00:00
dol_syslog ( " makeStripeSepaRequest Current Stripe environment is " . $stripearrayofkeysbyenv [ $servicestatus ][ 'publishable_key' ]);
2023-08-23 23:37:04 +00:00
dol_syslog ( " makeStripeSepaRequest Current Saved Stripe environment is " . $savstripearrayofkeysbyenv [ $servicestatus ][ 'publishable_key' ]);
$foundalternativestripeaccount = '' ;
FIX: Resolve possibly-undefined-variable cases flagged by PHPStan (#39523)
* FIX: Resolve possibly-undefined-variable cases flagged by PHPStan
Fixes several cases of the variable.undefined PHPStan rule instead of
just excluding them via the baseline: a wrong variable used to build a
delete link (dir_add_card.php), an uninitialized $result across a
try/catch (CMailFile), missing GETPOST reads ($mode, $fk_project/$date
reset via unset() creating cross-branch ambiguity), a missing $r
contract check (commonfieldsinimport.inc.php), missing @var/global
annotations for $conf/$langs/$bc, dead extrafields-display code
guarded by the wrong condition (expedition/card.php), and an
undefined $soc passed to formAddObjectLine() where objects have no
buyer thirdparty (replaced with null). Corresponding entries removed
from dev/build/phpstan/phpstan-baseline.neon.
* FIX: Resolve more possibly-undefined-variable cases flagged by PHPStan
Second batch of variable.undefined fixes removed from the baseline:
- Complex conditional flows PHPStan can't prove exhaustive (Stripe key
selection in commoninvoice.class.php, a situation-invoice loop var in
pdf_sponge.modules.php, a product loop var in stock/movement_list.php)
fixed by adding a definite initialization before the ambiguous branch.
- A commented-out $linkback assignment restored in
expensereport/payment/info.php.
- Missing GETPOST reads added (holiday/list.php update-date filters,
product/stock/info.php $action/$socid, projet/comment.php $mode).
- A dead-code $mesg call to dol_htmloutput_mesg() removed from
admin_hrm.php (messages are already shown via setEventMessages()).
- Redundant isset() checks removed in product/reassort.php and
reassortlot.php where $type is unconditionally set earlier in the
same file, so the isset()-false branch was unreachable dead code.
- $user documented as always available in public/bookcal/index.php
(NOREQUIREUSER is not defined on that page).
- A genuinely missing $tmpcode initialization fixed in
attendee_new.php, suggestbooth.php and suggestconference.php: when
an existing thirdparty is reused (or SOCIETE_CODECLIENT_ADDON has no
auto-numbering), $tmpcode was never set before being assigned to
code_client/code_fournisseur.
* add phan fix
* add phan fix
* fix
* fix
* fix
2026-08-15 16:33:12 +00:00
$stripearrayofkeys = array ();
2023-08-23 23:37:04 +00:00
// Force stripe to another value (by default this value is empty)
if ( ! empty ( $forcestripe )) {
dol_syslog ( " makeStripeSepaRequest A dedicated stripe account was forced, so we switch to it. " );
$tmparray = explode ( '@' , $forcestripe );
if ( ! empty ( $tmparray [ 1 ])) {
$tmparray2 = explode ( ':' , $tmparray [ 1 ]);
2023-08-25 19:57:16 +00:00
if ( ! empty ( $tmparray2 [ 1 ])) {
$stripearrayofkeysbyenv [ $servicestatus ][ " publishable_key " ] = $tmparray2 [ 0 ];
$stripearrayofkeysbyenv [ $servicestatus ][ " secret_key " ] = $tmparray2 [ 1 ];
2023-08-23 23:37:04 +00:00
$stripearrayofkeys = $stripearrayofkeysbyenv [ $servicestatus ];
\Stripe\Stripe :: setApiKey ( $stripearrayofkeys [ 'secret_key' ]);
$foundalternativestripeaccount = $tmparray [ 0 ]; // Store the customer id
dol_syslog ( " makeStripeSepaRequest We use now customer= " . $foundalternativestripeaccount . " publishable_key= " . $stripearrayofkeys [ 'publishable_key' ], LOG_DEBUG );
}
}
if ( ! $foundalternativestripeaccount ) {
$stripearrayofkeysbyenv = $savstripearrayofkeysbyenv ;
$stripearrayofkeys = $savstripearrayofkeysbyenv [ $servicestatus ];
\Stripe\Stripe :: setApiKey ( $stripearrayofkeys [ 'secret_key' ]);
dol_syslog ( " makeStripeSepaRequest We found a bad value for Stripe Account for thirdparty id= " . $thirdparty -> id . " , so we ignore it and keep using the global one, so " . $stripearrayofkeys [ 'publishable_key' ], LOG_WARNING );
}
} else {
$stripearrayofkeysbyenv = $savstripearrayofkeysbyenv ;
$stripearrayofkeys = $savstripearrayofkeysbyenv [ $servicestatus ];
\Stripe\Stripe :: setApiKey ( $stripearrayofkeys [ 'secret_key' ]);
dol_syslog ( " makeStripeSepaRequest No dedicated Stripe Account requested, so we use global one, so " . $stripearrayofkeys [ 'publishable_key' ], LOG_DEBUG );
}
2022-09-09 02:10:48 +00:00
2023-02-27 14:58:15 +00:00
$stripeacc = $stripe -> getStripeAccount ( $service , $this -> socid ); // Get Stripe OAuth connect account if it exists (no network access here)
2022-09-09 02:10:48 +00:00
2023-08-23 23:37:04 +00:00
if ( $foundalternativestripeaccount ) {
if ( empty ( $stripeacc )) { // If the Stripe connect account not set, we use common API usage
2024-03-12 23:29:19 +00:00
$customer = \Stripe\Customer :: retrieve ( array ( 'id' => " $foundalternativestripeaccount " , 'expand[]' => 'sources' ));
2023-08-23 23:37:04 +00:00
} else {
2024-03-12 23:29:19 +00:00
$customer = \Stripe\Customer :: retrieve ( array ( 'id' => " $foundalternativestripeaccount " , 'expand[]' => 'sources' ), array ( " stripe_account " => $stripeacc ));
2023-08-23 23:37:04 +00:00
}
} else {
$customer = $stripe -> customerStripe ( $thirdparty , $stripeacc , $servicestatus , 0 );
if ( empty ( $customer ) && ! empty ( $stripe -> error )) {
2025-01-02 16:32:36 +00:00
$this -> error = $stripe -> error ;
$this -> errors [] = $this -> error ;
2023-08-23 23:37:04 +00:00
}
/* if ( ! empty ( $customer ) && empty ( $customer -> sources )) {
$customer = null ;
2025-01-02 16:32:36 +00:00
$this -> error = '\Stripe\Customer::retrieve did not returned the sources' ;
$this -> errors [] = $this -> error ;
2023-08-23 23:37:04 +00:00
} */
2023-02-27 14:58:15 +00:00
}
2022-09-09 02:10:48 +00:00
2023-02-27 14:58:15 +00:00
// $nbhoursbetweentries = (empty($conf->global->SELLYOURSAAS_NBHOURSBETWEENTRIES) ? 49 : $conf->global->SELLYOURSAAS_NBHOURSBETWEENTRIES); // Must have more that 48 hours + 1 between each try (so 1 try every 3 daily batch)
// $nbdaysbeforeendoftries = (empty($conf->global->SELLYOURSAAS_NBDAYSBEFOREENDOFTRIES) ? 35 : $conf->global->SELLYOURSAAS_NBDAYSBEFOREENDOFTRIES);
$postactionmessages = [];
2022-09-09 02:10:48 +00:00
2023-02-27 14:58:15 +00:00
if ( $resultthirdparty > 0 && ! empty ( $customer )) {
if ( ! $error ) { // Payment was not canceled
$stripecard = null ;
if ( $companypaymentmode -> type == 'ban' ) {
// Check into societe_rib if a payment mode for Stripe and ban payment exists
2024-01-13 18:48:20 +00:00
// To make a Stripe SEPA payment request, we must have the payment mode source already saved into societe_rib and retrieved with ->sepaStripe
2023-02-27 14:58:15 +00:00
// The payment mode source is created when we create the bank account on Stripe with paymentmodes.php?action=create
$stripecard = $stripe -> sepaStripe ( $customer , $companypaymentmode , $stripeacc , $servicestatus , 0 );
2023-03-04 11:16:38 +00:00
} else {
$error ++ ;
$this -> error = 'The payment mode type is not "ban"' ;
2022-10-13 03:31:36 +00:00
}
2022-09-09 02:10:48 +00:00
2023-02-27 14:58:15 +00:00
if ( $stripecard ) { // Can be src_... (for sepa) or pm_... (new card mode). Note that card_... (old card mode) should not happen here.
$FULLTAG = 'DID=' . $did . '-INV=' . $this -> id . '-CUS=' . $thirdparty -> id ;
$description = 'Stripe payment from makeStripeSepaRequest: ' . $FULLTAG . ' did=' . $did . ' ref=' . $this -> ref ;
$stripefailurecode = '' ;
$stripefailuremessage = '' ;
$stripefailuredeclinecode = '' ;
// Using new SCA method
dol_syslog ( " * Create payment on SEPA " . $stripecard -> id . " , amounttopay= " . $amounttopay . " , amountstripe= " . $amountstripe . " , FULLTAG= " . $FULLTAG , LOG_DEBUG );
// Create payment intent and charge payment (confirmnow = true)
$paymentintent = $stripe -> getPaymentIntent ( $amounttopay , $currency , $FULLTAG , $description , $this , $customer -> id , $stripeacc , $servicestatus , 0 , 'automatic' , true , $stripecard -> id , 1 , 1 , $did );
$charge = new stdClass ();
if ( $paymentintent -> status === 'succeeded' || $paymentintent -> status === 'processing' ) {
$charge -> status = 'ok' ;
$charge -> id = $paymentintent -> id ;
$charge -> customer = $customer -> id ;
} elseif ( $paymentintent -> status === 'requires_action' ) {
//paymentintent->status may be => 'requires_action' (no error in such a case)
2026-02-10 15:54:51 +00:00
dol_syslog ( formatLogObject ( $paymentintent ), LOG_DEBUG );
2023-02-27 14:58:15 +00:00
$charge -> status = 'failed' ;
$charge -> customer = $customer -> id ;
$charge -> failure_code = $stripe -> code ;
$charge -> failure_message = $stripe -> error ;
$charge -> failure_declinecode = $stripe -> declinecode ;
$stripefailurecode = $stripe -> code ;
$stripefailuremessage = 'Action required. Contact the support at ' ; // . $conf->global->SELLYOURSAAS_MAIN_EMAIL;
$stripefailuredeclinecode = $stripe -> declinecode ;
} else {
2026-02-10 15:54:51 +00:00
dol_syslog ( formatLogObject ( $paymentintent ), LOG_DEBUG );
2023-02-27 14:58:15 +00:00
$charge -> status = 'failed' ;
$charge -> customer = $customer -> id ;
$charge -> failure_code = $stripe -> code ;
$charge -> failure_message = $stripe -> error ;
$charge -> failure_declinecode = $stripe -> declinecode ;
$stripefailurecode = $stripe -> code ;
$stripefailuremessage = $stripe -> error ;
$stripefailuredeclinecode = $stripe -> declinecode ;
}
2022-10-13 03:31:36 +00:00
2023-02-27 14:58:15 +00:00
//var_dump("stripefailurecode=".$stripefailurecode." stripefailuremessage=".$stripefailuremessage." stripefailuredeclinecode=".$stripefailuredeclinecode);
//exit;
// Return $charge = array('id'=>'ch_XXXX', 'status'=>'succeeded|pending|failed', 'failure_code'=>, 'failure_message'=>...)
if ( empty ( $charge ) || $charge -> status == 'failed' ) {
dol_syslog ( 'Failed to charge payment mode ' . $stripecard -> id . ' stripefailurecode=' . $stripefailurecode . ' stripefailuremessage=' . $stripefailuremessage . ' stripefailuredeclinecode=' . $stripefailuredeclinecode , LOG_WARNING );
// Save a stripe payment was in error
$this -> stripechargeerror ++ ;
$error ++ ;
$errorforinvoice ++ ;
2025-01-03 13:23:58 +00:00
$errmsg = $langs -> trans ( " FailedToChargeSEPA " );
2023-02-27 14:58:15 +00:00
if ( ! empty ( $charge )) {
if ( $stripefailuredeclinecode == 'authentication_required' ) {
$errauthenticationmessage = $langs -> trans ( " ErrSCAAuthentication " );
$errmsg = $errauthenticationmessage ;
} elseif ( in_array ( $stripefailuredeclinecode , [ 'insufficient_funds' , 'generic_decline' ])) {
$errmsg .= ': ' . $charge -> failure_code ;
$errmsg .= ( $charge -> failure_message ? ' - ' : '' ) . ' ' . $charge -> failure_message ;
if ( empty ( $stripefailurecode )) {
$stripefailurecode = $charge -> failure_code ;
}
if ( empty ( $stripefailuremessage )) {
$stripefailuremessage = $charge -> failure_message ;
}
} else {
$errmsg .= ': failure_code=' . $charge -> failure_code ;
$errmsg .= ( $charge -> failure_message ? ' - ' : '' ) . ' failure_message=' . $charge -> failure_message ;
if ( empty ( $stripefailurecode )) {
$stripefailurecode = $charge -> failure_code ;
}
if ( empty ( $stripefailuremessage )) {
$stripefailuremessage = $charge -> failure_message ;
}
2022-09-09 02:10:48 +00:00
}
} else {
2023-02-27 14:58:15 +00:00
$errmsg .= ': ' . $stripefailurecode . ' - ' . $stripefailuremessage ;
$errmsg .= ( $stripefailuredeclinecode ? ' - ' . $stripefailuredeclinecode : '' );
2022-09-09 02:10:48 +00:00
}
2023-02-27 14:58:15 +00:00
$description = 'Stripe payment ERROR from makeStripeSepaRequest: ' . $FULLTAG ;
$postactionmessages [] = $errmsg . ' (' . $stripearrayofkeys [ 'publishable_key' ] . ')' ;
2025-01-02 16:32:36 +00:00
$this -> error = $errmsg ;
$this -> errors [] = $this -> error ;
2022-09-09 02:10:48 +00:00
} else {
2023-03-04 11:16:38 +00:00
dol_syslog ( 'Successfuly request ' . $type . ' ' . $stripecard -> id );
2022-09-09 02:10:48 +00:00
2023-03-04 11:16:38 +00:00
$postactionmessages [] = 'Success to request ' . $type . ' (' . $charge -> id . ' with ' . $stripearrayofkeys [ 'publishable_key' ] . ')' ;
2022-09-09 02:10:48 +00:00
2024-01-13 18:48:20 +00:00
// Save a stripe payment was done in real life so later we will be able to force a commit on recorded payments
2023-02-27 14:58:15 +00:00
// even if in batch mode (method doTakePaymentStripe), we will always make all action in one transaction with a forced commit.
$this -> stripechargedone ++ ;
2022-09-09 02:10:48 +00:00
2023-02-27 14:58:15 +00:00
// Default description used for label of event. Will be overwrite by another value later.
$description = 'Stripe payment request OK (' . $charge -> id . ') from makeStripeSepaRequest: ' . $FULLTAG ;
}
2022-09-09 02:10:48 +00:00
2023-02-27 14:58:15 +00:00
$object = $this ;
2022-10-13 03:31:36 +00:00
2023-02-27 14:58:15 +00:00
// Track an event
if ( empty ( $charge ) || $charge -> status == 'failed' ) {
$actioncode = 'PAYMENT_STRIPE_KO' ;
$extraparams = $stripefailurecode ;
$extraparams .= (( $extraparams && $stripefailuremessage ) ? ' - ' : '' ) . $stripefailuremessage ;
$extraparams .= (( $extraparams && $stripefailuredeclinecode ) ? ' - ' : '' ) . $stripefailuredeclinecode ;
} else {
$actioncode = 'PAYMENT_STRIPE_OK' ;
2025-03-06 03:56:54 +00:00
$extraparams = array ();
2023-02-27 14:58:15 +00:00
}
} else {
$error ++ ;
$errorforinvoice ++ ;
2023-03-04 11:16:38 +00:00
dol_syslog ( " No ban payment method found for this stripe customer " . $customer -> id , LOG_WARNING );
2025-01-02 16:32:36 +00:00
$this -> error = 'Failed to get direct debit payment method for stripe customer = ' . $customer -> id ;
$this -> errors [] = $this -> error ;
2023-02-27 14:58:15 +00:00
2023-03-04 11:16:38 +00:00
$description = 'Failed to find or use the payment mode - no ban defined for the thirdparty account' ;
2023-02-27 14:58:15 +00:00
$stripefailurecode = 'BADPAYMENTMODE' ;
2023-03-04 11:16:38 +00:00
$stripefailuremessage = 'Failed to find or use the payment mode - no ban defined for the thirdparty account' ;
2023-02-27 14:58:15 +00:00
$postactionmessages [] = $description . ' (' . $stripearrayofkeys [ 'publishable_key' ] . ')' ;
$object = $this ;
2022-09-09 02:10:48 +00:00
2023-01-18 13:43:09 +00:00
$actioncode = 'PAYMENT_STRIPE_KO' ;
2025-03-06 03:56:54 +00:00
$extraparams = array ();
2023-01-18 13:43:09 +00:00
}
2022-09-09 02:10:48 +00:00
} else {
2023-02-27 14:58:15 +00:00
// If error because payment was canceled for a logical reason, we do nothing (no event added)
$description = '' ;
$stripefailurecode = '' ;
$stripefailuremessage = '' ;
2023-01-18 13:43:09 +00:00
$object = $this ;
2023-02-27 14:58:15 +00:00
$actioncode = '' ;
2025-03-06 03:56:54 +00:00
$extraparams = array ();
2022-09-09 02:10:48 +00:00
}
2023-02-27 14:58:15 +00:00
} else { // Else of the if ($resultthirdparty > 0 && ! empty($customer)) {
if ( $resultthirdparty <= 0 ) {
dol_syslog ( 'SellYourSaasUtils Failed to load customer for thirdparty_id = ' . $thirdparty -> id , LOG_WARNING );
2025-01-02 16:32:36 +00:00
$this -> error = 'Failed to load Stripe account for thirdparty_id = ' . $thirdparty -> id ;
$this -> errors [] = $this -> error ;
2023-02-27 14:58:15 +00:00
} else { // $customer stripe not found
dol_syslog ( 'SellYourSaasUtils Failed to get Stripe customer id for thirdparty_id = ' . $thirdparty -> id . " in mode " . $servicestatus . " in Stripe env " . $stripearrayofkeysbyenv [ $servicestatus ][ 'publishable_key' ], LOG_WARNING );
2025-01-02 16:32:36 +00:00
$this -> error = 'Failed to get Stripe account id for thirdparty_id = ' . $thirdparty -> id . " in mode " . $servicestatus . " in Stripe env " . $stripearrayofkeysbyenv [ $servicestatus ][ 'publishable_key' ];
$this -> errors [] = $this -> error ;
2023-02-27 14:58:15 +00:00
}
$error ++ ;
$errorforinvoice ++ ;
$description = 'Failed to find or use your payment mode (no payment mode for this customer id)' ;
$stripefailurecode = 'BADPAYMENTMODE' ;
$stripefailuremessage = 'Failed to find or use your payment mode (no payment mode for this customer id)' ;
2024-05-30 11:37:17 +00:00
$postactionmessages = [];
2022-09-09 02:10:48 +00:00
2023-01-18 13:43:09 +00:00
$object = $this ;
2022-09-09 02:10:48 +00:00
2023-02-27 14:58:15 +00:00
$actioncode = 'PAYMENT_STRIPE_KO' ;
2025-03-06 03:56:54 +00:00
$extraparams = array ();
2022-09-09 02:10:48 +00:00
}
2023-02-27 14:58:15 +00:00
if ( $description ) {
dol_syslog ( " * Record event for credit transfer or direct debit request result - " . $description );
require_once DOL_DOCUMENT_ROOT . '/comm/action/class/actioncomm.class.php' ;
// Insert record of payment (success or error)
$actioncomm = new ActionComm ( $this -> db );
$actioncomm -> type_code = 'AC_OTH_AUTO' ; // Type of event ('AC_OTH', 'AC_OTH_AUTO', 'AC_XXX'...)
$actioncomm -> code = 'AC_' . $actioncode ;
$actioncomm -> label = $description ;
Qual: Apply automatic phan fixes (deprecations, unneeded imports) (#28154)
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
* Qual: Apply automatic phan fixes (deprecations, unneeded imports)
# Qual: Apply automatic phan fixes (deprecations, unneeded imports)
This applies automatic fixes by phan for deprecated functions, unneeded imports).
2024-02-13 20:46:12 +00:00
$actioncomm -> note_private = implode ( " , \n " , $postactionmessages );
2023-02-27 14:58:15 +00:00
$actioncomm -> fk_project = $this -> fk_project ;
$actioncomm -> datep = $now ;
$actioncomm -> datef = $now ;
$actioncomm -> percentage = - 1 ; // Not applicable
$actioncomm -> socid = $thirdparty -> id ;
$actioncomm -> contactid = 0 ;
$actioncomm -> authorid = $user -> id ; // User saving action
$actioncomm -> userownerid = $user -> id ; // Owner of action
// Fields when action is a real email (content is already into note)
/* $actioncomm -> email_msgid = $object -> email_msgid ;
$actioncomm -> email_from = $object -> email_from ;
$actioncomm -> email_sender = $object -> email_sender ;
$actioncomm -> email_to = $object -> email_to ;
$actioncomm -> email_tocc = $object -> email_tocc ;
$actioncomm -> email_tobcc = $object -> email_tobcc ;
$actioncomm -> email_subject = $object -> email_subject ;
$actioncomm -> errors_to = $object -> errors_to ; */
$actioncomm -> fk_element = $this -> id ;
2025-03-06 03:56:54 +00:00
$actioncomm -> elementid = $this -> id ;
2023-02-27 14:58:15 +00:00
$actioncomm -> elementtype = $this -> element ;
2025-03-06 03:56:54 +00:00
$actioncomm -> extraparams = $extraparams ; // Can be null, empty string or array()
2023-02-27 14:58:15 +00:00
$actioncomm -> create ( $user );
2022-10-13 03:31:36 +00:00
}
2023-02-27 14:58:15 +00:00
$this -> description = $description ;
$this -> postactionmessages = $postactionmessages ;
} catch ( Exception $e ) {
2022-10-13 03:31:36 +00:00
$error ++ ;
$errorforinvoice ++ ;
2023-02-27 14:58:15 +00:00
dol_syslog ( 'Error ' . $e -> getMessage (), LOG_ERR );
2025-01-02 16:32:36 +00:00
$this -> error = 'Error ' . $e -> getMessage ();
$this -> errors [] = $this -> error ;
2022-10-13 03:31:36 +00:00
}
2023-02-27 14:58:15 +00:00
} else { // If remain to pay is null
2022-09-09 02:10:48 +00:00
$error ++ ;
2022-10-13 03:31:36 +00:00
$errorforinvoice ++ ;
2023-02-27 14:58:15 +00:00
dol_syslog ( " Remain to pay is null for the invoice " . $this -> id . " " . $this -> ref . " . Why is the invoice not classified 'Paid' ? " , LOG_WARNING );
2025-01-02 16:32:36 +00:00
$this -> error = " Remain to pay is null for the invoice " . $this -> id . " " . $this -> ref . " . Why is the invoice not classified 'Paid' ? " ;
$this -> errors [] = $this -> error ;
2022-09-09 02:10:48 +00:00
}
}
2023-02-24 22:15:54 +00:00
// Set status of the order to "Transferred" with method 'api'
if ( ! $error && ! $errorforinvoice ) {
$result = $bon -> set_infotrans ( $user , $now , 3 );
2023-02-22 14:09:37 +00:00
if ( $result < 0 ) {
$error ++ ;
$errorforinvoice ++ ;
dol_syslog ( " Error on BonPrelevement creation " , LOG_ERR );
2025-01-02 16:32:36 +00:00
$this -> error = " Error on BonPrelevement creation " ;
$this -> errors [] = $this -> error ;
2023-02-22 14:09:37 +00:00
}
2023-02-10 14:30:36 +00:00
}
2024-10-13 14:45:42 +00:00
if ( ! $error && ! $errorforinvoice && $paymentintent !== null ) {
2023-02-10 14:30:36 +00:00
// Update the direct debit payment request of the processed invoice to save the id of the prelevement_bon
$sql = " UPDATE " . MAIN_DB_PREFIX . " prelevement_demande SET " ;
2023-02-24 22:15:54 +00:00
$sql .= " ext_payment_id = ' " . $this -> db -> escape ( $paymentintent -> id ) . " ', " ;
$sql .= " ext_payment_site = ' " . $this -> db -> escape ( $service ) . " ' " ;
2023-02-10 14:30:36 +00:00
$sql .= " WHERE rowid = " . (( int ) $did );
2023-02-24 22:15:54 +00:00
dol_syslog ( get_class ( $this ) . " ::makeStripeSepaRequest update to save stripe paymentintent ids " , LOG_DEBUG );
2023-02-10 14:30:36 +00:00
$resql = $this -> db -> query ( $sql );
if ( ! $resql ) {
$this -> error = $this -> db -> lasterror ();
dol_syslog ( get_class ( $this ) . '::makeStripeSepaRequest Erreur' );
$error ++ ;
}
2022-09-09 02:10:48 +00:00
}
2023-02-24 22:15:54 +00:00
if ( ! $error && ! $errorforinvoice ) {
$this -> db -> commit ();
} else {
$this -> db -> rollback ();
}
2022-10-13 03:31:36 +00:00
} else {
$this -> error = 'WithdrawRequestErrorNilAmount' ;
dol_syslog ( get_class ( $this ) . '::makeStripeSepaRequest WithdrawRequestErrorNilAmount' );
$error ++ ;
}
2022-09-09 02:10:48 +00:00
2023-02-24 22:15:54 +00:00
/*
2022-10-13 03:31:36 +00:00
if ( ! $error ) {
2023-02-24 22:15:54 +00:00
// Force payment mode of the invoice to withdraw
2022-10-13 03:31:36 +00:00
$payment_mode_id = dol_getIdFromCode ( $this -> db , ( $type == 'bank-transfer' ? 'VIR' : 'PRE' ), 'c_paiement' , 'code' , 'id' , 1 );
if ( $payment_mode_id > 0 ) {
$result = $this -> setPaymentMethods ( $payment_mode_id );
2022-09-09 02:10:48 +00:00
}
2023-02-24 22:15:54 +00:00
} */
2022-10-13 03:31:36 +00:00
if ( $error ) {
return - 1 ;
}
return 1 ;
2022-09-09 02:10:48 +00:00
} else {
$this -> error = $this -> db -> error ();
2022-10-13 03:31:36 +00:00
dol_syslog ( get_class ( $this ) . '::makeStripeSepaRequest Erreur -2' );
2022-09-09 02:10:48 +00:00
return - 2 ;
}
} else {
$this -> error = " Status of invoice does not allow this " ;
2024-01-17 23:42:43 +00:00
dol_syslog ( get_class ( $this ) . " ::makeStripeSepaRequest " . $this -> error . " " . $this -> status . " , " . $this -> paye . " , " . $this -> mode_reglement_id , LOG_WARNING );
2022-09-09 02:10:48 +00:00
return - 3 ;
}
}
2020-06-24 17:59:06 +00:00
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
/**
* Remove a direct debit request or a credit transfer request
*
* @ param User $fuser User making delete
* @ param int $did ID of request to delete
2023-12-06 14:46:39 +00:00
* @ return int Return integer < 0 if OK , > 0 if KO
2020-06-24 17:59:06 +00:00
*/
public function demande_prelevement_delete ( $fuser , $did )
{
// phpcs:enable
2022-10-28 15:51:25 +00:00
$sql = 'DELETE FROM ' . $this -> db -> prefix () . 'prelevement_demande' ;
2021-03-30 09:36:50 +00:00
$sql .= ' WHERE rowid = ' . (( int ) $did );
2020-06-24 17:59:06 +00:00
$sql .= ' AND traite = 0' ;
2021-02-23 21:03:23 +00:00
if ( $this -> db -> query ( $sql )) {
2020-06-24 17:59:06 +00:00
return 0 ;
2020-06-27 00:00:42 +00:00
} else {
2020-06-24 17:59:06 +00:00
$this -> error = $this -> db -> lasterror ();
dol_syslog ( get_class ( $this ) . '::demande_prelevement_delete Error ' . $this -> error );
return - 1 ;
}
}
2022-01-04 19:44:17 +00:00
2024-04-24 19:57:55 +00:00
/**
* Build string for EPC QR Code
*
* @ return string String for EPC QR Code
*/
public function buildEPCQrCodeString ()
{
global $mysoc ;
2022-01-04 19:44:17 +00:00
2025-11-20 00:49:24 +00:00
// Get the amount to pay
2025-11-20 15:23:47 +00:00
$amount_to_pay = $this -> getRemainToPay ();
2025-11-20 00:49:24 +00:00
2025-11-21 17:34:24 +00:00
// Prevent negative values (e.g. overpayments)
$amount_to_pay = max ( 0 , $amount_to_pay );
2025-11-20 00:49:24 +00:00
// Ensure numeric formatting for EPC QR code
$amount_to_pay = price2num ( $amount_to_pay , 'MT' );
2024-04-24 19:57:55 +00:00
// Initialize an array to hold the lines of the QR code
$lines = array ();
// Add the standard elements to the QR code
$lines = [
'BCD' , // Service Tag (optional)
'002' , // Version (optional)
'1' , // Character set (optional)
'SCT' , // Identification (optional)
];
// Add the bank account information
include_once DOL_DOCUMENT_ROOT . '/compta/bank/class/account.class.php' ;
2025-10-15 03:02:34 +00:00
$idofbankaccountouse = $this -> fk_account ;
if ( empty ( $idofbankaccountouse )) {
2025-10-15 10:31:30 +00:00
$idofbankaccountouse = $this -> fk_bank ; // for backward compatibility
2025-10-15 03:02:34 +00:00
}
if ( empty ( $idofbankaccountouse )) {
$idofbankaccountouse = getDolGlobalInt ( 'FACTURE_RIB_NUMBER' );
}
if ( $idofbankaccountouse > 0 ) {
$bankAccount = new Account ( $this -> db );
$bankAccount -> fetch ( $idofbankaccountouse );
2024-04-24 19:57:55 +00:00
$lines [] = $bankAccount -> bic ; //BIC (required)
2024-11-11 16:38:41 +00:00
if ( ! empty ( $bankAccount -> owner_name )) {
$lines [] = $bankAccount -> owner_name ; //Owner of the bank account, if present (required)
} else {
$lines [] = $mysoc -> name ; //Name (required)
}
2024-04-24 19:57:55 +00:00
$lines [] = $bankAccount -> iban ; //IBAN (required)
} else {
$lines [] = " " ; //BIC (required)
$lines [] = $mysoc -> name ; //Name (required)
$lines [] = " " ; //IBAN (required)
}
// Add the amount and reference
2025-11-20 00:49:24 +00:00
$lines [] = 'EUR' . $amount_to_pay ; // Amount (optional)
2024-10-25 15:14:48 +00:00
$lines [] = '' ; // Purpose (optional)
2024-04-24 19:57:55 +00:00
$lines [] = '' ; // Payment reference (optional)
$lines [] = $this -> ref ; // Remittance Information (optional)
// Join the lines with newline characters and return the result
return implode ( " \n " , $lines );
}
2022-01-04 19:44:17 +00:00
/**
* Build string for ZATCA QR Code ( Arabi Saudia )
*
* @ return string String for ZATCA QR Code
*/
public function buildZATCAQRString ()
{
2022-05-22 10:38:52 +00:00
global $conf , $mysoc ;
2022-01-04 19:44:17 +00:00
$tmplang = new Translate ( '' , $conf );
$tmplang -> setDefaultLang ( 'en_US' );
$tmplang -> load ( " main " );
$datestring = dol_print_date ( $this -> date , 'dayhourrfc' );
2022-03-19 18:14:12 +00:00
//$pricewithtaxstring = price($this->total_ttc, 0, $tmplang, 0, -1, 2);
//$pricetaxstring = price($this->total_tva, 0, $tmplang, 0, -1, 2);
$pricewithtaxstring = price2num ( $this -> total_ttc , 2 , 1 );
$pricetaxstring = price2num ( $this -> total_tva , 2 , 1 );
2022-01-04 19:44:17 +00:00
/*
$name = implode ( unpack ( " H* " , $this -> thirdparty -> name ));
$vatnumber = implode ( unpack ( " H* " , $this -> thirdparty -> tva_intra ));
$date = implode ( unpack ( " H* " , $datestring ));
$pricewithtax = implode ( unpack ( " H* " , price2num ( $pricewithtaxstring , 2 )));
$pricetax = implode ( unpack ( " H* " , $pricetaxstring ));
2022-05-17 12:55:38 +00:00
//var_dump(strlen($this->thirdparty->name));
//var_dump(str_pad(dechex('9'), 2, '0', STR_PAD_LEFT));
//var_dump($this->thirdparty->name);
//var_dump(implode(unpack("H*", $this->thirdparty->name)));
//var_dump(price($this->total_tva, 0, $tmplang, 0, -1, 2));
2022-01-04 19:44:17 +00:00
$s = '01' . str_pad ( dechex ( strlen ( $this -> thirdparty -> name )), 2 , '0' , STR_PAD_LEFT ) . $name ;
$s .= '02' . str_pad ( dechex ( strlen ( $this -> thirdparty -> tva_intra )), 2 , '0' , STR_PAD_LEFT ) . $vatnumber ;
$s .= '03' . str_pad ( dechex ( strlen ( $datestring )), 2 , '0' , STR_PAD_LEFT ) . $date ;
$s .= '04' . str_pad ( dechex ( strlen ( $pricewithtaxstring )), 2 , '0' , STR_PAD_LEFT ) . $pricewithtax ;
$s .= '05' . str_pad ( dechex ( strlen ( $pricetaxstring )), 2 , '0' , STR_PAD_LEFT ) . $pricetax ;
$s .= '' ; // Hash of xml invoice
$s .= '' ; // ecda signature
$s .= '' ; // ecda public key
$s .= '' ; // ecda signature of public key stamp
*/
2024-11-26 02:43:42 +00:00
$mysocname = $mysoc -> name ? ? '' ;
2025-03-01 19:51:07 +00:00
$mysoctva_intra = $mysoc -> tva_intra ? ? '' ;
2022-01-04 19:44:17 +00:00
// Using TLV format
2024-11-26 02:43:42 +00:00
$s = pack ( 'C1' , 1 ) . pack ( 'C1' , strlen ( $mysocname )) . $mysocname ;
2025-03-01 19:51:07 +00:00
$s .= pack ( 'C1' , 2 ) . pack ( 'C1' , strlen ( $mysoctva_intra )) . $mysoctva_intra ;
2022-03-19 18:14:12 +00:00
$s .= pack ( 'C1' , 3 ) . pack ( 'C1' , strlen ( $datestring )) . $datestring ;
2022-01-04 19:44:17 +00:00
$s .= pack ( 'C1' , 4 ) . pack ( 'C1' , strlen ( $pricewithtaxstring )) . $pricewithtaxstring ;
$s .= pack ( 'C1' , 5 ) . pack ( 'C1' , strlen ( $pricetaxstring )) . $pricetaxstring ;
$s .= '' ; // Hash of xml invoice
$s .= '' ; // ecda signature
$s .= '' ; // ecda public key
$s .= '' ; // ecda signature of public key stamp
$s = base64_encode ( $s );
return $s ;
}
2022-06-19 11:06:07 +00:00
/**
* Build string for QR - Bill ( Switzerland )
*
* @ return string String for Switzerland QR Code if QR - Bill
*/
public function buildSwitzerlandQRString ()
{
global $conf , $mysoc ;
$tmplang = new Translate ( '' , $conf );
$tmplang -> setDefaultLang ( 'en_US' );
$tmplang -> load ( " main " );
$pricewithtaxstring = price2num ( $this -> total_ttc , 2 , 1 );
$pricetaxstring = price2num ( $this -> total_tva , 2 , 1 );
$complementaryinfo = '' ;
/*
Example : //S1/10/10201409/11/190512/20/1400.000-53/30/106017086/31/180508/32/7.7/40/2:10;0:30
2026-06-28 11:43:41 +00:00
/ 10 / Invoice number -- 10201409
/ 11 / Invoice date -- 12.05 . 2019
/ 20 / Customer reference -- 1400.000 - 53
/ 30 / VAT IDE number -- CHE - 106.017 . 086 TVA
/ 31 / Service date for VAT accounting -- 08.05 . 2018
/ 32 / VAT rate on total invoice amount -- 7.7 %
/ 40 / Terms -- 2 % discount at 10 days , net payment at 30 days
2022-06-19 11:06:07 +00:00
*/
$datestring = dol_print_date ( $this -> date , '%y%m%d' );
//$pricewithtaxstring = price($this->total_ttc, 0, $tmplang, 0, -1, 2);
//$pricetaxstring = price($this->total_tva, 0, $tmplang, 0, -1, 2);
$complementaryinfo = '//S1/10/' . str_replace ( '/' , '' , $this -> ref ) . '/11/' . $datestring ;
if ( $this -> ref_client ) {
$complementaryinfo .= '/20/' . $this -> ref_client ;
}
2022-11-08 16:49:15 +00:00
if ( $this -> thirdparty -> tva_intra ) {
$complementaryinfo .= '/30/' . $this -> thirdparty -> tva_intra ;
2022-06-19 11:06:07 +00:00
}
2023-02-02 14:06:19 +00:00
include_once DOL_DOCUMENT_ROOT . '/compta/bank/class/account.class.php' ;
2023-02-02 13:56:03 +00:00
$bankaccount = new Account ( $this -> db );
2022-06-19 11:06:07 +00:00
// Header
2022-12-04 14:16:45 +00:00
$s = '' ;
2022-06-19 11:06:07 +00:00
$s .= " SPC \n " ;
$s .= " 0200 \n " ;
$s .= " 1 \n " ;
2026-06-28 11:43:41 +00:00
// Info Seller ("Account / Payable to")
2022-06-19 11:06:07 +00:00
if ( $this -> fk_account > 0 ) {
2023-02-02 14:06:19 +00:00
// Bank BAN if country is LI or CH. TODO Add a test to check than IBAN start with CH or LI
2022-06-19 11:26:49 +00:00
$bankaccount -> fetch ( $this -> fk_account );
$s .= $bankaccount -> iban . " \n " ;
2022-06-19 11:06:07 +00:00
} else {
$s .= " \n " ;
}
2023-02-02 14:06:19 +00:00
if ( $bankaccount -> id > 0 && getDolGlobalString ( 'PDF_SWISS_QRCODE_USE_OWNER_OF_ACCOUNT_AS_CREDITOR' )) {
2024-01-13 18:48:20 +00:00
// If a bank account is provided and we ask to use it as creditor, we use the bank address
2023-02-02 14:06:19 +00:00
// TODO In a future, we may always use this address, and if name/address/zip/town/country differs from $mysoc, we can use the address of $mysoc into the final seller field ?
$s .= " S \n " ;
2024-10-24 10:38:41 +00:00
$s .= dol_trunc ( $bankaccount -> owner_name , 70 , 'right' , 'UTF-8' , 1 ) . " \n " ;
2023-02-02 14:06:19 +00:00
$addresslinearray = explode ( " \n " , $bankaccount -> owner_address );
$s .= dol_trunc ( empty ( $addresslinearray [ 1 ]) ? '' : $addresslinearray [ 1 ], 70 , 'right' , 'UTF-8' , 1 ) . " \n " ; // address line 1
$s .= dol_trunc ( empty ( $addresslinearray [ 2 ]) ? '' : $addresslinearray [ 2 ], 70 , 'right' , 'UTF-8' , 1 ) . " \n " ; // address line 2
/* $s .= dol_trunc ( $mysoc -> zip , 16 , 'right' , 'UTF-8' , 1 ) . " \n " ;
$s .= dol_trunc ( $mysoc -> town , 35 , 'right' , 'UTF-8' , 1 ) . " \n " ;
$s .= dol_trunc ( $mysoc -> country_code , 2 , 'right' , 'UTF-8' , 1 ) . " \n " ; */
} else {
$s .= " S \n " ;
2025-02-01 14:53:36 +00:00
$s .= dol_trunc (( string ) $mysoc -> name , 70 , 'right' , 'UTF-8' , 1 ) . " \n " ;
2023-02-02 14:06:19 +00:00
$addresslinearray = explode ( " \n " , $mysoc -> address );
$s .= dol_trunc ( empty ( $addresslinearray [ 1 ]) ? '' : $addresslinearray [ 1 ], 70 , 'right' , 'UTF-8' , 1 ) . " \n " ; // address line 1
$s .= dol_trunc ( empty ( $addresslinearray [ 2 ]) ? '' : $addresslinearray [ 2 ], 70 , 'right' , 'UTF-8' , 1 ) . " \n " ; // address line 2
$s .= dol_trunc ( $mysoc -> zip , 16 , 'right' , 'UTF-8' , 1 ) . " \n " ;
$s .= dol_trunc ( $mysoc -> town , 35 , 'right' , 'UTF-8' , 1 ) . " \n " ;
$s .= dol_trunc ( $mysoc -> country_code , 2 , 'right' , 'UTF-8' , 1 ) . " \n " ;
}
2026-06-28 11:43:41 +00:00
// Final seller (Ultimate seller) ("Final creditor" = "In favour of")
2022-06-19 11:06:07 +00:00
$s .= " \n " ;
$s .= " \n " ;
$s .= " \n " ;
$s .= " \n " ;
$s .= " \n " ;
$s .= " \n " ;
$s .= " \n " ;
// Amount of payment (to do?)
$s .= price ( $pricewithtaxstring , 0 , 'none' , 0 , 0 , 2 ) . " \n " ;
2022-06-19 11:26:49 +00:00
$s .= ( $this -> multicurrency_code ? $this -> multicurrency_code : $conf -> currency ) . " \n " ;
2022-06-19 11:06:07 +00:00
// Buyer
2022-06-19 11:26:49 +00:00
$s .= " S \n " ;
2025-02-01 14:53:36 +00:00
$s .= dol_trunc (( string ) $this -> thirdparty -> name , 70 , 'right' , 'UTF-8' , 1 ) . " \n " ;
2022-06-19 11:26:49 +00:00
$addresslinearray = explode ( " \n " , $this -> thirdparty -> address );
$s .= dol_trunc ( empty ( $addresslinearray [ 1 ]) ? '' : $addresslinearray [ 1 ], 70 , 'right' , 'UTF-8' , 1 ) . " \n " ; // address line 1
$s .= dol_trunc ( empty ( $addresslinearray [ 2 ]) ? '' : $addresslinearray [ 2 ], 70 , 'right' , 'UTF-8' , 1 ) . " \n " ; // address line 2
2022-06-19 11:06:07 +00:00
$s .= dol_trunc ( $this -> thirdparty -> zip , 16 , 'right' , 'UTF-8' , 1 ) . " \n " ;
$s .= dol_trunc ( $this -> thirdparty -> town , 35 , 'right' , 'UTF-8' , 1 ) . " \n " ;
$s .= dol_trunc ( $this -> thirdparty -> country_code , 2 , 'right' , 'UTF-8' , 1 ) . " \n " ;
// ID of payment
$s .= " NON \n " ; // NON or QRR
2023-02-02 14:06:19 +00:00
$s .= " \n " ; // QR Code reference if previous field is QRR
// Free text
2022-06-19 11:06:07 +00:00
if ( $complementaryinfo ) {
$s .= $complementaryinfo . " \n " ;
} else {
$s .= " \n " ;
}
$s .= " EPD \n " ;
2023-02-02 14:06:19 +00:00
// More text, complementary info
if ( $complementaryinfo ) {
$s .= $complementaryinfo . " \n " ;
}
2022-06-19 11:06:07 +00:00
$s .= " \n " ;
//var_dump($s);exit;
return $s ;
}
2012-07-11 16:13:41 +00:00
}
2014-09-23 17:37:59 +00:00
2020-04-10 08:59:32 +00:00
require_once DOL_DOCUMENT_ROOT . '/core/class/commonobjectline.class.php' ;
2014-09-23 17:37:59 +00:00
2013-07-07 11:14:32 +00:00
/**
* Parent class of all other business classes for details of elements ( invoices , contracts , proposals , orders , ... )
*/
2014-09-23 17:37:59 +00:00
abstract class CommonInvoiceLine extends CommonObjectLine
2013-06-10 14:05:41 +00:00
{
2015-03-23 00:39:12 +00:00
/**
2020-10-12 17:33:00 +00:00
* Custom label of line . Not used by default .
* @ deprecated
2024-10-13 14:45:42 +00:00
* @ var string
2015-03-23 00:39:12 +00:00
*/
2020-10-12 17:33:00 +00:00
public $label ;
2015-03-23 00:39:12 +00:00
/**
2024-10-13 14:45:42 +00:00
* @ deprecated Use $product_ref
2020-10-12 17:33:00 +00:00
* @ see $product_ref
2024-10-13 14:45:42 +00:00
* @ var string
2015-03-23 00:39:12 +00:00
*/
2020-10-12 17:33:00 +00:00
public $ref ; // Product ref (deprecated)
/**
2024-10-13 14:45:42 +00:00
* @ var string
* @ deprecated Use $product_label
2020-10-12 17:33:00 +00:00
* @ see $product_label
*/
public $libelle ; // Product label (deprecated)
2015-03-23 00:39:12 +00:00
/**
* Type of the product . 0 for product 1 for service
* @ var int
*/
public $product_type = 0 ;
2020-10-12 17:33:00 +00:00
/**
* Product ref
* @ var string
*/
public $product_ref ;
/**
* Product label
* @ var string
*/
public $product_label ;
/**
* Product description
* @ var string
*/
public $product_desc ;
/**
* Quantity
2024-10-13 14:45:42 +00:00
* @ var float
2020-10-12 17:33:00 +00:00
*/
public $qty ;
/**
* Unit price before taxes
* @ var float
*/
public $subprice ;
2021-03-08 10:33:07 +00:00
/**
* Unit price before taxes
* @ var float
* @ deprecated
*/
public $price ;
2015-03-23 00:39:12 +00:00
/**
* Id of corresponding product
* @ var int
*/
public $fk_product ;
2017-05-02 19:27:56 +00:00
/**
* VAT code
* @ var string
*/
public $vat_src_code ;
2015-03-23 00:39:12 +00:00
/**
2024-03-19 17:23:00 +00:00
* VAT % Vat rate can be like " 21.30 (CODE) "
2024-10-13 14:45:42 +00:00
* @ var float | string
2015-03-23 00:39:12 +00:00
*/
public $tva_tx ;
/**
* Local tax 1 %
* @ var float
*/
public $localtax1_tx ;
/**
* Local tax 2 %
* @ var float
*/
public $localtax2_tx ;
2021-03-08 10:33:07 +00:00
/**
* Local tax 1 type
2024-02-18 14:04:18 +00:00
* @ var int < 0 , 6 > From 1 to 6 , or 0 if not found
* @ see getLocalTaxesFromRate ()
2021-03-08 10:33:07 +00:00
*/
public $localtax1_type ;
/**
* Local tax 2 type
2024-02-18 14:04:18 +00:00
* @ var int < 0 , 6 > From 1 to 6 , or 0 if not found
* @ see getLocalTaxesFromRate ()
2021-03-08 10:33:07 +00:00
*/
public $localtax2_type ;
2015-03-23 00:39:12 +00:00
/**
* Percent of discount
* @ var float
*/
public $remise_percent ;
2021-03-08 10:33:07 +00:00
/**
* Fixed discount
* @ var float
* @ deprecated
*/
public $remise ;
2015-03-23 00:39:12 +00:00
/**
* Total amount before taxes
* @ var float
*/
public $total_ht ;
/**
* Total VAT amount
* @ var float
*/
public $total_tva ;
/**
* Total local tax 1 amount
* @ var float
*/
public $total_localtax1 ;
/**
* Total local tax 2 amount
* @ var float
*/
public $total_localtax2 ;
/**
* Total amount with taxes
* @ var float
*/
public $total_ttc ;
2025-06-11 16:07:33 +00:00
/**
* @ var float | null
*/
public $revenuestamp ;
2024-10-13 14:45:42 +00:00
/**
* @ var int < 0 , 1 >
*/
2020-11-09 14:18:56 +00:00
public $date_start_fill ; // If set to 1, when invoice is created from a template invoice, it will also auto set the field date_start at creation
2024-10-13 14:45:42 +00:00
/**
* @ var int < 0 , 1 >
*/
2020-11-09 14:18:56 +00:00
public $date_end_fill ; // If set to 1, when invoice is created from a template invoice, it will also auto set the field date_end at creation
2020-11-09 14:15:21 +00:00
2024-10-13 14:45:42 +00:00
/**
* @ var float
*/
2021-03-08 10:33:07 +00:00
public $buy_price_ht ;
2024-10-13 14:45:42 +00:00
/**
* @ var float
* @ deprecated For backward compatibility
*/
public $buyprice ;
/**
* @ var float | int | string
* @ deprecated For backward compatibility
*/
public $pa_ht ;
2021-03-08 10:33:07 +00:00
2024-10-13 14:45:42 +00:00
/**
* @ var string
*/
2021-03-08 10:33:07 +00:00
public $marge_tx ;
2024-10-13 14:45:42 +00:00
/**
* @ var string
*/
2021-03-08 10:33:07 +00:00
public $marque_tx ;
2015-03-23 00:39:12 +00:00
/**
2019-10-19 16:33:06 +00:00
* List of cumulative options :
2020-11-10 12:20:45 +00:00
* Bit 0 : 0 for common VAT - 1 if VAT french NPR
2026-01-21 17:23:03 +00:00
* Bit 1 : 0 if standard line - 1 if bit discount ( link to line into llx_remise_except )
2015-03-23 00:39:12 +00:00
* @ var int
*/
public $info_bits = 0 ;
2024-03-28 11:54:08 +00:00
/**
* List of special options to define line :
2024-03-28 19:16:32 +00:00
* 1 : shipment cost lines
* 2 : ecotaxe
* 3 : ? ?
* id of module : a meaning for the module
* @ var int
2024-03-28 11:54:08 +00:00
*/
2024-03-28 19:16:32 +00:00
public $special_code = 0 ;
2020-11-08 11:34:45 +00:00
2024-02-23 12:28:17 +00:00
/**
2024-10-13 14:45:42 +00:00
* @ var int
2024-02-23 12:28:17 +00:00
* @ deprecated Use user_creation_id
*/
2021-03-08 10:33:07 +00:00
public $fk_user_author ;
2024-03-28 19:16:32 +00:00
2024-02-23 12:28:17 +00:00
/**
2024-10-13 14:45:42 +00:00
* @ var int
2024-02-23 12:28:17 +00:00
* @ deprecated Use user_modification_id
*/
2021-03-08 10:33:07 +00:00
public $fk_user_modif ;
2022-06-11 19:53:14 +00:00
2024-10-13 14:45:42 +00:00
/**
* @ var int
*/
2026-01-05 12:28:09 +00:00
public $fk_code_ventilation ;
2026-01-26 15:11:21 +00:00
/**
* @ var float Situation advance percentage ( default 100 for standard invoices )
*/
2026-01-29 09:42:44 +00:00
public $situation_percent = 100 ;
2026-04-27 13:40:05 +00:00
/**
* Check if a line is a deposit line
*
* @ return bool True if line is a deposit , false otherwise
*/
public function isDepositLine ()
{
// Do not take into account lines of the type "deposit."
$reg = array ();
if ( preg_match ( '/^\((.*)\)$/' , $this -> desc , $reg )) {
if ( $reg [ 1 ] == 'DEPOSIT' ) {
return true ;
}
}
return false ;
}
2013-06-10 14:05:41 +00:00
}