diff --git a/htdocs/langs/en_US/paypal.lang b/htdocs/langs/en_US/paypal.lang
index 51e98ccc8a2..1f8a9c2bd35 100644
--- a/htdocs/langs/en_US/paypal.lang
+++ b/htdocs/langs/en_US/paypal.lang
@@ -1,7 +1,7 @@
# Dolibarr language file - Source file is en_US - paypal
PaypalSetup=PayPal module setup
PaypalDesc=This module allows payment by customers via PayPal . This can be used for a ad-hoc payment or for a payment related to a Dolibarr object (invoice, order, ...)
-PaypalOrCBDoPayment=Pay with PayPal (Credit Card or PayPal)
+PaypalOrCBDoPayment=Pay with PayPal (Card or PayPal)
PaypalDoPayment=Pay with PayPal
PAYPAL_API_SANDBOX=Mode test/sandbox
PAYPAL_API_USER=API username
@@ -33,3 +33,4 @@ PaypalImportPayment=Import PayPal payments
PostActionAfterPayment=Post actions after payments
ARollbackWasPerformedOnPostActions=A rollback was performed on all Post actions. You must complete post actions manually if they are necessary.
ValidationOfPaymentFailed=Validation of payment has failed
+CardOwner=Card owner
diff --git a/htdocs/public/payment/newpayment.php b/htdocs/public/payment/newpayment.php
index f06228291ef..8489f0ef071 100644
--- a/htdocs/public/payment/newpayment.php
+++ b/htdocs/public/payment/newpayment.php
@@ -803,6 +803,28 @@ if (! $source)
print ' ';
print ''."\n";
+ if (! empty($conf->stripe->enabled) && $paymentmethod == 'stripe' && ! empty($conf->global->STRIPE_USE_INTENT_WITH_AUTOMATIC_CONFIRMATION))
+ {
+ require_once DOL_DOCUMENT_ROOT.'/stripe/class/stripe.class.php';
+
+ $service = 'StripeLive';
+ $servicestatus = 1;
+
+ if (empty($conf->global->STRIPE_LIVE) || GETPOST('forcesandbox', 'alpha'))
+ {
+ $service = 'StripeTest';
+ $servicestatus = 0;
+ }
+ $stripe = new Stripe($db);
+ $stripeacc = $stripe->getStripeAccount($service);
+ $stripecu = null;
+ // for dev only
+ print '
'.$langs->trans("PaymentIntent");
+ print ' ';
+ $paymentintent=$stripe->getPaymentIntent($amount, $currency, $tag, $object, $stripecu, $stripeacc, $servicestatus);
+ print ''.$paymentintent->id.' ';
+ print ' '."\n";
+ }
// We do not add fields shipToName, shipToStreet, shipToCity, shipToState, shipToCountryCode, shipToZip, shipToStreet2, phoneNum
// as they don't exists (buyer is unknown, tag is free).
}
@@ -896,6 +918,29 @@ if ($source == 'order')
print ' ';
print ''."\n";
+ if (! empty($conf->stripe->enabled) && $paymentmethod == 'stripe' && empty($order->billed) && ! empty($conf->global->STRIPE_USE_INTENT_WITH_AUTOMATIC_CONFIRMATION))
+ {
+ require_once DOL_DOCUMENT_ROOT.'/stripe/class/stripe.class.php';
+
+ $service = 'StripeLive';
+ $servicestatus = 1;
+
+ if (empty($conf->global->STRIPE_LIVE) || GETPOST('forcesandbox', 'alpha'))
+ {
+ $service = 'StripeTest';
+ $servicestatus = 0;
+ }
+ $stripe = new Stripe($db);
+ $stripeacc = $stripe->getStripeAccount($service);
+ $stripecu = $stripe->customerStripe($order->thirdparty, $stripeacc, $servicestatus, 1);
+ // for dev only
+ print ''.$langs->trans("PaymentIntent");
+ print ' ';
+ $paymentintent=$stripe->getPaymentIntent($amount, $currency, $tag, $object, $stripecu, $stripeacc, $servicestatus);
+ print ''.$paymentintent->id.' ';
+ print ' '."\n";
+ }
+
// Shipping address
$shipToName=$order->thirdparty->name;
$shipToStreet=$order->thirdparty->address;
@@ -1007,14 +1052,14 @@ if ($source == 'invoice')
print ' ';
print ' ';
}
- // Currency
- print ' '.$langs->trans("Currency".$currency).' ';
- print ' ';
}
else
{
- print price($object->total_ttc, 1, $langs);
+ print ''.price($object->total_ttc, 1, $langs).' ';
}
+ // Currency
+ print ' '.$langs->trans("Currency".$currency).' ';
+ print ' ';
print ''."\n";
// Tag
@@ -1024,6 +1069,28 @@ if ($source == 'invoice')
print ' ';
print ''."\n";
+ if (! empty($conf->stripe->enabled) && ($paymentmethod == 'stripe') && empty($object->paye) && ! empty($conf->global->STRIPE_USE_INTENT_WITH_AUTOMATIC_CONFIRMATION))
+ {
+ require_once DOL_DOCUMENT_ROOT.'/stripe/class/stripe.class.php';
+
+ $service = 'StripeLive';
+ $servicestatus = 1;
+ if (empty($conf->global->STRIPE_LIVE) || GETPOST('forcesandbox', 'alpha'))
+ {
+ $service = 'StripeTest';
+ $servicestatus = 0;
+ }
+ $stripe = new Stripe($db);
+ $stripeacc = $stripe->getStripeAccount($service);
+ $stripecu = $stripe->customerStripe($invoice->thirdparty, $stripeacc, $servicestatus, 1);
+ // for dev only
+ print ''.$langs->trans("PaymentIntent");
+ print ' ';
+ $paymentintent=$stripe->getPaymentIntent($amount, $currency, $tag, $object, $stripecu, $stripeacc, $servicestatus);
+ print ''.$paymentintent->id.' ';
+ print ' '."\n";
+ }
+
// Shipping address
$shipToName=$invoice->thirdparty->name;
$shipToStreet=$invoice->thirdparty->address;
@@ -1149,6 +1216,7 @@ if ($source == 'contractline')
// Debitor
print ''.$langs->trans("ThirdParty");
print ' '.$contract->thirdparty->name.' ';
+ print ' '."\n";
// Object
$text=''.$langs->trans("PaymentRenewContractId", $contract->ref, $contractline->ref).' ';
@@ -1234,6 +1302,29 @@ if ($source == 'contractline')
print ' ';
print ''."\n";
+ if (! empty($conf->stripe->enabled) && $paymentmethod == 'stripe' && ! empty($conf->global->STRIPE_USE_INTENT_WITH_AUTOMATIC_CONFIRMATION))
+ {
+ require_once DOL_DOCUMENT_ROOT.'/stripe/class/stripe.class.php';
+
+ $service = 'StripeLive';
+ $servicestatus = 1;
+
+ if (empty($conf->global->STRIPE_LIVE) || GETPOST('forcesandbox', 'alpha'))
+ {
+ $service = 'StripeTest';
+ $servicestatus = 0;
+ }
+ $stripe = new Stripe($db);
+ $stripeacc = $stripe->getStripeAccount($service);
+ $stripecu = null;
+ // for dev only
+ print ''.$langs->trans("PaymentIntent");
+ print ' ';
+ $paymentintent=$stripe->getPaymentIntent($amount, $currency, $tag, $object, $stripecu, $stripeacc, $servicestatus);
+ print ''.$paymentintent->id.' ';
+ print ' '."\n";
+ }
+
// Shipping address
$shipToName=$contract->thirdparty->name;
$shipToStreet=$contract->thirdparty->address;
@@ -1400,6 +1491,29 @@ if ($source == 'membersubscription')
print ' ';
print ''."\n";
+ if (! empty($conf->stripe->enabled) && $paymentmethod == 'stripe' && ! empty($conf->global->STRIPE_USE_INTENT_WITH_AUTOMATIC_CONFIRMATION))
+ {
+ require_once DOL_DOCUMENT_ROOT.'/stripe/class/stripe.class.php';
+
+ $service = 'StripeLive';
+ $servicestatus = 1;
+
+ if (empty($conf->global->STRIPE_LIVE) || GETPOST('forcesandbox', 'alpha'))
+ {
+ $service = 'StripeTest';
+ $servicestatus = 0;
+ }
+ $stripe = new Stripe($db);
+ $stripeacc = $stripe->getStripeAccount($service);
+ $stripecu = null;
+ // for dev only
+ print ''.$langs->trans("PaymentIntent");
+ print ' ';
+ $paymentintent=$stripe->getPaymentIntent($amount, $currency, $tag, $object, $stripecu, $stripeacc, $servicestatus);
+ print ''.$paymentintent->id.' ';
+ print ' '."\n";
+ }
+
// Shipping address
$shipToName=$member->getFullName($langs);
$shipToStreet=$member->address;
@@ -1541,6 +1655,29 @@ if ($source == 'donation')
print ' ';
print ''."\n";
+ if (! empty($conf->stripe->enabled) && ($paymentmethod == 'stripe') && empty($object->paid) && ! empty($conf->global->STRIPE_USE_INTENT_WITH_AUTOMATIC_CONFIRMATION))
+ {
+ require_once DOL_DOCUMENT_ROOT.'/stripe/class/stripe.class.php';
+
+ $service = 'StripeLive';
+ $servicestatus = 1;
+
+ if (empty($conf->global->STRIPE_LIVE) || GETPOST('forcesandbox', 'alpha'))
+ {
+ $service = 'StripeTest';
+ $servicestatus = 0;
+ }
+ $stripe = new Stripe($db);
+ $stripeacc = $stripe->getStripeAccount($service);
+ $stripecu = $stripe->customerStripe($don->thirdparty, $stripeacc, $servicestatus, 1);
+ // for dev only
+ print ''.$langs->trans("PaymentIntent");
+ print ' ';
+ $paymentintent=$stripe->getPaymentIntent($amount, $currency, $tag, $object, $stripecu, $stripeacc, $servicestatus);
+ print ''.$paymentintent->id.' ';
+ print ' '."\n";
+ }
+
// Shipping address
$shipToName=$don->getFullName($langs);
$shipToStreet=$don->address;
@@ -1724,25 +1861,38 @@ if (preg_match('/^dopayment/', $action))
print ' ';
print '
-
'."\n";
@@ -1750,8 +1900,94 @@ if (preg_match('/^dopayment/', $action))
// Code to ask the credit card. This use the default "API version". No way to force API version when using JS code.
print '';
}
}
diff --git a/htdocs/stripe/class/stripe.class.php b/htdocs/stripe/class/stripe.class.php
index d604dcdd3f2..1f2f39719a8 100644
--- a/htdocs/stripe/class/stripe.class.php
+++ b/htdocs/stripe/class/stripe.class.php
@@ -140,7 +140,7 @@ class Stripe extends CommonObject
if (empty($object->id))
{
- dol_syslog("customerStripe is called with param object not loaded");
+ dol_syslog("customerStripe is called with the parameter object that is not loaded");
return null;
}
@@ -240,6 +240,9 @@ class Stripe extends CommonObject
/**
* Get the Stripe payment intent. Create it with confirm=false
*
+ * @param double $amount Amount
+ * @param string $currency_code Currency code
+ * @param string $tag Tag
* @param Societe $object Object to pay with 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
@@ -249,127 +252,133 @@ class Stripe extends CommonObject
* @param boolean $confirmnow false=default, true=try to confirm immediatly after create (if conditions are ok)
* @return \Stripe\PaymentIntent|null Stripe PaymentIntent or null if not found
*/
- public function getPaymentIntent($object, $customer, $key = null, $status = 0, $usethirdpartyemailforreceiptemail = 0, $mode = 'automatic', $confirmnow = false)
+ public function getPaymentIntent($amount, $currency_code, $tag, $object = null, $customer = null, $key = null, $status = 0, $usethirdpartyemailforreceiptemail = 0, $mode = 'automatic', $confirmnow = false)
{
global $conf, $user, $mysoc;
- if (empty($object->id))
- {
- dol_syslog("object not loaded");
- return null;
- }
-
- $error = 0;
-
if (empty($status)) $service = 'StripeTest';
else $service = 'StripeLive';
+ $arrayzerounitcurrency=array('BIF', 'CLP', 'DJF', 'GNF', 'JPY', 'KMF', 'KRW', 'MGA', 'PYG', 'RWF', 'VND', 'VUV', 'XAF', 'XOF', 'XPF');
+ if (! in_array($currency_code, $arrayzerounitcurrency)) $stripeamount = $amount * 100;
+ else $stripeamount = $amount;
+
+ $fee = round(($$stripeamount * ($conf->global->STRIPE_APPLICATION_FEE_PERCENT / 100) + $conf->global->STRIPE_APPLICATION_FEE) * 100);
+ if ($fee >= ($conf->global->STRIPE_APPLICATION_FEE_MAXIMAL * 100) && $conf->global->STRIPE_APPLICATION_FEE_MAXIMAL>$conf->global->STRIPE_APPLICATION_FEE_MINIMAL) {
+ $fee = round($conf->global->STRIPE_APPLICATION_FEE_MAXIMAL * 100);
+ } elseif ($fee < ($conf->global->STRIPE_APPLICATION_FEE_MINIMAL * 100)) {
+ $fee = round($conf->global->STRIPE_APPLICATION_FEE_MINIMAL * 100);
+ }
+
$paymentintent = null;
- $sql = "SELECT pi.ext_payment_id, pi.entity, pi.fk_facture, pi.sourcetype, pi.ext_payment_site";
- $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) . "::getPaymentIntent 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) . "::getPaymentIntent found existing payment intent record");
-
- // 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(($object->total_ttc * ($conf->global->STRIPE_APPLICATION_FEE_PERCENT / 100) + $conf->global->STRIPE_APPLICATION_FEE) * 100);
- if ($fee >= ($conf->global->STRIPE_APPLICATION_FEE_MAXIMAL * 100) && $conf->global->STRIPE_APPLICATION_FEE_MAXIMAL>$conf->global->STRIPE_APPLICATION_FEE_MINIMAL) {
- $fee = round($conf->global->STRIPE_APPLICATION_FEE_MAXIMAL * 100);
- } elseif ($fee < ($conf->global->STRIPE_APPLICATION_FEE_MINIMAL * 100)) {
- $fee = round($conf->global->STRIPE_APPLICATION_FEE_MINIMAL * 100);
- }
-
- $ipaddress=getUserRemoteIP();
- // Not enough space for a ref so we store id. Also with multicompany we can have same ref for 2 different
- // object and we need a unique (this is used later as idempotency_key)
- $description=$object->element.$object->id;
-
- $dataforintent = array(
- "confirm" => $confirmnow, // Do not confirm immediatly during creation of intent
- "confirmation_method" => $mode,
- "amount" => $stripeamount,
- "currency" => $object->multicurrency_code,
- "customer" => $customer,
- "allowed_source_types" => ["card"],
- "statement_descriptor" => dol_trunc($description, 10, 'right', 'UTF-8', 1), // 22 chars that appears on bank receipt (company + description)
- "metadata" => array('dol_type'=>$object->element, 'dol_id'=>$object->id, 'dol_version'=>DOL_VERSION, 'dol_entity'=>$conf->entity, 'ipaddress'=>$ipaddress)
- );
- // save_payment_method = true,
- // payment_method_types =
- // payment_method =
-
- if ($conf->entity!=$conf->global->STRIPECONNECT_PRINCIPAL && $fee>0)
- {
- $dataforintent["application_fee"] = $fee;
- }
- if ($usethirdpartyemailforreceiptemail && $object->thirdparty->email)
- {
- $dataforintent["receipt_email"] = $object->thirdparty->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.", '".$this->db->escape($object->element)."', " . $conf->entity . ", '" . $service . "')";
- $resql = $this->db->query($sql);
- if (! $resql)
- {
- $this->error = $this->db->lasterror();
- dol_syslog(get_class($this) . "::PaymentIntent failed to insert paymentintent with id=".$paymentintent->id." into database.");
- }
- }
- catch(Exception $e)
- {
- $this->error = $e->getMessage();
- }
- }
- }
- else
+ if (is_object($object))
{
- dol_print_error($this->db);
+ $sql = "SELECT pi.ext_payment_id, pi.entity, pi.fk_facture, pi.sourcetype, pi.ext_payment_site";
+ $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) . "::getPaymentIntent search stripe payment intent for object 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) . "::getPaymentIntent found existing payment intent record");
+
+ // 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();
+ }
+ }
+ }
+ }
+
+ if (empty($paymentintent))
+ {
+ $ipaddress=getUserRemoteIP();
+ // Not enough space for a ref so we store id. Also with multicompany we can have same ref for 2 different
+ // object and we need a unique (this is used later as idempotency_key)
+ $description=$tag;
+ $metadata = array('dol_version'=>DOL_VERSION, 'dol_entity'=>$conf->entity, 'ipaddress'=>$ipaddress);
+ if (is_object($object))
+ {
+ $metadata['dol_type'] = $object->element;
+ $metadata['dol_id'] = $object->id;
+ }
+
+ $dataforintent = array(
+ "confirm" => $confirmnow, // Do not confirm immediatly during creation of intent
+ "confirmation_method" => $mode,
+ "amount" => $stripeamount,
+ "currency" => $currency_code,
+ "payment_method_types" => ["card"],
+ "statement_descriptor" => dol_trunc($description, 10, 'right', 'UTF-8', 1), // 22 chars that appears on bank receipt (company + description)
+ "metadata" => $metadata
+ );
+ if (! is_null($customer)) $dataforintent["customer"]=$customer;
+ // save_payment_method = true,
+ // payment_method =
+
+ if ($conf->entity!=$conf->global->STRIPECONNECT_PRINCIPAL && $fee>0)
+ {
+ $dataforintent["application_fee"] = $fee;
+ }
+ if ($usethirdpartyemailforreceiptemail && is_object($object) && $object->thirdparty->email)
+ {
+ $dataforintent["receipt_email"] = $object->thirdparty->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));
+ }
+
+ // Store the payment intent
+ if (is_object($object))
+ {
+ $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.", '".$this->db->escape($object->element)."', " . $conf->entity . ", '" . $service . "')";
+ $resql = $this->db->query($sql);
+ if (! $resql)
+ {
+ $this->error = $this->db->lasterror();
+ dol_syslog(get_class($this) . "::PaymentIntent failed to insert paymentintent with id=".$paymentintent->id." into database.");
+ }
+ }
+ else
+ {
+ $_SESSION["stripe_payment_intent"] = $paymentintent;
+ }
+ }
+ catch(Exception $e)
+ {
+ $this->error = $e->getMessage();
+ }
}
return $paymentintent;