From cc1aabfd19fd3882fa18faac5ce284fa49af1416 Mon Sep 17 00:00:00 2001 From: ptibogxiv Date: Tue, 12 Feb 2019 18:47:35 +0100 Subject: [PATCH 1/6] NEW Stripe Payment Intent Starting in September 2019, a new regulation called Strong Customer Authentication (SCA) will require businesses in Europe to request additional authentication for online payments. We recommend that all European businesses start building their Stripe integrations with either our PaymentIntents API or our new Checkout to be ready for these rule changes. https://stripe.com/docs/payments/payment-intents need replace actual integration --- htdocs/stripe/class/stripe.class.php | 129 ++++++++++++++++++++++++++- 1 file changed, 128 insertions(+), 1 deletion(-) diff --git a/htdocs/stripe/class/stripe.class.php b/htdocs/stripe/class/stripe.class.php index 1a0807014a8..94c3d658f21 100644 --- a/htdocs/stripe/class/stripe.class.php +++ b/htdocs/stripe/class/stripe.class.php @@ -1,5 +1,5 @@ +/* Copyright (C) 2018-2019 Thibault FOUCART * * 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 @@ -237,7 +237,134 @@ class Stripe extends CommonObject return $customer; } + + /** + * Get the Stripe payment intent + * + * @param Societe $object Object tp pay on Stripe + * @param string $customer Stripe customer ref 'cus_xxxxxxxxxxxxx' via customerStripe() + * @param string $key ''=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 $usethirdpartyemailforreceiptemail 1=use thirdparty email fpr receipt + * @param int $mode automatic=automatic payment, manual=need confirmation + * @return \Stripe\PaymentIntent|null Stripe PaymentIntent or null if not found + */ + public function getPaymentIntent($object, $customer, $key=null, $status=0, $usethirdpartyemailforreceiptemail=0, $mode='automatic') + { + global $conf, $user; + if (empty($object->id)) + { + dol_syslog("object not loaded"); + return null; + } + + $error = 0; + + if (empty($status)) $service = 'StripeTest'; + else $service = 'StripeLive'; + + $paymentintent = null; + + $sql = "SELECT pi.ext_payment_id, pi.entity, pi.fk_facture, pi.sourcetype, pi.ext_payment_site"; // key_account is cus_.... + $sql.= " FROM " . MAIN_DB_PREFIX . "prelevement_facture_demande as pi"; + $sql.= " WHERE pi.fk_facture = " . $object->id; + $sql.= " AND pi.sourcetype = '" . $object->element . "'"; + $sql.= " AND pi.entity IN (".getEntity('societe').")"; + $sql.= " AND pi.ext_payment_site = '" . $service . "'"; + + dol_syslog(get_class($this) . "::customerStripe search stripe customer id for thirdparty id=".$object->id, LOG_DEBUG); + $resql = $this->db->query($sql); + if ($resql) { + $num = $this->db->num_rows($resql); + if ($num) + { + $obj = $this->db->fetch_object($resql); + $intent = $obj->ext_payment_id; + + dol_syslog(get_class($this) . "::customerStripe found stripe customer key_account = ".$tiers); + + // Force to use the correct API key + global $stripearrayofkeysbyenv; + \Stripe\Stripe::setApiKey($stripearrayofkeysbyenv[$status]['secret_key']); + + try { + if (empty($key)) { // If the Stripe connect account not set, we use common API usage + $paymentintent = \Stripe\PaymentIntent::retrieve($intent); + } else { + $paymentintent = \Stripe\PaymentIntent::retrieve($intent, array("stripe_account" => $key)); + } + } + catch(Exception $e) + { + $this->error = $e->getMessage(); + } + } + else //if ($createifnotlinkedtostripe) + { + $arrayzerounitcurrency=array('BIF', 'CLP', 'DJF', 'GNF', 'JPY', 'KMF', 'KRW', 'MGA', 'PYG', 'RWF', 'VND', 'VUV', 'XAF', 'XOF', 'XPF'); + if (! in_array($object->multicurrency_code, $arrayzerounitcurrency)) $stripeamount=$object->multicurrency_total_ttc * 100; + else $stripeamount = $object->multicurrency_total_ttc; + + $fee = round(($amount * ($conf->global->STRIPE_APPLICATION_FEE_PERCENT / 100) + $conf->global->STRIPE_APPLICATION_FEE) * 100); + if ($fee < ($conf->global->STRIPE_APPLICATION_FEE_MINIMAL * 100)) { + $fee = round($conf->global->STRIPE_APPLICATION_FEE_MINIMAL * 100); + } + + $description=$object->element.$object->ref; + + $dataforintent = array( + "amount" => $stripeamount, + "currency" => $object->multicurrency_code, + "customer" => $customer, + "allowed_source_types" => ["card"], + "statement_descriptor" => dol_trunc(dol_trunc(dol_string_unaccent($mysoc->name), 8, 'right', 'UTF-8', 1).' '.$description, 22, 'right', 'UTF-8', 1), // 22 chars that appears on bank receipt + "metadata" => array('dol_type'=>$object->element, 'dol_id'=>$object->id, 'dol_version'=>DOL_VERSION, 'dol_entity'=>$conf->entity, 'ipaddress'=>(empty($_SERVER['REMOTE_ADDR'])?'':$_SERVER['REMOTE_ADDR'])) + ); + + if ($conf->entity!=$conf->global->STRIPECONNECT_PRINCIPAL && $fee>0) + { + $dataforintent["application_fee"] = $fee; + } + if ($societe->email && $usethirdpartyemailforreceiptemail) + { + $dataforintent["receipt_email"] = $societe->email; + } + + try { + // Force to use the correct API key + global $stripearrayofkeysbyenv; + \Stripe\Stripe::setApiKey($stripearrayofkeysbyenv[$status]['secret_key']); + + if (empty($key)) { // If the Stripe connect account not set, we use common API usage + $paymentintent = \Stripe\PaymentIntent::create($dataforintent, array("idempotency_key" => "$description")); + } else { + $paymentintent = \Stripe\PaymentIntent::create($dataforintent, array("idempotency_key" => "$description","stripe_account" => $key)); + } + $now=dol_now(); + $sql = "INSERT INTO " . MAIN_DB_PREFIX . "prelevement_facture_demande (fk_soc, date_demande, fk_user_demande, ext_payment_id, fk_facture, sourcetype, entity, ext_payment_site)"; + $sql .= " VALUES ('".$object->socid."','".$this->db->idate($now)."', '0', '".$this->db->escape($paymentintent->id)."', ".$object->id.", '".$object->element."', " . $conf->entity . ", '" . $service . "')"; + $resql = $this->db->query($sql); + if (! $resql) + { + $this->error = $this->db->lasterror(); + dol_syslog(get_class($this) . "::PaymentIntent not insert with id=".$paymentintent->id); + } + } + catch(Exception $e) + { + $this->error = $e->getMessage(); + } + } + } + else + { + dol_print_error($this->db); + } + + return $paymentintent; + } + /** * Get the Stripe card of a company payment mode (with option to create it on Stripe if not linked yet) * From 85272b83454918fcfcc48ba00275639ad5b8067c Mon Sep 17 00:00:00 2001 From: ptibogxiv Date: Tue, 12 Feb 2019 18:58:57 +0100 Subject: [PATCH 2/6] NEW support stripe payment prelevement --- htdocs/install/mysql/migration/9.0.0-10.0.0.sql | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/htdocs/install/mysql/migration/9.0.0-10.0.0.sql b/htdocs/install/mysql/migration/9.0.0-10.0.0.sql index 1bac8ec18e6..d52e1a7dc0f 100644 --- a/htdocs/install/mysql/migration/9.0.0-10.0.0.sql +++ b/htdocs/install/mysql/migration/9.0.0-10.0.0.sql @@ -88,10 +88,14 @@ ALTER TABLE llx_subscription ADD fk_type integer(11); ALTER TABLE llx_bank_url DROP INDEX uk_bank_url; ALTER TABLE llx_bank_url ADD UNIQUE INDEX uk_bank_url (fk_bank, url_id, type); - ALTER TABLE llx_actioncomm ADD COLUMN calling_duration integer; - ALTER TABLE llx_don ADD COLUMN fk_soc integer NULL; -ALTER TABLE llx_payment_various ADD COLUMN subledger_account varchar(32); \ No newline at end of file +ALTER TABLE llx_payment_various ADD COLUMN subledger_account varchar(32); + +ALTER TABLE llx_prelevement_facture_demande ADD COLUMN entity integer(11); +ALTER TABLE llx_prelevement_facture_demande ADD COLUMN sourcetype varchar(32); +ALTER TABLE llx_prelevement_facture_demande ADD COLUMN fk_soc integer(11); +ALTER TABLE llx_prelevement_facture_demande ADD COLUMN ext_payment_id varchar(128) NULL; +ALTER TABLE llx_prelevement_facture_demande ADD COLUMN ext_payment_site varchar(128) NULL; From 8f3ffc6520eb3bb8efff1e7dcced21426fb0ce1f Mon Sep 17 00:00:00 2001 From: ptibogxiv Date: Tue, 12 Feb 2019 19:03:45 +0100 Subject: [PATCH 3/6] NEW stripe payment intent use it for stripe --- .../mysql/tables/llx_prelevement_facture_demande.sql | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/htdocs/install/mysql/tables/llx_prelevement_facture_demande.sql b/htdocs/install/mysql/tables/llx_prelevement_facture_demande.sql index 9da18cbd416..4be4b3c8ddb 100644 --- a/htdocs/install/mysql/tables/llx_prelevement_facture_demande.sql +++ b/htdocs/install/mysql/tables/llx_prelevement_facture_demande.sql @@ -20,7 +20,10 @@ create table llx_prelevement_facture_demande ( rowid integer AUTO_INCREMENT PRIMARY KEY, + entity integer DEFAULT 1 NOT NULL, fk_facture integer NOT NULL, + sourcetype varchar(32), + fk_soc integer NULL, amount double(24,8) NOT NULL, date_demande datetime NOT NULL, traite smallint DEFAULT 0, @@ -31,6 +34,8 @@ create table llx_prelevement_facture_demande code_banque varchar(128), code_guichet varchar(6), number varchar(255), - cle_rib varchar(5) + cle_rib varchar(5), + ext_payment_id varchar(128), + ext_payment_site varchar(128), )ENGINE=innodb; From 7d5ea4fc35b02d5bdfdde251f16099c0ee5e924a Mon Sep 17 00:00:00 2001 From: ptibogxiv Date: Tue, 12 Feb 2019 19:42:34 +0100 Subject: [PATCH 4/6] Update stripe.class.php --- htdocs/stripe/class/stripe.class.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/htdocs/stripe/class/stripe.class.php b/htdocs/stripe/class/stripe.class.php index 94c3d658f21..38432fbd5db 100644 --- a/htdocs/stripe/class/stripe.class.php +++ b/htdocs/stripe/class/stripe.class.php @@ -239,17 +239,17 @@ class Stripe extends CommonObject } /** - * Get the Stripe payment intent + * Get the Stripe payment intent * * @param Societe $object Object tp pay on Stripe * @param string $customer Stripe customer ref 'cus_xxxxxxxxxxxxx' via customerStripe() * @param string $key ''=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 $usethirdpartyemailforreceiptemail 1=use thirdparty email fpr receipt - * @param int $mode automatic=automatic payment, manual=need confirmation + * @param int $mode automatic=automatic payment, manual=need confirmation * @return \Stripe\PaymentIntent|null Stripe PaymentIntent or null if not found */ - public function getPaymentIntent($object, $customer, $key=null, $status=0, $usethirdpartyemailforreceiptemail=0, $mode='automatic') + public function getPaymentIntent($object, $customer, $key = null, $status = 0, $usethirdpartyemailforreceiptemail = 0, $mode = 'automatic') { global $conf, $user; @@ -269,7 +269,7 @@ class Stripe extends CommonObject $sql = "SELECT pi.ext_payment_id, pi.entity, pi.fk_facture, pi.sourcetype, pi.ext_payment_site"; // key_account is cus_.... $sql.= " FROM " . MAIN_DB_PREFIX . "prelevement_facture_demande as pi"; $sql.= " WHERE pi.fk_facture = " . $object->id; - $sql.= " AND pi.sourcetype = '" . $object->element . "'"; + $sql.= " AND pi.sourcetype = '" . $object->element . "'"; $sql.= " AND pi.entity IN (".getEntity('societe').")"; $sql.= " AND pi.ext_payment_site = '" . $service . "'"; @@ -311,7 +311,7 @@ class Stripe extends CommonObject $fee = round($conf->global->STRIPE_APPLICATION_FEE_MINIMAL * 100); } - $description=$object->element.$object->ref; + $description=$object->element.$object->ref; $dataforintent = array( "amount" => $stripeamount, @@ -329,7 +329,7 @@ class Stripe extends CommonObject if ($societe->email && $usethirdpartyemailforreceiptemail) { $dataforintent["receipt_email"] = $societe->email; - } + } try { // Force to use the correct API key From 00cfee0c37d4d74d78f69ddc1405f979ccc696ac Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Thu, 14 Feb 2019 16:10:06 +0100 Subject: [PATCH 5/6] Update 9.0.0-10.0.0.sql --- htdocs/install/mysql/migration/9.0.0-10.0.0.sql | 1 - 1 file changed, 1 deletion(-) diff --git a/htdocs/install/mysql/migration/9.0.0-10.0.0.sql b/htdocs/install/mysql/migration/9.0.0-10.0.0.sql index b32ae7b0846..f412de36e76 100644 --- a/htdocs/install/mysql/migration/9.0.0-10.0.0.sql +++ b/htdocs/install/mysql/migration/9.0.0-10.0.0.sql @@ -97,7 +97,6 @@ ALTER TABLE llx_payment_various ADD COLUMN subledger_account varchar(32); ALTER TABLE llx_prelevement_facture_demande ADD COLUMN entity integer(11); ALTER TABLE llx_prelevement_facture_demande ADD COLUMN sourcetype varchar(32); -ALTER TABLE llx_prelevement_facture_demande ADD COLUMN fk_soc integer(11); ALTER TABLE llx_prelevement_facture_demande ADD COLUMN ext_payment_id varchar(128) NULL; ALTER TABLE llx_prelevement_facture_demande ADD COLUMN ext_payment_site varchar(128) NULL; From 567d92f886e4b591233718ed62f869ba2c6f17cb Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Thu, 14 Feb 2019 16:10:31 +0100 Subject: [PATCH 6/6] Update llx_prelevement_facture_demande.sql --- htdocs/install/mysql/tables/llx_prelevement_facture_demande.sql | 1 - 1 file changed, 1 deletion(-) diff --git a/htdocs/install/mysql/tables/llx_prelevement_facture_demande.sql b/htdocs/install/mysql/tables/llx_prelevement_facture_demande.sql index 4be4b3c8ddb..3887980d718 100644 --- a/htdocs/install/mysql/tables/llx_prelevement_facture_demande.sql +++ b/htdocs/install/mysql/tables/llx_prelevement_facture_demande.sql @@ -23,7 +23,6 @@ create table llx_prelevement_facture_demande entity integer DEFAULT 1 NOT NULL, fk_facture integer NOT NULL, sourcetype varchar(32), - fk_soc integer NULL, amount double(24,8) NOT NULL, date_demande datetime NOT NULL, traite smallint DEFAULT 0,