From 06fafc9d7b7358684d13e0af768d5269220352ef Mon Sep 17 00:00:00 2001 From: lmarcouiller Date: Thu, 1 Sep 2022 15:04:30 +0200 Subject: [PATCH 1/2] New : Add action to push banque account in Stripe account --- htdocs/societe/paymentmodes.php | 42 ++++++++- htdocs/stripe/class/stripe.class.php | 123 +++++++++++++++++++++++++++ 2 files changed, 163 insertions(+), 2 deletions(-) diff --git a/htdocs/societe/paymentmodes.php b/htdocs/societe/paymentmodes.php index 5b9bd1046ef..7d082440661 100644 --- a/htdocs/societe/paymentmodes.php +++ b/htdocs/societe/paymentmodes.php @@ -516,6 +516,40 @@ if (empty($reshook)) { } } } + if ($action == 'syncsepatostripe') { + $companybankaccount->fetch(GETPOST('bankid')); + // print "stripe account = " . json_encode($stripe->getStripeAccount($service)); + // print json_encode($companybankaccount); + // print "fetch id = " . json_encode($socid); + + $companypaymentmode = new CompanyPaymentMode($db); + $companypaymentmode->fetch(null, null, $socid); + // print json_encode($companypaymentmode); + + if ($companypaymentmode->type != 'ban') { + $error++; + setEventMessages('ThisPaymentModeIsNotSepa', null, 'errors'); + } else { + // Get the Stripe customer + $cu = $stripe->customerStripe($object, $stripeacc, $servicestatus); + // print json_encode($cu); + if (!$cu) { + $error++; + setEventMessages($stripe->error, $stripe->errors, 'errors'); + } + + if (!$error) { + // Creation of Stripe SEPA + update of societe_account + $card = $stripe->sepaStripe($cu, $companypaymentmode, $stripeacc, $servicestatus, 1); + if (!$card) { + $error++; + setEventMessages($stripe->error, $stripe->errors, 'errors'); + } else { + setEventMessages("", array("SEPA on Stripe", "SEPA IBAN is now linked to customer account !")); + } + } + } + } if ($action == 'setkey_account') { $error = 0; @@ -632,7 +666,7 @@ if (empty($reshook)) { } elseif ($action == 'setassourcedefault') { // Set as default when payment mode defined remotely only try { $cu = $stripe->customerStripe($object, $stripeacc, $servicestatus); - if (preg_match('/pm_/', $source)) { + if (preg_match('/pm_|src_/', $source)) { $cu->invoice_settings->default_payment_method = (string) $source; // New } else { $cu->default_source = (string) $source; // Old @@ -660,6 +694,10 @@ if (empty($reshook)) { // $card->detach(); Does not work with card_, only with src_ if (method_exists($card, 'detach')) { $card->detach(); + $sql = "UPDATE ".MAIN_DB_PREFIX."societe_rib as sr "; + $sql .= " SET stripe_card_ref = null"; + $sql .= " WHERE sr.stripe_card_ref = '".$db->escape($source)."'"; + $resql = $db->query($sql); } else { $card->delete(); } @@ -1465,7 +1503,7 @@ if ($socid && $action != 'edit' && $action != 'create' && $action != 'editcard' // Edit/Delete print ''; if ($permissiontoaddupdatepaymentinformation) { - print ''; + print ''; print img_picto($langs->trans("CreateBAN"), 'stripe'); print ''; diff --git a/htdocs/stripe/class/stripe.class.php b/htdocs/stripe/class/stripe.class.php index 5ec149ba07f..6814dc3757f 100644 --- a/htdocs/stripe/class/stripe.class.php +++ b/htdocs/stripe/class/stripe.class.php @@ -588,7 +588,130 @@ class Stripe extends CommonObject return null; } } + /** + * Get the Stripe SEPA of a company payment mode + * + * @param \Stripe\StripeCustomer $cu Object stripe customer. + * @param CompanyPaymentMode $object Object companypaymentmode to check, or create on stripe (create on stripe also update the societe_rib table for current entity) + * @param string $stripeacc ''=Use common API. If not '', it is the Stripe connect account 'acc_....' to use Stripe connect + * @param int $status Status (0=test, 1=live) + * @param int $createifnotlinkedtostripe 1=Create the stripe sepa and the link if the sepa is not yet linked to a stripe sepa. Deprecated with new Stripe API and SCA. + * @return \Stripe\PaymentMethod|null Stripe SEPA or null if not found + */ + public function sepaStripe($cu, CompanyPaymentMode $object, $stripeacc = '', $status = 0, $createifnotlinkedtostripe = 0) + { + global $conf, $user, $langs; + $sepa = null; + $sql = "SELECT sa.stripe_card_ref, sa.proprio, sa.iban_prefix"; // stripe_card_ref is src_ for sepa + $sql .= " FROM ".MAIN_DB_PREFIX."societe_rib as sa"; + $sql .= " WHERE sa.rowid = ".$object->id; // We get record from ID, no need for filter on entity + $sql .= " AND sa.type = 'ban'"; //type ban to get normal bank account of customer (prelevement) + + $soc = new Societe($this->db); + $soc->fetch($object->fk_soc); + + dol_syslog(get_class($this)."::fetch search stripe sepa(card) id for paymentmode id=".$object->id.", stripeacc=".$stripeacc.", status=".$status.", createifnotlinkedtostripe=".$createifnotlinkedtostripe, LOG_DEBUG); + $resql = $this->db->query($sql); + if ($resql) { + $num = $this->db->num_rows($resql); + if ($num) { + $obj = $this->db->fetch_object($resql); + $cardref = $obj->stripe_card_ref; + dol_syslog(get_class($this)."::cardStripe cardref=".$cardref); + if ($cardref) { + try { + if (empty($stripeacc)) { // If the Stripe connect account not set, we use common API usage + if (!preg_match('/^pm_/', $cardref) && !empty($cu->sources)) { + $sepa = $cu->sources->retrieve($cardref); + } else { + $sepa = \Stripe\PaymentMethod::retrieve($cardref); + } + } else { + if (!preg_match('/^pm_/', $cardref) && !empty($cu->sources)) { + //$sepa = $cu->sources->retrieve($cardref, array("stripe_account" => $stripeacc)); // this API fails when array stripe_account is provided + $sepa = $cu->sources->retrieve($cardref); + } else { + //$sepa = \Stripe\PaymentMethod::retrieve($cardref, array("stripe_account" => $stripeacc)); // Don't know if this works + $sepa = \Stripe\PaymentMethod::retrieve($cardref); + } + } + } catch (Exception $e) { + $this->error = $e->getMessage(); + dol_syslog($this->error, LOG_WARNING); + } + } elseif ($createifnotlinkedtostripe) { + $iban = $obj->iban_prefix; //prefix ? + $ipaddress = getUserRemoteIP(); + + $dataforcard = array( + 'type'=>'sepa_debit', + "sepa_debit" => array('iban' => $iban), + 'currency' => 'eur', + 'usage' => 'reusable', + 'owner' => array( + 'name' => $soc->name, + ), + "metadata" => array('dol_id'=>$object->id, 'dol_version'=>DOL_VERSION, 'dol_entity'=>$conf->entity, 'ipaddress'=>$ipaddress) + ); + + //$a = \Stripe\Stripe::getApiKey(); + //var_dump($a);var_dump($stripeacc);exit; + try { + dol_syslog("Try to create sepa_debit 0"); + + $service = 'StripeTest'; + $servicestatus = 0; + if (!empty($conf->global->STRIPE_LIVE) && !GETPOST('forcesandbox', 'alpha')) { + $service = 'StripeLive'; + $servicestatus = 1; + } + // Force to use the correct API key + global $stripearrayofkeysbyenv; + $stripeacc = $stripearrayofkeysbyenv[$servicestatus]['secret_key']; + + dol_syslog("Try to create sepa_debit with data = ".json_encode($dataforcard)); + $s = new \Stripe\StripeClient($stripeacc); + $sepa = $s->sources->create($dataforcard); + if (!$sepa) { + $this->error = 'Creation of sepa_debit on Stripe has failed'; + } else { + //association du client avec cette source de paimeent + $cs = $cu->createSource( + $cu->id, + [ + 'source' => $sepa->id, + ] + ); + if (!$cs) { + $this->error = 'Link SEPA <-> Customer failed'; + } else { + dol_syslog("Try to create sepa_debit 3"); + // print json_encode($sepa); + + $sql = "UPDATE ".MAIN_DB_PREFIX."societe_rib"; + $sql .= " SET stripe_card_ref = '".$this->db->escape($sepa->id)."', card_type = 'sepa_debit',"; + $sql .= " stripe_account= '" . $cu->id . '@' . $stripeacc . "'"; + $sql .= " WHERE rowid = ".$object->id; + $sql .= " AND type = 'ban'"; + $resql = $this->db->query($sql); + if (!$resql) { + $this->error = $this->db->lasterror(); + } + } + } + } catch (Exception $e) { + $this->error = $e->getMessage(); + dol_syslog($this->error, LOG_WARNING); + } + } + } + } else { + dol_print_error($this->db); + } + + return $sepa; + } /** * Get the Stripe payment intent. Create it with confirmnow=false From c8ddcf86b61d5618d0cfd6d09fdcb3dd0bb23097 Mon Sep 17 00:00:00 2001 From: lmarcouiller Date: Thu, 1 Sep 2022 16:06:03 +0200 Subject: [PATCH 2/2] fix Ci error --- htdocs/stripe/class/stripe.class.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/htdocs/stripe/class/stripe.class.php b/htdocs/stripe/class/stripe.class.php index 6814dc3757f..6410050c642 100644 --- a/htdocs/stripe/class/stripe.class.php +++ b/htdocs/stripe/class/stripe.class.php @@ -588,6 +588,7 @@ class Stripe extends CommonObject return null; } } + /** * Get the Stripe SEPA of a company payment mode * @@ -605,7 +606,7 @@ class Stripe extends CommonObject $sql = "SELECT sa.stripe_card_ref, sa.proprio, sa.iban_prefix"; // stripe_card_ref is src_ for sepa $sql .= " FROM ".MAIN_DB_PREFIX."societe_rib as sa"; - $sql .= " WHERE sa.rowid = ".$object->id; // We get record from ID, no need for filter on entity + $sql .= " WHERE sa.rowid = '".$this->db->escape($object->id)."'"; // We get record from ID, no need for filter on entity $sql .= " AND sa.type = 'ban'"; //type ban to get normal bank account of customer (prelevement) $soc = new Societe($this->db); @@ -691,8 +692,8 @@ class Stripe extends CommonObject $sql = "UPDATE ".MAIN_DB_PREFIX."societe_rib"; $sql .= " SET stripe_card_ref = '".$this->db->escape($sepa->id)."', card_type = 'sepa_debit',"; - $sql .= " stripe_account= '" . $cu->id . '@' . $stripeacc . "'"; - $sql .= " WHERE rowid = ".$object->id; + $sql .= " stripe_account= '" . $this->db->escape($cu->id . "@" . $stripeacc) . "'"; + $sql .= " WHERE rowid = '".$this->db->escape($object->id)."'"; $sql .= " AND type = 'ban'"; $resql = $this->db->query($sql); if (!$resql) {