NEW Support different bank account for several direct debit payments

This commit is contained in:
Laurent Destailleur 2023-02-27 15:58:15 +01:00
parent 14d6c5fbdb
commit 570748ad79
4 changed files with 340 additions and 287 deletions

View File

@ -1,4 +1,6 @@
<?php
use Stripe\BankAccount;
/* Copyright (C) 2002-2005 Rodolphe Quiedeville <rodolphe@quiedeville.org>
* Copyright (C) 2004 Eric Seigne <eric.seigne@ryxeo.com>
* Copyright (C) 2004-2016 Laurent Destailleur <eldy@users.sourceforge.net>
@ -138,7 +140,7 @@ if (empty($reshook)) {
}
}
// Payment with Direct Debit Stripe
// Make payment with Direct Debit Stripe
if ($action == 'sepastripepayment' && $usercancreate) {
$result = $object->makeStripeSepaRequest($user, GETPOST('did', 'int'), 'direct-debit', 'facture');
if ($result < 0) {
@ -153,7 +155,7 @@ if (empty($reshook)) {
}
}
// payments conditions
// Set payments conditions
if ($action == 'setconditions' && $usercancreate) {
$object->fetch($id);
$object->cond_reglement_code = 0; // To clean property
@ -915,7 +917,7 @@ if ($object->id > 0) {
// Past requests
$sql = "SELECT pfd.rowid, pfd.traite, pfd.date_demande, pfd.date_traite, pfd.fk_prelevement_bons, pfd.amount,";
$sql .= " pb.ref, pb.date_trans, pb.method_trans, pb.credite, pb.date_credit, pb.datec, pb.statut as status,";
$sql .= " pb.ref, pb.date_trans, pb.method_trans, pb.credite, pb.date_credit, pb.datec, pb.statut as status, pb.fk_bank_account,";
$sql .= " u.rowid as user_id, u.email, u.lastname, u.firstname, u.login, u.statut as user_status";
$sql .= " FROM ".MAIN_DB_PREFIX."prelevement_demande as pfd";
$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."user as u on pfd.fk_user_demande = u.rowid";
@ -929,16 +931,16 @@ if ($object->id > 0) {
$sql .= " AND pfd.type = 'ban'";
$sql .= " ORDER BY pfd.date_demande DESC";
$result = $db->query($sql);
if ($result) {
$num = $db->num_rows($result);
$resql = $db->query($sql);
if ($resql) {
$num = $db->num_rows($resql);
$numclosed = $num;
$i = 0;
$tmpuser = new User($db);
while ($i < $num) {
$obj = $db->fetch_object($result);
$obj = $db->fetch_object($resql);
$tmpuser->id = $obj->user_id;
$tmpuser->login = $obj->login;
@ -975,9 +977,26 @@ if ($object->id > 0) {
$withdrawreceipt->date_creation = $db->jdate($obj->datec);
$withdrawreceipt->statut = $obj->status;
$withdrawreceipt->status = $obj->status;
$withdrawreceipt->fk_bank_account = $obj->fk_bank_account;
//$withdrawreceipt->credite = $db->jdate($obj->credite);
print $withdrawreceipt->getNomUrl(1);
print ' ';
print $withdrawreceipt->getLibStatut(2);
// Show the bank account
$fk_bank_account = $withdrawreceipt->fk_bank_account;
if (empty($fk_bank_account)) {
$fk_bank_account = ($object->type == 'bank-transfer' ? $conf->global->PAYMENTBYBANKTRANSFER_ID_BANKACCOUNT : $conf->global->PRELEVEMENT_ID_BANKACCOUNT);
}
if ($fk_bank_account > 0) {
$bankaccount = new Account($db);
$result = $bankaccount->fetch($fk_bank_account);
if ($result > 0) {
print ' - ';
print $bankaccount->getNomUrl(1);
}
}
}
print "</td>\n";
@ -995,7 +1014,7 @@ if ($object->id > 0) {
print '<tr class="oddeven"><td colspan="7"><span class="opacitymedium">'.$langs->trans("None").'</span></td></tr>';
}
$db->free($result);
$db->free($resql);
} else {
dol_print_error($db);
}

View File

@ -215,7 +215,8 @@ if ($id > 0 || $ref) {
$result = $acc->fetch($object->fk_bank_account);
} else { // For backward compatibility
$acc = new Account($db);
$result = $acc->fetch(($object->type == 'bank-transfer' ? $conf->global->PAYMENTBYBANKTRANSFER_ID_BANKACCOUNT : $conf->global->PRELEVEMENT_ID_BANKACCOUNT));
$fk_bank_account = ($object->type == 'bank-transfer' ? $conf->global->PAYMENTBYBANKTRANSFER_ID_BANKACCOUNT : $conf->global->PRELEVEMENT_ID_BANKACCOUNT);
$result = $acc->fetch($fk_bank_account);
}
print '<tr><td class="titlefieldcreate">';

View File

@ -92,6 +92,7 @@ class BonPrelevement extends CommonObject
public $user_credit;
public $type;
public $fk_bank_account; // The bank the receipt is generated for
const STATUS_DRAFT = 0;
const STATUS_TRANSFERED = 1;
@ -299,6 +300,7 @@ class BonPrelevement extends CommonObject
$sql .= ", p.date_credit as date_credit";
$sql .= ", p.fk_user_credit";
$sql .= ", p.type";
$sql .= ", p.fk_bank_account";
$sql .= ", p.statut as status";
$sql .= " FROM ".MAIN_DB_PREFIX."prelevement_bons as p";
$sql .= " WHERE p.entity IN (".getEntity('invoice').")";
@ -328,6 +330,7 @@ class BonPrelevement extends CommonObject
$this->user_credit = $obj->fk_user_credit;
$this->type = $obj->type;
$this->fk_bank_account = $obj->fk_bank_account;
$this->status = $obj->status;
$this->statut = $obj->status; // For backward compatibility
@ -369,7 +372,7 @@ class BonPrelevement extends CommonObject
$this->db->begin();
$sql = " UPDATE ".MAIN_DB_PREFIX."prelevement_bons ";
$sql = " UPDATE ".MAIN_DB_PREFIX."prelevement_bons";
$sql .= " SET fk_user_credit = ".$user->id;
$sql .= ", statut = ".self::STATUS_CREDITED;
$sql .= ", date_credit = '".$this->db->idate($date)."'";
@ -383,8 +386,12 @@ class BonPrelevement extends CommonObject
$subject = $langs->trans("InfoCreditSubject", $this->ref);
$message = $langs->trans("InfoCreditMessage", $this->ref, dol_print_date($date, 'dayhour'));
//Add payment of withdrawal into bank
$bankaccount = ($this->type == 'bank-transfer' ? $conf->global->PAYMENTBYBANKTRANSFER_ID_BANKACCOUNT : $conf->global->PRELEVEMENT_ID_BANKACCOUNT);
// Add payment of withdrawal into bank
$fk_bank_account = $this->fk_bank_account;
if (empty($fk_bank_account)) {
$fk_bank_account = ($this->type == 'bank-transfer' ? $conf->global->PAYMENTBYBANKTRANSFER_ID_BANKACCOUNT : $conf->global->PRELEVEMENT_ID_BANKACCOUNT);
}
$facs = array();
$amounts = array();
$amountsperthirdparty = array();
@ -455,7 +462,7 @@ class BonPrelevement extends CommonObject
$modeforaddpayment = 'payment';
}
$result = $paiement->addPaymentToBank($user, $modeforaddpayment, '(WithdrawalPayment)', $bankaccount, '', '');
$result = $paiement->addPaymentToBank($user, $modeforaddpayment, '(WithdrawalPayment)', $fk_bank_account, '', '');
if ($result < 0) {
$error++;
$this->error = $paiement->error;
@ -742,17 +749,18 @@ class BonPrelevement extends CommonObject
* - Link the order with the prelevement_demande lines
* TODO delete params banque and agence when not necessary
*
* @param int $banque dolibarr mysoc bank
* @param int $agence dolibarr mysoc bank office (guichet)
* @param string $mode real=do action, simu=test only
* @param string $format FRST, RCUR or ALL
* @param string $executiondate Date to execute the transfer
* @param int $notrigger Disable triggers
* @param string $type 'direct-debit' or 'bank-transfer'
* @param int $did ID of an existing payment request. If $did is defined, no entry
* @return int <0 if KO, No of invoice included into file if OK
* @param int $banque dolibarr mysoc bank
* @param int $agence dolibarr mysoc bank office (guichet)
* @param string $mode real=do action, simu=test only
* @param string $format FRST, RCUR or ALL
* @param string $executiondate Date to execute the transfer
* @param int $notrigger Disable triggers
* @param string $type 'direct-debit' or 'bank-transfer'
* @param int $did ID of an existing payment request. If $did is defined, no entry
* @param int $fk_bank_account Bank account ID the receipt is generated for. Will use the ID into the setup of module Direct Debit or Credit Transfer if 0.
* @return int <0 if KO, No of invoice included into file if OK
*/
public function create($banque = 0, $agence = 0, $mode = 'real', $format = 'ALL', $executiondate = '', $notrigger = 0, $type = 'direct-debit', $did = 0)
public function create($banque = 0, $agence = 0, $mode = 'real', $format = 'ALL', $executiondate = '', $notrigger = 0, $type = 'direct-debit', $did = 0, $fk_bank_account = 0)
{
// phpcs:enable
global $conf, $langs, $user;
@ -762,6 +770,7 @@ class BonPrelevement extends CommonObject
require_once DOL_DOCUMENT_ROOT."/compta/facture/class/facture.class.php";
require_once DOL_DOCUMENT_ROOT."/societe/class/societe.class.php";
// Check params
if ($type != 'bank-transfer') {
if (empty($format)) {
$this->error = 'ErrorBadParametersForDirectDebitFileCreate';
@ -769,6 +778,11 @@ class BonPrelevement extends CommonObject
}
}
// Clean params
if (empty($fk_bank_account)) {
$fk_bank_account = ($type == 'bank-transfer' ? $conf->global->PAYMENTBYBANKTRANSFER_ID_BANKACCOUNT : $conf->global->PRELEVEMENT_ID_BANKACCOUNT);
}
$error = 0;
$datetimeprev = dol_now('gmt');
@ -969,12 +983,13 @@ class BonPrelevement extends CommonObject
// Create withdraw order in database
$sql = "INSERT INTO ".MAIN_DB_PREFIX."prelevement_bons (";
$sql .= "ref, entity, datec, type";
$sql .= "ref, entity, datec, type, fk_bank_account";
$sql .= ") VALUES (";
$sql .= "'".$this->db->escape($ref)."'";
$sql .= ", ".((int) $conf->entity);
$sql .= ", '".$this->db->idate($now)."'";
$sql .= ", '".($type == 'bank-transfer' ? 'bank-transfer' : 'debit-order')."'";
$sql .= ", ".((int) $fk_bank_account);
$sql .= ")";
$resql = $this->db->query($sql);
@ -1055,12 +1070,8 @@ class BonPrelevement extends CommonObject
$this->date_echeance = $datetimeprev;
$this->reference_remise = $ref;
$id = $conf->global->PRELEVEMENT_ID_BANKACCOUNT;
if ($type == 'bank-transfer') {
$id = $conf->global->PAYMENTBYBANKTRANSFER_ID_BANKACCOUNT;
}
$account = new Account($this->db);
if ($account->fetch($id) > 0) {
if ($account->fetch($fk_bank_account) > 0) {
$this->emetteur_code_banque = $account->code_banque;
$this->emetteur_code_guichet = $account->code_guichet;
$this->emetteur_numero_compte = $account->number;
@ -1382,16 +1393,22 @@ class BonPrelevement extends CommonObject
* File is generated with name this->filename
*
* @param string $format FRST, RCUR or ALL
* @param string $executiondate Date to execute transfer
* @param int $executiondate Timestamp date to execute transfer
* @param string $type 'direct-debit' or 'bank-transfer'
* @param int $fk_bank_account Bank account ID the receipt is generated for. Will use the ID into the setup of module Direct Debit or Credit Transfer if 0.
* @return int >=0 if OK, <0 if KO
*/
public function generate($format = 'ALL', $executiondate = '', $type = 'direct-debit')
public function generate($format = 'ALL', $executiondate = 0, $type = 'direct-debit', $fk_bank_account = 0)
{
global $conf, $langs, $mysoc;
//TODO: Optimize code to read lines in a single function
// Clean params
if (empty($fk_bank_account)) {
$fk_bank_account = ($type == 'bank-transfer' ? $conf->global->PAYMENTBYBANKTRANSFER_ID_BANKACCOUNT : $conf->global->PRELEVEMENT_ID_BANKACCOUNT);
}
$result = 0;
dol_syslog(get_class($this)."::generate build file=".$this->filename." type=".$type);
@ -1486,7 +1503,7 @@ class BonPrelevement extends CommonObject
// Define $fileEmetteurSection. Start of bloc PmtInf. Will contains all $nbtotalDrctDbtTxInf
if ($result != -2) {
$fileEmetteurSection .= $this->EnregEmetteurSEPA($conf, $date_actu, $nbtotalDrctDbtTxInf, $this->total, $CrLf, $format, $type);
$fileEmetteurSection .= $this->EnregEmetteurSEPA($conf, $date_actu, $nbtotalDrctDbtTxInf, $this->total, $CrLf, $format, $type, $fk_bank_account);
}
/**
@ -2041,31 +2058,36 @@ class BonPrelevement extends CommonObject
* Write sender of request (me).
* Note: The tag PmtInf is opened here but closed into caller
*
* @param Conf $configuration conf
* @param int $ladate Date
* @param int $nombre 0 or 1
* @param float $total Total
* @param string $CrLf End of line character
* @param string $format FRST or RCUR or ALL
* @param string $type 'direct-debit' or 'bank-transfer'
* @return string String with SEPA Sender
* @param Conf $configuration conf
* @param int $ladate Date
* @param int $nombre 0 or 1
* @param float $total Total
* @param string $CrLf End of line character
* @param string $format FRST or RCUR or ALL
* @param string $type 'direct-debit' or 'bank-transfer'
* @param int $fk_bank_account Bank account ID the receipt is generated for. Will use the ID into the setup of module Direct Debit or Credit Transfer if 0.
* @return string String with SEPA Sender
* @see EnregEmetteur()
*/
public function EnregEmetteurSEPA($configuration, $ladate, $nombre, $total, $CrLf = '\n', $format = 'FRST', $type = 'direct-debit')
public function EnregEmetteurSEPA($configuration, $ladate, $nombre, $total, $CrLf = '\n', $format = 'FRST', $type = 'direct-debit', $fk_bank_account = 0)
{
// phpcs:enable
// SEPA INITIALISATION
global $conf;
// Clean parameters
$dateTime_YMD = dol_print_date($ladate, '%Y%m%d');
$dateTime_ETAD = dol_print_date($ladate, '%Y-%m-%d');
$dateTime_YMDHMS = dol_print_date($ladate, '%Y-%m-%dT%H:%M:%S');
// Clean params
if (empty($fk_bank_account)) {
$fk_bank_account = ($type == 'bank-transfer' ? $conf->global->PAYMENTBYBANKTRANSFER_ID_BANKACCOUNT : $conf->global->PRELEVEMENT_ID_BANKACCOUNT);
}
// Get data of bank account
//$id = $configuration->global->PRELEVEMENT_ID_BANKACCOUNT;
$id = ($type == 'bank-transfer' ? $conf->global->PAYMENTBYBANKTRANSFER_ID_BANKACCOUNT : $conf->global->PRELEVEMENT_ID_BANKACCOUNT);
$account = new Account($this->db);
if ($account->fetch($id) > 0) {
if ($account->fetch($fk_bank_account) > 0) {
$this->emetteur_code_banque = $account->code_banque;
$this->emetteur_code_guichet = $account->code_guichet;
$this->emetteur_numero_compte = $account->number;
@ -2081,8 +2103,7 @@ class BonPrelevement extends CommonObject
// Get pending payments
$sql = "SELECT rowid, ref";
$sql .= " FROM";
$sql .= " ".MAIN_DB_PREFIX."prelevement_bons as pb";
$sql .= " FROM ".MAIN_DB_PREFIX."prelevement_bons as pb";
$sql .= " WHERE pb.rowid = ".((int) $this->id);
$resql = $this->db->query($sql);
@ -2294,10 +2315,10 @@ class BonPrelevement extends CommonObject
}
/**
* Return status label of object
* Return status label of object
*
* @param int $mode 0=Label, 1=Picto + label, 2=Picto, 3=Label + Picto
* @return string Label
* @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
* @return string Label
*/
public function getLibStatut($mode = 0)
{

View File

@ -900,7 +900,7 @@ abstract class CommonInvoice extends CommonObject
dol_syslog(get_class($this)."::makeStripeSepaRequest start", LOG_DEBUG);
if ($this->statut > self::STATUS_DRAFT && $this->paye == 0) {
// Get the default payment mode for BAN payment
// Get the default payment mode for BAN payment of the third party
require_once DOL_DOCUMENT_ROOT.'/societe/class/companybankaccount.class.php';
$bac = new CompanyBankAccount($this->db); // table societe_rib
$result = $bac->fetch(0, $this->socid, 1, 'ban');
@ -974,295 +974,307 @@ abstract class CommonInvoice extends CommonObject
$amountstripe = $amountstripe * 100;
}
$fk_bank_account = getDolGlobalInt('STRIPE_BANK_ACCOUNT_FOR_PAYMENTS');
if (!($fk_bank_account > 0)) {
$error++;
$errorforinvoice++;
dol_syslog("Error no bank account defined for Stripe payments", LOG_ERR);
$this->errors[] = "Error bank account for Stripe payments not defined into Stripe module";
}
$this->db->begin();
// Create a prelevement_bon
$bon = new BonPrelevement($this->db);
if (empty($obj->fk_prelevement_bons)) {
// This create record into llx_prelevment_bons and update link with llx_prelevement_demande
$nbinvoices = $bon->create(0, 0, 'real', 'ALL', '', 0, 'direct-debit', $did);
if ($nbinvoices <= 0) {
if (!$error) {
if (empty($obj->fk_prelevement_bons)) {
// This create record into llx_prelevment_bons and update link with llx_prelevement_demande
$nbinvoices = $bon->create(0, 0, 'real', 'ALL', '', 0, 'direct-debit', $did, $fk_bank_account);
if ($nbinvoices <= 0) {
$error++;
$errorforinvoice++;
dol_syslog("Error on BonPrelevement creation", LOG_ERR);
$this->errors[] = "Error on BonPrelevement creation";
}
/*
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++;
$this->errors[] = "Error on updateing fk_prelevement_bons to ".$bon->id;
}
}
*/
} else {
$error++;
$errorforinvoice++;
dol_syslog("Error on BonPrelevement creation", LOG_ERR);
$this->errors[] = "Error on BonPrelevement creation";
dol_syslog("Error Line already part of a bank payment order", LOG_ERR);
$this->errors[] = "The line is already included into a bank payment order. Delete the bank payment order first.";
}
/*
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++;
$this->errors[] = "Error on updateing fk_prelevement_bons to ".$bon->id;
}
}
*/
} else {
$error++;
$errorforinvoice++;
dol_syslog("Error Line already part of a bank payment order", LOG_ERR);
$this->errors[] = "The line is already included into a bank payment order. Delete the bank payment order first.";
}
if (!$error && $amountstripe > 0) {
try {
//var_dump($companypaymentmode);
dol_syslog("We will try to pay with companypaymentmodeid=" . $companypaymentmode->id . " stripe_card_ref=" . $companypaymentmode->stripe_card_ref . " mode=" . $companypaymentmode->status, LOG_DEBUG);
if (!$error) {
if ($amountstripe > 0) {
try {
//var_dump($companypaymentmode);
dol_syslog("We will try to pay with companypaymentmodeid=" . $companypaymentmode->id . " stripe_card_ref=" . $companypaymentmode->stripe_card_ref . " mode=" . $companypaymentmode->status, LOG_DEBUG);
$thirdparty = new Societe($this->db);
$resultthirdparty = $thirdparty->fetch($this->socid);
$thirdparty = new Societe($this->db);
$resultthirdparty = $thirdparty->fetch($this->socid);
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);
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);
dol_syslog("makeStripeSepaRequest Current Stripe environment is " . $stripearrayofkeysbyenv[$servicestatus]['publishable_key']);
dol_syslog("makeStripeSepaRequest Current Stripe environment is " . $stripearrayofkeysbyenv[$servicestatus]['publishable_key']);
$stripearrayofkeys = $stripearrayofkeysbyenv[$servicestatus];
\Stripe\Stripe::setApiKey($stripearrayofkeys['secret_key']);
$stripearrayofkeys = $stripearrayofkeysbyenv[$servicestatus];
\Stripe\Stripe::setApiKey($stripearrayofkeys['secret_key']);
dol_syslog("makeStripeSepaRequest get stripe connet account", LOG_DEBUG);
$stripeacc = $stripe->getStripeAccount($service, $this->socid); // Get Stripe OAuth connect account if it exists (no network access here)
dol_syslog("makeStripeSepaRequest get stripe connect account return " . json_encode($stripeacc), LOG_DEBUG);
dol_syslog("makeStripeSepaRequest get stripe connet account", LOG_DEBUG);
$stripeacc = $stripe->getStripeAccount($service, $this->socid); // Get Stripe OAuth connect account if it exists (no network access here)
dol_syslog("makeStripeSepaRequest get stripe connect account return " . json_encode($stripeacc), LOG_DEBUG);
$customer = $stripe->customerStripe($thirdparty, $stripeacc, $servicestatus, 0);
if (empty($customer) && !empty($stripe->error)) {
$this->errors[] = $stripe->error;
}
$customer = $stripe->customerStripe($thirdparty, $stripeacc, $servicestatus, 0);
if (empty($customer) && !empty($stripe->error)) {
$this->errors[] = $stripe->error;
}
// $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 = [];
// $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 = [];
if ($resultthirdparty > 0 && !empty($customer)) {
if (!$error) { // Payment was not canceled
$sepaMode = false;
$stripecard = null;
if ($companypaymentmode->type == 'ban') {
$sepaMode = true;
// Check into societe_rib if a payment mode for Stripe and ban payment exists
// To make a Stripe SEPA payment request, we must have the payment mode source already saved into societe_rib and retreived with ->sepaStripe
// 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);
}
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)
dol_syslog(var_export($paymentintent, true), LOG_DEBUG);
$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 {
dol_syslog(var_export($paymentintent, true), LOG_DEBUG);
$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;
if ($resultthirdparty > 0 && !empty($customer)) {
if (!$error) { // Payment was not canceled
$sepaMode = false;
$stripecard = null;
if ($companypaymentmode->type == 'ban') {
$sepaMode = true;
// Check into societe_rib if a payment mode for Stripe and ban payment exists
// To make a Stripe SEPA payment request, we must have the payment mode source already saved into societe_rib and retreived with ->sepaStripe
// 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);
}
//var_dump("stripefailurecode=".$stripefailurecode." stripefailuremessage=".$stripefailuremessage." stripefailuredeclinecode=".$stripefailuredeclinecode);
//exit;
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 = '';
// 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);
// Using new SCA method
dol_syslog("* Create payment on SEPA " . $stripecard->id . ", amounttopay=" . $amounttopay . ", amountstripe=" . $amountstripe . ", FULLTAG=" . $FULLTAG, LOG_DEBUG);
// Save a stripe payment was in error
$this->stripechargeerror++;
// 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);
$error++;
$errorforinvoice++;
$errmsg = $langs->trans("FailedToChargeCard");
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;
}
}
$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)
dol_syslog(var_export($paymentintent, true), LOG_DEBUG);
$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 {
$errmsg .= ': ' . $stripefailurecode . ' - ' . $stripefailuremessage;
$errmsg .= ($stripefailuredeclinecode ? ' - ' . $stripefailuredeclinecode : '');
dol_syslog(var_export($paymentintent, true), LOG_DEBUG);
$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;
}
$description = 'Stripe payment ERROR from makeStripeSepaRequest: ' . $FULLTAG;
$postactionmessages[] = $errmsg . ' (' . $stripearrayofkeys['publishable_key'] . ')';
$this->errors[] = $errmsg;
//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++;
$errmsg = $langs->trans("FailedToChargeCard");
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;
}
}
} else {
$errmsg .= ': ' . $stripefailurecode . ' - ' . $stripefailuremessage;
$errmsg .= ($stripefailuredeclinecode ? ' - ' . $stripefailuredeclinecode : '');
}
$description = 'Stripe payment ERROR from makeStripeSepaRequest: ' . $FULLTAG;
$postactionmessages[] = $errmsg . ' (' . $stripearrayofkeys['publishable_key'] . ')';
$this->errors[] = $errmsg;
} else {
dol_syslog('Successfuly request direct debit ' . $stripecard->id);
$postactionmessages[] = 'Success to request direct debit (' . $charge->id . ' with ' . $stripearrayofkeys['publishable_key'] . ')';
// Save a stripe payment was done in realy life so later we will be able to force a commit on recorded payments
// even if in batch mode (method doTakePaymentStripe), we will always make all action in one transaction with a forced commit.
$this->stripechargedone++;
// Default description used for label of event. Will be overwrite by another value later.
$description = 'Stripe payment request OK (' . $charge->id . ') from makeStripeSepaRequest: ' . $FULLTAG;
}
$object = $this;
// 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';
$extraparams = '';
}
} else {
dol_syslog('Successfuly request direct debit ' . $stripecard->id);
$error++;
$errorforinvoice++;
dol_syslog("No direct debit payment method found for this stripe customer " . $customer->id, LOG_WARNING);
$this->errors[] = 'Failed to get direct debit payment method for stripe customer = ' . $customer->id;
$postactionmessages[] = 'Success to request direct debit (' . $charge->id . ' with ' . $stripearrayofkeys['publishable_key'] . ')';
$description = 'Failed to find or use the payment mode - no credit card defined for the customer account';
$stripefailurecode = 'BADPAYMENTMODE';
$stripefailuremessage = 'Failed to find or use the payment mode - no credit card defined for the customer account';
$postactionmessages[] = $description . ' (' . $stripearrayofkeys['publishable_key'] . ')';
// Save a stripe payment was done in realy life so later we will be able to force a commit on recorded payments
// even if in batch mode (method doTakePaymentStripe), we will always make all action in one transaction with a forced commit.
$this->stripechargedone++;
$object = $this;
// Default description used for label of event. Will be overwrite by another value later.
$description = 'Stripe payment request OK (' . $charge->id . ') from makeStripeSepaRequest: ' . $FULLTAG;
}
$object = $this;
// 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';
$extraparams = '';
}
} else {
$error++;
$errorforinvoice++;
dol_syslog("No direct debit payment method found for this stripe customer " . $customer->id, LOG_WARNING);
$this->errors[] = 'Failed to get direct debit payment method for stripe customer = ' . $customer->id;
$description = 'Failed to find or use the payment mode - no credit card defined for the customer account';
$stripefailurecode = 'BADPAYMENTMODE';
$stripefailuremessage = 'Failed to find or use the payment mode - no credit card defined for the customer account';
$postactionmessages[] = $description . ' (' . $stripearrayofkeys['publishable_key'] . ')';
// If error because payment was canceled for a logical reason, we do nothing (no event added)
$description = '';
$stripefailurecode = '';
$stripefailuremessage = '';
$object = $this;
$actioncode = 'PAYMENT_STRIPE_KO';
$actioncode = '';
$extraparams = '';
}
} else {
// If error because payment was canceled for a logical reason, we do nothing (no event added)
$description = '';
$stripefailurecode = '';
$stripefailuremessage = '';
} 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);
$this->errors[] = 'Failed to load customer for thirdparty_id = ' . $thirdparty->id;
} 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);
$this->errors[] = 'Failed to get Stripe customer id for thirdparty_id = ' . $thirdparty->id . " in mode " . $servicestatus . " in Stripe env " . $stripearrayofkeysbyenv[$servicestatus]['publishable_key'];
}
$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)';
$postactionmessages = [];
$object = $this;
$actioncode = '';
$actioncode = 'PAYMENT_STRIPE_KO';
$extraparams = '';
}
} 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);
$this->errors[] = 'Failed to load customer for thirdparty_id = ' . $thirdparty->id;
} 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);
$this->errors[] = 'Failed to get Stripe customer id for thirdparty_id = ' . $thirdparty->id . " in mode " . $servicestatus . " in Stripe env " . $stripearrayofkeysbyenv[$servicestatus]['publishable_key'];
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;
$actioncomm->note_private = join(",\n", $postactionmessages);
$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;
$actioncomm->elementtype = $this->element;
$actioncomm->extraparams = dol_trunc($extraparams, 250);
$actioncomm->create($user);
}
$this->description = $description;
$this->postactionmessages = $postactionmessages;
} catch (Exception $e) {
$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)';
$postactionmessages = [];
$object = $this;
$actioncode = 'PAYMENT_STRIPE_KO';
$extraparams = '';
dol_syslog('Error ' . $e->getMessage(), LOG_ERR);
$this->errors[] = 'Error ' . $e->getMessage();
}
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;
$actioncomm->note_private = join(",\n", $postactionmessages);
$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;
$actioncomm->elementtype = $this->element;
$actioncomm->extraparams = dol_trunc($extraparams, 250);
$actioncomm->create($user);
}
$this->description = $description;
$this->postactionmessages = $postactionmessages;
} catch (Exception $e) {
} else { // If remain to pay is null
$error++;
$errorforinvoice++;
dol_syslog('Error ' . $e->getMessage(), LOG_ERR);
$this->errors[] = 'Error ' . $e->getMessage();
dol_syslog("Remain to pay is null for the invoice " . $this->id . " " . $this->ref . ". Why is the invoice not classified 'Paid' ?", LOG_WARNING);
$this->errors[] = "Remain to pay is null for the invoice " . $this->id . " " . $this->ref . ". Why is the invoice not classified 'Paid' ?";
}
} else { // If remain to pay is null
$error++;
$errorforinvoice++;
dol_syslog("Remain to pay is null for the invoice " . $this->id . " " . $this->ref . ". Why is the invoice not classified 'Paid' ?", LOG_WARNING);
$this->errors[] = "Remain to pay is null for the invoice " . $this->id . " " . $this->ref . ". Why is the invoice not classified 'Paid' ?";
}
// Set status of the order to "Transferred" with method 'api'