dolibarr  17.0.3
stripe.class.php
1 <?php
2 /* Copyright (C) 2018-2021 Thibault FOUCART <support@ptibogxiv.net>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 // Put here all includes required by your class file
19 require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php';
20 require_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php';
21 require_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php';
22 require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
23 require_once DOL_DOCUMENT_ROOT.'/stripe/config.php'; // This set stripe global env
24 
25 
29 class Stripe extends CommonObject
30 {
34  public $rowid;
35 
39  public $fk_soc;
40 
44  public $fk_key;
45 
49  public $id;
50 
51  public $mode;
52 
56  public $entity;
57 
58  public $statut;
59 
60  public $type;
61 
62  public $code;
63  public $declinecode;
64 
68  public $message;
69 
75  public function __construct($db)
76  {
77  $this->db = $db;
78  }
79 
80 
89  public function getStripeAccount($mode = 'StripeTest', $fk_soc = 0, $entity = -1)
90  {
91  global $conf;
92 
93  $key = '';
94  if ($entity < 0) {
95  $entity = $conf->entity;
96  }
97 
98  $sql = "SELECT tokenstring";
99  $sql .= " FROM ".MAIN_DB_PREFIX."oauth_token";
100  $sql .= " WHERE service = '".$this->db->escape($mode)."'";
101  $sql .= " AND entity = ".((int) $entity);
102  if ($fk_soc > 0) {
103  $sql .= " AND fk_soc = ".((int) $fk_soc);
104  } else {
105  $sql .= " AND fk_soc IS NULL";
106  }
107  $sql .= " AND fk_user IS NULL AND fk_adherent IS NULL";
108 
109  dol_syslog(get_class($this)."::getStripeAccount", LOG_DEBUG);
110 
111  $result = $this->db->query($sql);
112  if ($result) {
113  if ($this->db->num_rows($result)) {
114  $obj = $this->db->fetch_object($result);
115  $tokenstring = $obj->tokenstring;
116 
117  $tmparray = json_decode($tokenstring);
118  $key = empty($tmparray->stripe_user_id) ? '' : $tmparray->stripe_user_id;
119  } else {
120  $tokenstring = '';
121  }
122  } else {
123  dol_print_error($this->db);
124  }
125 
126  dol_syslog("No dedicated Stripe Connect account available for entity ".$conf->entity);
127  return $key;
128  }
129 
138  public function getStripeCustomerAccount($id, $status = 0, $site_account = '')
139  {
140  include_once DOL_DOCUMENT_ROOT.'/societe/class/societeaccount.class.php';
141  $societeaccount = new SocieteAccount($this->db);
142  return $societeaccount->getCustomerAccount($id, 'stripe', $status, $site_account); // Get thirdparty cus_...
143  }
144 
145 
156  public function customerStripe(Societe $object, $key = '', $status = 0, $createifnotlinkedtostripe = 0)
157  {
158  global $conf, $user;
159 
160  if (empty($object->id)) {
161  dol_syslog("customerStripe is called with the parameter object that is not loaded");
162  return null;
163  }
164 
165  $customer = null;
166 
167  // Force to use the correct API key
168  global $stripearrayofkeysbyenv;
169  \Stripe\Stripe::setApiKey($stripearrayofkeysbyenv[$status]['secret_key']);
170 
171  $sql = "SELECT sa.key_account as key_account, sa.entity"; // key_account is cus_....
172  $sql .= " FROM ".MAIN_DB_PREFIX."societe_account as sa";
173  $sql .= " WHERE sa.fk_soc = ".((int) $object->id);
174  $sql .= " AND sa.entity IN (".getEntity('societe').")";
175  $sql .= " AND sa.site = 'stripe' AND sa.status = ".((int) $status);
176  $sql .= " AND (sa.site_account IS NULL OR sa.site_account = '' OR sa.site_account = '".$this->db->escape($stripearrayofkeysbyenv[$status]['publishable_key'])."')";
177  $sql .= " AND sa.key_account IS NOT NULL AND sa.key_account <> ''";
178 
179  dol_syslog(get_class($this)."::customerStripe search stripe customer id for thirdparty id=".$object->id, LOG_DEBUG);
180  $resql = $this->db->query($sql);
181  if ($resql) {
182  $num = $this->db->num_rows($resql);
183  if ($num) {
184  $obj = $this->db->fetch_object($resql);
185  $tiers = $obj->key_account;
186 
187  dol_syslog(get_class($this)."::customerStripe found stripe customer key_account = ".$tiers.". We will try to read it on Stripe with publishable_key = ".$stripearrayofkeysbyenv[$status]['publishable_key']);
188 
189  try {
190  if (empty($key)) { // If the Stripe connect account not set, we use common API usage
191  //$customer = \Stripe\Customer::retrieve("$tiers");
192  $customer = \Stripe\Customer::retrieve(array('id'=>"$tiers", 'expand[]'=>'sources'));
193  } else {
194  //$customer = \Stripe\Customer::retrieve("$tiers", array("stripe_account" => $key));
195  $customer = \Stripe\Customer::retrieve(array('id'=>"$tiers", 'expand[]'=>'sources'), array("stripe_account" => $key));
196  }
197  } catch (Exception $e) {
198  // For exemple, we may have error: 'No such customer: cus_XXXXX; a similar object exists in live mode, but a test mode key was used to make this request.'
199  $this->error = $e->getMessage();
200  }
201  } elseif ($createifnotlinkedtostripe) {
202  $ipaddress = getUserRemoteIP();
203 
204  $dataforcustomer = array(
205  "email" => $object->email,
206  "description" => $object->name,
207  "metadata" => array('dol_id'=>$object->id, 'dol_version'=>DOL_VERSION, 'dol_entity'=>$conf->entity, 'ipaddress'=>$ipaddress)
208  );
209 
210  $vatcleaned = $object->tva_intra ? $object->tva_intra : null;
211 
212  /*
213  $taxinfo = array('type'=>'vat');
214  if ($vatcleaned)
215  {
216  $taxinfo["tax_id"] = $vatcleaned;
217  }
218  // We force data to "null" if not defined as expected by Stripe
219  if (empty($vatcleaned)) $taxinfo=null;
220  $dataforcustomer["tax_info"] = $taxinfo;
221  */
222 
223  //$a = \Stripe\Stripe::getApiKey();
224  //var_dump($a);var_dump($key);exit;
225  try {
226  // Force to use the correct API key
227  global $stripearrayofkeysbyenv;
228  \Stripe\Stripe::setApiKey($stripearrayofkeysbyenv[$status]['secret_key']);
229 
230  if (empty($key)) { // If the Stripe connect account not set, we use common API usage
231  $customer = \Stripe\Customer::create($dataforcustomer);
232  } else {
233  $customer = \Stripe\Customer::create($dataforcustomer, array("stripe_account" => $key));
234  }
235 
236  // Create the VAT record in Stripe
237  if (!empty($conf->global->STRIPE_SAVE_TAX_IDS)) { // We setup to save Tax info on Stripe side. Warning: This may result in error when saving customer
238  if (!empty($vatcleaned)) {
239  $isineec = isInEEC($object);
240  if ($object->country_code && $isineec) {
241  //$taxids = $customer->allTaxIds($customer->id);
242  $customer->createTaxId($customer->id, array('type'=>'eu_vat', 'value'=>$vatcleaned));
243  }
244  }
245  }
246 
247  // Create customer in Dolibarr
248  $sql = "INSERT INTO ".MAIN_DB_PREFIX."societe_account (fk_soc, login, key_account, site, site_account, status, entity, date_creation, fk_user_creat)";
249  $sql .= " VALUES (".((int) $object->id).", '', '".$this->db->escape($customer->id)."', 'stripe', '".$this->db->escape($stripearrayofkeysbyenv[$status]['publishable_key'])."', ".((int) $status).", ".((int) $conf->entity).", '".$this->db->idate(dol_now())."', ".((int) $user->id).")";
250  $resql = $this->db->query($sql);
251  if (!$resql) {
252  $this->error = $this->db->lasterror();
253  }
254  } catch (Exception $e) {
255  $this->error = $e->getMessage();
256  }
257  }
258  } else {
259  dol_print_error($this->db);
260  }
261 
262  return $customer;
263  }
264 
273  public function getPaymentMethodStripe($paymentmethod, $key = '', $status = 0)
274  {
275  $stripepaymentmethod = null;
276 
277  try {
278  // Force to use the correct API key
279  global $stripearrayofkeysbyenv;
280  \Stripe\Stripe::setApiKey($stripearrayofkeysbyenv[$status]['secret_key']);
281  if (empty($key)) { // If the Stripe connect account not set, we use common API usage
282  $stripepaymentmethod = \Stripe\PaymentMethod::retrieve(''.$paymentmethod->id.'');
283  } else {
284  $stripepaymentmethod = \Stripe\PaymentMethod::retrieve(''.$paymentmethod->id.'', array("stripe_account" => $key));
285  }
286  } catch (Exception $e) {
287  $this->error = $e->getMessage();
288  }
289 
290  return $stripepaymentmethod;
291  }
292 
301  public function getSelectedReader($reader, $key = '', $status = 0)
302  {
303  $selectedreader = null;
304 
305  try {
306  // Force to use the correct API key
307  global $stripearrayofkeysbyenv;
308  \Stripe\Stripe::setApiKey($stripearrayofkeysbyenv[$status]['secret_key']);
309  if (empty($key)) { // If the Stripe connect account not set, we use common API usage
310  $selectedreader = \Stripe\Terminal\Reader::retrieve(''.$reader.'');
311  } else {
312  $stripepaymentmethod = \Stripe\Terminal\Reader::retrieve(''.$reader.'', array("stripe_account" => $key));
313  }
314  } catch (Exception $e) {
315  $this->error = $e->getMessage();
316  }
317 
318  return $selectedreader;
319  }
320 
346  public function getPaymentIntent($amount, $currency_code, $tag, $description = '', $object = null, $customer = null, $key = null, $status = 0, $usethirdpartyemailforreceiptemail = 0, $mode = 'automatic', $confirmnow = false, $payment_method = null, $off_session = 0, $noidempotency_key = 1)
347  {
348  global $conf, $user;
349 
350  dol_syslog(get_class($this)."::getPaymentIntent", LOG_INFO, 1);
351 
352  $error = 0;
353 
354  if (empty($status)) {
355  $service = 'StripeTest';
356  } else {
357  $service = 'StripeLive';
358  }
359 
360  $arrayzerounitcurrency = array('BIF', 'CLP', 'DJF', 'GNF', 'JPY', 'KMF', 'KRW', 'MGA', 'PYG', 'RWF', 'VND', 'VUV', 'XAF', 'XOF', 'XPF');
361  if (!in_array($currency_code, $arrayzerounitcurrency)) {
362  $stripeamount = $amount * 100;
363  } else {
364  $stripeamount = $amount;
365  }
366 
367  $fee = $amount * ($conf->global->STRIPE_APPLICATION_FEE_PERCENT / 100) + $conf->global->STRIPE_APPLICATION_FEE;
368  if ($fee >= $conf->global->STRIPE_APPLICATION_FEE_MAXIMAL && $conf->global->STRIPE_APPLICATION_FEE_MAXIMAL > $conf->global->STRIPE_APPLICATION_FEE_MINIMAL) {
369  $fee = $conf->global->STRIPE_APPLICATION_FEE_MAXIMAL;
370  } elseif ($fee < $conf->global->STRIPE_APPLICATION_FEE_MINIMAL) {
371  $fee = $conf->global->STRIPE_APPLICATION_FEE_MINIMAL;
372  }
373  if (!in_array($currency_code, $arrayzerounitcurrency)) {
374  $stripefee = round($fee * 100);
375  } else {
376  $stripefee = round($fee);
377  }
378 
379  $paymentintent = null;
380 
381  if (is_object($object) && getDolGlobalInt('STRIPE_REUSE_EXISTING_INTENT_IF_FOUND') && !getDolGlobalInt('STRIPE_CARD_PRESENT')) {
382  // Warning. If a payment was tried and failed, a payment intent was created.
383  // But if we change something on object to pay (amount or other that does not change the idempotency key), reusing same payment intent is not allowed by Stripe.
384  // Recommended solution is to recreate a new payment intent each time we need one (old one will be automatically closed by Stripe after a delay), Stripe will
385  // automatically return the existing payment intent if idempotency is provided when we try to create the new one.
386  // That's why we can comment the part of code to retrieve a payment intent with object id (never mind if we cumulate payment intent with old ones that will not be used)
387 
388  $sql = "SELECT pi.ext_payment_id, pi.entity, pi.fk_facture, pi.sourcetype, pi.ext_payment_site";
389  $sql .= " FROM ".MAIN_DB_PREFIX."prelevement_demande as pi";
390  $sql .= " WHERE pi.fk_facture = ".((int) $object->id);
391  $sql .= " AND pi.sourcetype = '".$this->db->escape($object->element)."'";
392  $sql .= " AND pi.entity IN (".getEntity('societe').")";
393  $sql .= " AND pi.ext_payment_site = '".$this->db->escape($service)."'";
394 
395  dol_syslog(get_class($this)."::getPaymentIntent search stripe payment intent for object id = ".$object->id, LOG_DEBUG);
396  $resql = $this->db->query($sql);
397  if ($resql) {
398  $num = $this->db->num_rows($resql);
399  if ($num) {
400  $obj = $this->db->fetch_object($resql);
401  $intent = $obj->ext_payment_id;
402 
403  dol_syslog(get_class($this)."::getPaymentIntent found existing payment intent record");
404 
405  // Force to use the correct API key
406  global $stripearrayofkeysbyenv;
407  \Stripe\Stripe::setApiKey($stripearrayofkeysbyenv[$status]['secret_key']);
408 
409  try {
410  if (empty($key)) { // If the Stripe connect account not set, we use common API usage
411  $paymentintent = \Stripe\PaymentIntent::retrieve($intent);
412  } else {
413  $paymentintent = \Stripe\PaymentIntent::retrieve($intent, array("stripe_account" => $key));
414  }
415  } catch (Exception $e) {
416  $error++;
417  $this->error = $e->getMessage();
418  }
419  }
420  }
421  }
422 
423  if (empty($paymentintent)) {
424  // Try to create intent. See https://stripe.com/docs/api/payment_intents/create
425  $ipaddress = getUserRemoteIP();
426  $metadata = array('dol_version'=>DOL_VERSION, 'dol_entity'=>$conf->entity, 'ipaddress'=>$ipaddress);
427  if (is_object($object)) {
428  $metadata['dol_type'] = $object->element;
429  $metadata['dol_id'] = $object->id;
430  if (is_object($object->thirdparty) && $object->thirdparty->id > 0) {
431  $metadata['dol_thirdparty_id'] = $object->thirdparty->id;
432  }
433  }
434 
435  // list of payment method types
436  $paymentmethodtypes = array("card");
437  $descriptor = dol_trunc($tag, 10, 'right', 'UTF-8', 1);
438  if (getDolGlobalInt('STRIPE_SEPA_DIRECT_DEBIT')) {
439  $paymentmethodtypes[] = "sepa_debit"; //&& ($object->thirdparty->isInEEC())
440  //$descriptor = preg_replace('/ref=[^:=]+/', '', $descriptor); // Clean ref
441  }
442  if (getDolGlobalInt('STRIPE_KLARNA')) {
443  $paymentmethodtypes[] = "klarna";
444  }
445  if (getDolGlobalInt('STRIPE_BANCONTACT')) {
446  $paymentmethodtypes[] = "bancontact";
447  }
448  if (getDolGlobalInt('STRIPE_IDEAL')) {
449  $paymentmethodtypes[] = "ideal";
450  }
451  if (getDolGlobalInt('STRIPE_GIROPAY')) {
452  $paymentmethodtypes[] = "giropay";
453  }
454  if (getDolGlobalInt('STRIPE_SOFORT')) {
455  $paymentmethodtypes[] = "sofort";
456  }
457  if (getDolGlobalInt('STRIPE_CARD_PRESENT') && $mode == 'terminal') {
458  $paymentmethodtypes = array("card_present");
459  }
460 
461  $dataforintent = array(
462  "confirm" => $confirmnow, // Do not confirm immediatly during creation of intent
463  "confirmation_method" => $mode,
464  "amount" => $stripeamount,
465  "currency" => $currency_code,
466  "payment_method_types" => $paymentmethodtypes,
467  "description" => $description,
468  //"save_payment_method" => true,
469  "setup_future_usage" => "on_session",
470  "metadata" => $metadata
471  );
472  if ($descriptor) {
473  $dataforintent["statement_descriptor_suffix"] = $descriptor; // For card payment, 22 chars that appears on bank receipt (prefix into stripe setup + this suffix)
474  $dataforintent["statement_descriptor"] = $descriptor; // For SEPA, it will take only statement_descriptor, not statement_descriptor_suffix
475  }
476  if (!is_null($customer)) {
477  $dataforintent["customer"] = $customer;
478  }
479  // payment_method =
480  // payment_method_types = array('card')
481  //var_dump($dataforintent);
482  if ($off_session) {
483  unset($dataforintent['setup_future_usage']);
484  // We can't use both "setup_future_usage" = "off_session" and "off_session" = true.
485  // Because $off_session parameter is dedicated to create paymentintent off_line (and not future payment), we need to use "off_session" = true.
486  //$dataforintent["setup_future_usage"] = "off_session";
487  $dataforintent["off_session"] = true;
488  }
489  if (getDolGlobalInt('STRIPE_GIROPAY')) {
490  unset($dataforintent['setup_future_usage']);
491  }
492  if (getDolGlobalInt('STRIPE_KLARNA')) {
493  unset($dataforintent['setup_future_usage']);
494  }
495  if (getDolGlobalInt('STRIPE_CARD_PRESENT') && $mode == 'terminal') {
496  unset($dataforintent['setup_future_usage']);
497  $dataforintent["capture_method"] = "manual";
498  $dataforintent["confirmation_method"] = "manual";
499  }
500  if (!is_null($payment_method)) {
501  $dataforintent["payment_method"] = $payment_method;
502  $description .= ' - '.$payment_method;
503  }
504 
505  if ($conf->entity != getDolGlobalInt('STRIPECONNECT_PRINCIPAL') && $stripefee > 0) {
506  $dataforintent["application_fee_amount"] = $stripefee;
507  }
508  if ($usethirdpartyemailforreceiptemail && is_object($object) && $object->thirdparty->email) {
509  $dataforintent["receipt_email"] = $object->thirdparty->email;
510  }
511 
512  try {
513  // Force to use the correct API key
514  global $stripearrayofkeysbyenv;
515  \Stripe\Stripe::setApiKey($stripearrayofkeysbyenv[$status]['secret_key']);
516 
517  $arrayofoptions = array();
518  if (empty($noidempotency_key)) {
519  $arrayofoptions["idempotency_key"] = $description;
520  }
521  // Note: If all data for payment intent are same than a previous on, even if we use 'create', Stripe will return ID of the old existing payment intent.
522  if (!empty($key)) { // If the Stripe connect account not set, we use common API usage
523  $arrayofoptions["stripe_account"] = $key;
524  }
525 
526  dol_syslog("dataforintent to create paymentintent = ".var_export($dataforintent, true));
527 
528  $paymentintent = \Stripe\PaymentIntent::create($dataforintent, $arrayofoptions);
529 
530  // Store the payment intent
531  if (is_object($object)) {
532  $paymentintentalreadyexists = 0;
533  // Check that payment intent $paymentintent->id is not already recorded.
534  $sql = "SELECT pi.rowid";
535  $sql .= " FROM ".MAIN_DB_PREFIX."prelevement_demande as pi";
536  $sql .= " WHERE pi.entity IN (".getEntity('societe').")";
537  $sql .= " AND pi.ext_payment_site = '".$this->db->escape($service)."'";
538  $sql .= " AND pi.ext_payment_id = '".$this->db->escape($paymentintent->id)."'";
539 
540  dol_syslog(get_class($this)."::getPaymentIntent search if payment intent already in prelevement_demande", LOG_DEBUG);
541  $resql = $this->db->query($sql);
542  if ($resql) {
543  $num = $this->db->num_rows($resql);
544  if ($num) {
545  $obj = $this->db->fetch_object($resql);
546  if ($obj) {
547  $paymentintentalreadyexists++;
548  }
549  }
550  } else {
551  dol_print_error($this->db);
552  }
553 
554  // If not, we create it.
555  if (!$paymentintentalreadyexists) {
556  $now = dol_now();
557  $sql = "INSERT INTO ".MAIN_DB_PREFIX."prelevement_demande (date_demande, fk_user_demande, ext_payment_id, fk_facture, sourcetype, entity, ext_payment_site, amount)";
558  $sql .= " VALUES ('".$this->db->idate($now)."', ".((int) $user->id).", '".$this->db->escape($paymentintent->id)."', ".((int) $object->id).", '".$this->db->escape($object->element)."', ".((int) $conf->entity).", '".$this->db->escape($service)."', ".((float) $amount).")";
559  $resql = $this->db->query($sql);
560  if (!$resql) {
561  $error++;
562  $this->error = $this->db->lasterror();
563  dol_syslog(get_class($this)."::PaymentIntent failed to insert paymentintent with id=".$paymentintent->id." into database.", LOG_ERR);
564  }
565  }
566  } else {
567  $_SESSION["stripe_payment_intent"] = $paymentintent;
568  }
569  } catch (Stripe\Error\Card $e) {
570  $error++;
571  $this->error = $e->getMessage();
572  $this->code = $e->getStripeCode();
573  $this->declinecode = $e->getDeclineCode();
574  } catch (Exception $e) {
575  //var_dump($dataforintent);
576  //var_dump($description);
577  //var_dump($key);
578  //var_dump($paymentintent);
579  //var_dump($e->getMessage());
580  //var_dump($e);
581  $error++;
582  $this->error = $e->getMessage();
583  $this->code = '';
584  $this->declinecode = '';
585  }
586  }
587 
588  dol_syslog(get_class($this)."::getPaymentIntent return error=".$error." this->error=".$this->error, LOG_INFO, -1);
589 
590  if (!$error) {
591  return $paymentintent;
592  } else {
593  return null;
594  }
595  }
596 
615  public function getSetupIntent($description, $object, $customer, $key, $status, $usethirdpartyemailforreceiptemail = 0, $confirmnow = false)
616  {
617  global $conf;
618 
619  dol_syslog("getSetupIntent description=".$description.' confirmnow='.$confirmnow, LOG_INFO, 1);
620 
621  $error = 0;
622 
623  if (empty($status)) {
624  $service = 'StripeTest';
625  } else {
626  $service = 'StripeLive';
627  }
628 
629  $setupintent = null;
630 
631  if (empty($setupintent)) {
632  $ipaddress = getUserRemoteIP();
633  $metadata = array('dol_version'=>DOL_VERSION, 'dol_entity'=>$conf->entity, 'ipaddress'=>$ipaddress);
634  if (is_object($object)) {
635  $metadata['dol_type'] = $object->element;
636  $metadata['dol_id'] = $object->id;
637  if (is_object($object->thirdparty) && $object->thirdparty->id > 0) {
638  $metadata['dol_thirdparty_id'] = $object->thirdparty->id;
639  }
640  }
641 
642  // list of payment method types
643  $paymentmethodtypes = array("card");
644  if (!empty($conf->global->STRIPE_SEPA_DIRECT_DEBIT)) {
645  $paymentmethodtypes[] = "sepa_debit"; //&& ($object->thirdparty->isInEEC())
646  }
647  if (!empty($conf->global->STRIPE_BANCONTACT)) {
648  $paymentmethodtypes[] = "bancontact";
649  }
650  if (!empty($conf->global->STRIPE_IDEAL)) {
651  $paymentmethodtypes[] = "ideal";
652  }
653  // Giropay not possible for setup intent
654  if (!empty($conf->global->STRIPE_SOFORT)) {
655  $paymentmethodtypes[] = "sofort";
656  }
657 
658  $dataforintent = array(
659  "confirm" => $confirmnow, // Do not confirm immediatly during creation of intent
660  "payment_method_types" => $paymentmethodtypes,
661  "usage" => "off_session",
662  "metadata" => $metadata
663  );
664  if (!is_null($customer)) {
665  $dataforintent["customer"] = $customer;
666  }
667  if (!is_null($description)) {
668  $dataforintent["description"] = $description;
669  }
670  // payment_method =
671  // payment_method_types = array('card')
672  //var_dump($dataforintent);
673 
674  if ($usethirdpartyemailforreceiptemail && is_object($object) && $object->thirdparty->email) {
675  $dataforintent["receipt_email"] = $object->thirdparty->email;
676  }
677 
678  try {
679  // Force to use the correct API key
680  global $stripearrayofkeysbyenv;
681  \Stripe\Stripe::setApiKey($stripearrayofkeysbyenv[$status]['secret_key']);
682 
683  dol_syslog("getSetupIntent ".$stripearrayofkeysbyenv[$status]['publishable_key'], LOG_DEBUG);
684 
685  // Note: If all data for payment intent are same than a previous on, even if we use 'create', Stripe will return ID of the old existing payment intent.
686  if (empty($key)) { // If the Stripe connect account not set, we use common API usage
687  //$setupintent = \Stripe\SetupIntent::create($dataforintent, array("idempotency_key" => "$description"));
688  $setupintent = \Stripe\SetupIntent::create($dataforintent, array());
689  } else {
690  //$setupintent = \Stripe\SetupIntent::create($dataforintent, array("idempotency_key" => "$description", "stripe_account" => $key));
691  $setupintent = \Stripe\SetupIntent::create($dataforintent, array("stripe_account" => $key));
692  }
693  //var_dump($setupintent->id);
694 
695  // Store the setup intent
696  /*if (is_object($object))
697  {
698  $setupintentalreadyexists = 0;
699  // Check that payment intent $setupintent->id is not already recorded.
700  $sql = "SELECT pi.rowid";
701  $sql.= " FROM " . MAIN_DB_PREFIX . "prelevement_demande as pi";
702  $sql.= " WHERE pi.entity IN (".getEntity('societe').")";
703  $sql.= " AND pi.ext_payment_site = '" . $this->db->escape($service) . "'";
704  $sql.= " AND pi.ext_payment_id = '".$this->db->escape($setupintent->id)."'";
705 
706  dol_syslog(get_class($this) . "::getPaymentIntent search if payment intent already in prelevement_demande", LOG_DEBUG);
707  $resql = $this->db->query($sql);
708  if ($resql) {
709  $num = $this->db->num_rows($resql);
710  if ($num)
711  {
712  $obj = $this->db->fetch_object($resql);
713  if ($obj) $setupintentalreadyexists++;
714  }
715  }
716  else dol_print_error($this->db);
717 
718  // If not, we create it.
719  if (! $setupintentalreadyexists)
720  {
721  $now=dol_now();
722  $sql = "INSERT INTO " . MAIN_DB_PREFIX . "prelevement_demande (date_demande, fk_user_demande, ext_payment_id, fk_facture, sourcetype, entity, ext_payment_site)";
723  $sql .= " VALUES ('".$this->db->idate($now)."', ".((int) $user->id).", '".$this->db->escape($setupintent->id)."', ".((int) $object->id).", '".$this->db->escape($object->element)."', " . ((int) $conf->entity) . ", '" . $this->db->escape($service) . "', ".((float) $amount).")";
724  $resql = $this->db->query($sql);
725  if (! $resql)
726  {
727  $error++;
728  $this->error = $this->db->lasterror();
729  dol_syslog(get_class($this) . "::PaymentIntent failed to insert paymentintent with id=".$setupintent->id." into database.");
730  }
731  }
732  }
733  else
734  {
735  $_SESSION["stripe_setup_intent"] = $setupintent;
736  }*/
737  } catch (Exception $e) {
738  //var_dump($dataforintent);
739  //var_dump($description);
740  //var_dump($key);
741  //var_dump($setupintent);
742  //var_dump($e->getMessage());
743  $error++;
744  $this->error = $e->getMessage();
745  }
746  }
747 
748  if (!$error) {
749  dol_syslog("getSetupIntent ".(is_object($setupintent) ? $setupintent->id : ''), LOG_INFO, -1);
750  return $setupintent;
751  } else {
752  dol_syslog("getSetupIntent return error=".$error, LOG_INFO, -1);
753  return null;
754  }
755  }
756 
757 
768  public function cardStripe($cu, CompanyPaymentMode $object, $stripeacc = '', $status = 0, $createifnotlinkedtostripe = 0)
769  {
770  global $conf, $user, $langs;
771 
772  $card = null;
773 
774  $sql = "SELECT sa.stripe_card_ref, sa.proprio, sa.exp_date_month, sa.exp_date_year, sa.number, sa.cvn"; // stripe_card_ref is card_....
775  $sql .= " FROM ".MAIN_DB_PREFIX."societe_rib as sa";
776  $sql .= " WHERE sa.rowid = ".((int) $object->id); // We get record from ID, no need for filter on entity
777  $sql .= " AND sa.type = 'card'";
778 
779  dol_syslog(get_class($this)."::cardStripe search stripe card id for paymentmode id=".$object->id.", stripeacc=".$stripeacc.", status=".$status.", createifnotlinkedtostripe=".$createifnotlinkedtostripe, LOG_DEBUG);
780  $resql = $this->db->query($sql);
781  if ($resql) {
782  $num = $this->db->num_rows($resql);
783  if ($num) {
784  $obj = $this->db->fetch_object($resql);
785  $cardref = $obj->stripe_card_ref;
786  dol_syslog(get_class($this)."::cardStripe cardref=".$cardref);
787  if ($cardref) {
788  try {
789  if (empty($stripeacc)) { // If the Stripe connect account not set, we use common API usage
790  if (!preg_match('/^pm_/', $cardref) && !empty($cu->sources)) {
791  $card = $cu->sources->retrieve($cardref);
792  } else {
793  $card = \Stripe\PaymentMethod::retrieve($cardref);
794  }
795  } else {
796  if (!preg_match('/^pm_/', $cardref) && !empty($cu->sources)) {
797  //$card = $cu->sources->retrieve($cardref, array("stripe_account" => $stripeacc)); // this API fails when array stripe_account is provided
798  $card = $cu->sources->retrieve($cardref);
799  } else {
800  //$card = \Stripe\PaymentMethod::retrieve($cardref, array("stripe_account" => $stripeacc)); // Don't know if this works
801  $card = \Stripe\PaymentMethod::retrieve($cardref);
802  }
803  }
804  } catch (Exception $e) {
805  $this->error = $e->getMessage();
806  dol_syslog($this->error, LOG_WARNING);
807  }
808  } elseif ($createifnotlinkedtostripe) {
809  $exp_date_month = $obj->exp_date_month;
810  $exp_date_year = $obj->exp_date_year;
811  $number = $obj->number;
812  $cvc = $obj->cvn; // cvn in database, cvc for stripe
813  $cardholdername = $obj->proprio;
814 
815  $ipaddress = getUserRemoteIP();
816 
817  $dataforcard = array(
818  "source" => array('object'=>'card', 'exp_month'=>$exp_date_month, 'exp_year'=>$exp_date_year, 'number'=>$number, 'cvc'=>$cvc, 'name'=>$cardholdername),
819  "metadata" => array('dol_id'=>$object->id, 'dol_version'=>DOL_VERSION, 'dol_entity'=>$conf->entity, 'ipaddress'=>$ipaddress)
820  );
821 
822  //$a = \Stripe\Stripe::getApiKey();
823  //var_dump($a);
824  //var_dump($stripeacc);exit;
825  try {
826  if (empty($stripeacc)) { // If the Stripe connect account not set, we use common API usage
827  if (empty($conf->global->STRIPE_USE_INTENT_WITH_AUTOMATIC_CONFIRMATION)) {
828  dol_syslog("Try to create card with dataforcard = ".json_encode($dataforcard));
829  $card = $cu->sources->create($dataforcard);
830  if (!$card) {
831  $this->error = 'Creation of card on Stripe has failed';
832  }
833  } else {
834  $connect = '';
835  if (!empty($stripeacc)) {
836  $connect = $stripeacc.'/';
837  }
838  $url = 'https://dashboard.stripe.com/'.$connect.'test/customers/'.$cu->id;
839  if ($status) {
840  $url = 'https://dashboard.stripe.com/'.$connect.'customers/'.$cu->id;
841  }
842  $urtoswitchonstripe = ' <a href="'.$url.'" target="_stripe">'.img_picto($langs->trans('ShowInStripe'), 'globe').'</a>';
843 
844  //dol_syslog("Error: This case is not supported", LOG_ERR);
845  $this->error = $langs->trans('CreationOfPaymentModeMustBeDoneFromStripeInterface', $urtoswitchonstripe);
846  }
847  } else {
848  if (empty($conf->global->STRIPE_USE_INTENT_WITH_AUTOMATIC_CONFIRMATION)) {
849  dol_syslog("Try to create card with dataforcard = ".json_encode($dataforcard));
850  $card = $cu->sources->create($dataforcard, array("stripe_account" => $stripeacc));
851  if (!$card) {
852  $this->error = 'Creation of card on Stripe has failed';
853  }
854  } else {
855  $connect = '';
856  if (!empty($stripeacc)) {
857  $connect = $stripeacc.'/';
858  }
859  $url = 'https://dashboard.stripe.com/'.$connect.'test/customers/'.$cu->id;
860  if ($status) {
861  $url = 'https://dashboard.stripe.com/'.$connect.'customers/'.$cu->id;
862  }
863  $urtoswitchonstripe = ' <a href="'.$url.'" target="_stripe">'.img_picto($langs->trans('ShowInStripe'), 'globe').'</a>';
864 
865  //dol_syslog("Error: This case is not supported", LOG_ERR);
866  $this->error = $langs->trans('CreationOfPaymentModeMustBeDoneFromStripeInterface', $urtoswitchonstripe);
867  }
868  }
869 
870  if ($card) {
871  $sql = "UPDATE ".MAIN_DB_PREFIX."societe_rib";
872  $sql .= " SET stripe_card_ref = '".$this->db->escape($card->id)."', card_type = '".$this->db->escape($card->brand)."',";
873  $sql .= " country_code = '".$this->db->escape($card->country)."',";
874  $sql .= " approved = ".($card->cvc_check == 'pass' ? 1 : 0);
875  $sql .= " WHERE rowid = ".((int) $object->id);
876  $sql .= " AND type = 'card'";
877  $resql = $this->db->query($sql);
878  if (!$resql) {
879  $this->error = $this->db->lasterror();
880  }
881  }
882  } catch (Exception $e) {
883  $this->error = $e->getMessage();
884  dol_syslog($this->error, LOG_WARNING);
885  }
886  }
887  }
888  } else {
889  dol_print_error($this->db);
890  }
891 
892  return $card;
893  }
894 
895 
906  public function sepaStripe($cu, CompanyPaymentMode $object, $stripeacc = '', $status = 0, $createifnotlinkedtostripe = 0)
907  {
908  global $conf, $user, $langs;
909  $sepa = null;
910 
911  $sql = "SELECT sa.stripe_card_ref, sa.proprio, sa.iban_prefix"; // stripe_card_ref is src_ for sepa
912  $sql .= " FROM ".MAIN_DB_PREFIX."societe_rib as sa";
913  $sql .= " WHERE sa.rowid = ".((int) $object->id); // We get record from ID, no need for filter on entity
914  $sql .= " AND sa.type = 'ban'"; //type ban to get normal bank account of customer (prelevement)
915 
916  $soc = new Societe($this->db);
917  $soc->fetch($object->fk_soc);
918 
919  dol_syslog(get_class($this)."::sepaStripe search stripe ban id for paymentmode id=".$object->id.", stripeacc=".$stripeacc.", status=".$status.", createifnotlinkedtostripe=".$createifnotlinkedtostripe, LOG_DEBUG);
920  $resql = $this->db->query($sql);
921  if ($resql) {
922  $num = $this->db->num_rows($resql);
923  if ($num) {
924  $obj = $this->db->fetch_object($resql);
925  $cardref = $obj->stripe_card_ref;
926  dol_syslog(get_class($this)."::sepaStripe cardref=".$cardref);
927  if ($cardref) {
928  try {
929  if (empty($stripeacc)) { // If the Stripe connect account not set, we use common API usage
930  if (!preg_match('/^pm_/', $cardref) && !empty($cu->sources)) {
931  $sepa = $cu->sources->retrieve($cardref);
932  } else {
933  $sepa = \Stripe\PaymentMethod::retrieve($cardref);
934  }
935  } else {
936  if (!preg_match('/^pm_/', $cardref) && !empty($cu->sources)) {
937  //$sepa = $cu->sources->retrieve($cardref, array("stripe_account" => $stripeacc)); // this API fails when array stripe_account is provided
938  $sepa = $cu->sources->retrieve($cardref);
939  } else {
940  //$sepa = \Stripe\PaymentMethod::retrieve($cardref, array("stripe_account" => $stripeacc)); // Don't know if this works
941  $sepa = \Stripe\PaymentMethod::retrieve($cardref);
942  }
943  }
944  } catch (Exception $e) {
945  $this->error = $e->getMessage();
946  dol_syslog($this->error, LOG_WARNING);
947  }
948  } elseif ($createifnotlinkedtostripe) {
949  $iban = $obj->iban_prefix; //prefix ?
950  $ipaddress = getUserRemoteIP();
951 
952  $dataforcard = array(
953  'type'=>'sepa_debit',
954  "sepa_debit" => array('iban' => $iban),
955  'currency' => 'eur',
956  'usage' => 'reusable',
957  'owner' => array(
958  'name' => $soc->name,
959  ),
960  "metadata" => array('dol_id'=>$object->id, 'dol_version'=>DOL_VERSION, 'dol_entity'=>$conf->entity, 'ipaddress'=>$ipaddress)
961  );
962 
963  //$a = \Stripe\Stripe::getApiKey();
964  //var_dump($a);var_dump($stripeacc);exit;
965  try {
966  dol_syslog("Try to create sepa_debit 0");
967 
968  $service = 'StripeTest';
969  $servicestatus = 0;
970  if (!empty($conf->global->STRIPE_LIVE) && !GETPOST('forcesandbox', 'alpha')) {
971  $service = 'StripeLive';
972  $servicestatus = 1;
973  }
974  // Force to use the correct API key
975  global $stripearrayofkeysbyenv;
976  $stripeacc = $stripearrayofkeysbyenv[$servicestatus]['secret_key'];
977 
978  dol_syslog("Try to create sepa_debit with data = ".json_encode($dataforcard));
979  $s = new \Stripe\StripeClient($stripeacc);
980  $sepa = $s->sources->create($dataforcard);
981  if (!$sepa) {
982  $this->error = 'Creation of sepa_debit on Stripe has failed';
983  } else {
984  // association du client avec cette source de paimeent
985  $cs = $cu->createSource($cu->id, array('source' => $sepa->id));
986  if (!$cs) {
987  $this->error = 'Link SEPA <-> Customer failed';
988  } else {
989  dol_syslog("Try to create sepa_debit 3");
990  // print json_encode($sepa);
991 
992  $sql = "UPDATE ".MAIN_DB_PREFIX."societe_rib";
993  $sql .= " SET stripe_card_ref = '".$this->db->escape($sepa->id)."', card_type = 'sepa_debit',";
994  $sql .= " stripe_account= '" . $this->db->escape($cu->id . "@" . $stripeacc) . "'";
995  $sql .= " WHERE rowid = ".((int) $object->id);
996  $sql .= " AND type = 'ban'";
997  $resql = $this->db->query($sql);
998  if (!$resql) {
999  $this->error = $this->db->lasterror();
1000  }
1001  }
1002  }
1003  } catch (Exception $e) {
1004  $this->error = $e->getMessage();
1005  dol_syslog($this->error, LOG_WARNING);
1006  }
1007  }
1008  }
1009  } else {
1010  dol_print_error($this->db);
1011  }
1012 
1013  return $sepa;
1014  }
1015 
1032  public function createPaymentStripe($amount, $currency, $origin, $item, $source, $customer, $account, $status = 0, $usethirdpartyemailforreceiptemail = 0, $capture = true)
1033  {
1034  global $conf;
1035 
1036  $error = 0;
1037 
1038  if (empty($status)) {
1039  $service = 'StripeTest';
1040  } else {
1041  $service = 'StripeLive';
1042  }
1043 
1044  $sql = "SELECT sa.key_account as key_account, sa.fk_soc, sa.entity";
1045  $sql .= " FROM ".MAIN_DB_PREFIX."societe_account as sa";
1046  $sql .= " WHERE sa.key_account = '".$this->db->escape($customer)."'";
1047  //$sql.= " AND sa.entity IN (".getEntity('societe').")";
1048  $sql .= " AND sa.site = 'stripe' AND sa.status = ".((int) $status);
1049 
1050  dol_syslog(get_class($this)."::fetch", LOG_DEBUG);
1051  $result = $this->db->query($sql);
1052  if ($result) {
1053  if ($this->db->num_rows($result)) {
1054  $obj = $this->db->fetch_object($result);
1055  $key = $obj->fk_soc;
1056  } else {
1057  $key = null;
1058  }
1059  } else {
1060  $key = null;
1061  }
1062 
1063  $arrayzerounitcurrency = array('BIF', 'CLP', 'DJF', 'GNF', 'JPY', 'KMF', 'KRW', 'MGA', 'PYG', 'RWF', 'VND', 'VUV', 'XAF', 'XOF', 'XPF');
1064  if (!in_array($currency, $arrayzerounitcurrency)) {
1065  $stripeamount = $amount * 100;
1066  } else {
1067  $stripeamount = $amount;
1068  }
1069 
1070  $societe = new Societe($this->db);
1071  if ($key > 0) {
1072  $societe->fetch($key);
1073  }
1074 
1075  $description = "";
1076  $ref = "";
1077  if ($origin == 'order') {
1078  $order = new Commande($this->db);
1079  $order->fetch($item);
1080  $ref = $order->ref;
1081  $description = "ORD=".$ref.".CUS=".$societe->id.".PM=stripe";
1082  } elseif ($origin == 'invoice') {
1083  $invoice = new Facture($this->db);
1084  $invoice->fetch($item);
1085  $ref = $invoice->ref;
1086  $description = "INV=".$ref.".CUS=".$societe->id.".PM=stripe";
1087  }
1088 
1089  $ipaddress = getUserRemoteIP();
1090 
1091  $metadata = array(
1092  "dol_id" => "".$item."",
1093  "dol_type" => "".$origin."",
1094  "dol_thirdparty_id" => "".$societe->id."",
1095  'dol_thirdparty_name' => $societe->name,
1096  'dol_version'=>DOL_VERSION,
1097  'dol_entity'=>$conf->entity,
1098  'ipaddress'=>$ipaddress
1099  );
1100  $return = new Stripe($this->db);
1101  try {
1102  // Force to use the correct API key
1103  global $stripearrayofkeysbyenv;
1104  \Stripe\Stripe::setApiKey($stripearrayofkeysbyenv[$status]['secret_key']);
1105 
1106  if (empty($conf->stripeconnect->enabled)) { // With a common Stripe account
1107  if (preg_match('/pm_/i', $source)) {
1108  $stripecard = $source;
1109  $amountstripe = $stripeamount;
1110  $FULLTAG = 'PFBO'; // Payment From Back Office
1111  $stripe = $return;
1112  $amounttopay = $amount;
1113  $servicestatus = $status;
1114 
1115  dol_syslog("* createPaymentStripe get stripeacc", LOG_DEBUG);
1116  $stripeacc = $stripe->getStripeAccount($service); // Get Stripe OAuth connect account if it exists (no network access here)
1117 
1118  dol_syslog("* createPaymentStripe Create payment for customer ".$customer->id." on source card ".$stripecard->id.", amounttopay=".$amounttopay.", amountstripe=".$amountstripe.", FULLTAG=".$FULLTAG, LOG_DEBUG);
1119 
1120  // Create payment intent and charge payment (confirmnow = true)
1121  $paymentintent = $stripe->getPaymentIntent($amounttopay, $currency, $FULLTAG, $description, $invoice, $customer->id, $stripeacc, $servicestatus, 0, 'automatic', true, $stripecard->id, 1);
1122 
1123  $charge = new stdClass();
1124  if ($paymentintent->status == 'succeeded') {
1125  $charge->status = 'ok';
1126  } else {
1127  $charge->status = 'failed';
1128  $charge->failure_code = $stripe->code;
1129  $charge->failure_message = $stripe->error;
1130  $charge->failure_declinecode = $stripe->declinecode;
1131  $stripefailurecode = $stripe->code;
1132  $stripefailuremessage = $stripe->error;
1133  $stripefailuredeclinecode = $stripe->declinecode;
1134  }
1135  } elseif (preg_match('/acct_/i', $source)) {
1136  $charge = \Stripe\Charge::create(array(
1137  "amount" => "$stripeamount",
1138  "currency" => "$currency",
1139  "statement_descriptor_suffix" => dol_trunc($description, 10, 'right', 'UTF-8', 1), // 22 chars that appears on bank receipt (company + description)
1140  "description" => "Stripe payment: ".$description,
1141  "capture" => $capture,
1142  "metadata" => $metadata,
1143  "source" => "$source"
1144  ));
1145  } else {
1146  $paymentarray = array(
1147  "amount" => "$stripeamount",
1148  "currency" => "$currency",
1149  "statement_descriptor_suffix" => dol_trunc($description, 10, 'right', 'UTF-8', 1), // 22 chars that appears on bank receipt (company + description)
1150  "description" => "Stripe payment: ".$description,
1151  "capture" => $capture,
1152  "metadata" => $metadata,
1153  "source" => "$source",
1154  "customer" => "$customer"
1155  );
1156 
1157  if ($societe->email && $usethirdpartyemailforreceiptemail) {
1158  $paymentarray["receipt_email"] = $societe->email;
1159  }
1160 
1161  $charge = \Stripe\Charge::create($paymentarray, array("idempotency_key" => "$description"));
1162  }
1163  } else {
1164  // With Stripe Connect
1165  $fee = $amount * ($conf->global->STRIPE_APPLICATION_FEE_PERCENT / 100) + $conf->global->STRIPE_APPLICATION_FEE;
1166  if ($fee >= $conf->global->STRIPE_APPLICATION_FEE_MAXIMAL && $conf->global->STRIPE_APPLICATION_FEE_MAXIMAL > $conf->global->STRIPE_APPLICATION_FEE_MINIMAL) {
1167  $fee = $conf->global->STRIPE_APPLICATION_FEE_MAXIMAL;
1168  } elseif ($fee < $conf->global->STRIPE_APPLICATION_FEE_MINIMAL) {
1169  $fee = $conf->global->STRIPE_APPLICATION_FEE_MINIMAL;
1170  }
1171 
1172  if (!in_array($currency, $arrayzerounitcurrency)) {
1173  $stripefee = round($fee * 100);
1174  } else {
1175  $stripefee = round($fee);
1176  }
1177 
1178  $paymentarray = array(
1179  "amount" => "$stripeamount",
1180  "currency" => "$currency",
1181  "statement_descriptor_suffix" => dol_trunc($description, 10, 'right', 'UTF-8', 1), // 22 chars that appears on bank receipt (company + description)
1182  "description" => "Stripe payment: ".$description,
1183  "capture" => $capture,
1184  "metadata" => $metadata,
1185  "source" => "$source",
1186  "customer" => "$customer"
1187  );
1188  if ($conf->entity != $conf->global->STRIPECONNECT_PRINCIPAL && $stripefee > 0) {
1189  $paymentarray["application_fee_amount"] = $stripefee;
1190  }
1191  if ($societe->email && $usethirdpartyemailforreceiptemail) {
1192  $paymentarray["receipt_email"] = $societe->email;
1193  }
1194 
1195  if (preg_match('/pm_/i', $source)) {
1196  $stripecard = $source;
1197  $amountstripe = $stripeamount;
1198  $FULLTAG = 'PFBO'; // Payment From Back Office
1199  $stripe = $return;
1200  $amounttopay = $amount;
1201  $servicestatus = $status;
1202 
1203  dol_syslog("* createPaymentStripe get stripeacc", LOG_DEBUG);
1204  $stripeacc = $stripe->getStripeAccount($service); // Get Stripe OAuth connect account if it exists (no network access here)
1205 
1206  dol_syslog("* createPaymentStripe Create payment on card ".$stripecard->id.", amounttopay=".$amounttopay.", amountstripe=".$amountstripe.", FULLTAG=".$FULLTAG, LOG_DEBUG);
1207 
1208  // Create payment intent and charge payment (confirmnow = true)
1209  $paymentintent = $stripe->getPaymentIntent($amounttopay, $currency, $FULLTAG, $description, $invoice, $customer->id, $stripeacc, $servicestatus, 0, 'automatic', true, $stripecard->id, 1);
1210 
1211  $charge = new stdClass();
1212  if ($paymentintent->status == 'succeeded') {
1213  $charge->status = 'ok';
1214  $charge->id = $paymentintent->id;
1215  } else {
1216  $charge->status = 'failed';
1217  $charge->failure_code = $stripe->code;
1218  $charge->failure_message = $stripe->error;
1219  $charge->failure_declinecode = $stripe->declinecode;
1220  }
1221  } else {
1222  $charge = \Stripe\Charge::create($paymentarray, array("idempotency_key" => "$description", "stripe_account" => "$account"));
1223  }
1224  }
1225  if (isset($charge->id)) {
1226  }
1227 
1228  $return->statut = 'success';
1229  $return->id = $charge->id;
1230 
1231  if (preg_match('/pm_/i', $source)) {
1232  $return->message = 'Payment retrieved by card status = '.$charge->status;
1233  } else {
1234  if ($charge->source->type == 'card') {
1235  $return->message = $charge->source->card->brand." ....".$charge->source->card->last4;
1236  } elseif ($charge->source->type == 'three_d_secure') {
1237  $stripe = new Stripe($this->db);
1238  $src = \Stripe\Source::retrieve("".$charge->source->three_d_secure->card."", array(
1239  "stripe_account" => $stripe->getStripeAccount($service)
1240  ));
1241  $return->message = $src->card->brand." ....".$src->card->last4;
1242  } else {
1243  $return->message = $charge->id;
1244  }
1245  }
1246  } catch (\Stripe\Error\Card $e) {
1247  include DOL_DOCUMENT_ROOT.'/core/class/CMailFile.class.php';
1248  // Since it's a decline, \Stripe\Error\Card will be caught
1249  $body = $e->getJsonBody();
1250  $err = $body['error'];
1251 
1252  $return->statut = 'error';
1253  $return->id = $err['charge'];
1254  $return->type = $err['type'];
1255  $return->code = $err['code'];
1256  $return->message = $err['message'];
1257  $body = "Error: <br>".$return->id." ".$return->message." ";
1258  $subject = '[Alert] Payment error using Stripe';
1259  $cmailfile = new CMailFile($subject, $conf->global->ONLINE_PAYMENT_SENDEMAIL, $conf->global->MAIN_INFO_SOCIETE_MAIL, $body);
1260  $cmailfile->sendfile();
1261 
1262  $error++;
1263  dol_syslog($e->getMessage(), LOG_WARNING, 0, '_stripe');
1264  } catch (\Stripe\Error\RateLimit $e) {
1265  // Too many requests made to the API too quickly
1266  $error++;
1267  dol_syslog($e->getMessage(), LOG_WARNING, 0, '_stripe');
1268  } catch (\Stripe\Error\InvalidRequest $e) {
1269  // Invalid parameters were supplied to Stripe's API
1270  $error++;
1271  dol_syslog($e->getMessage(), LOG_WARNING, 0, '_stripe');
1272  } catch (\Stripe\Error\Authentication $e) {
1273  // Authentication with Stripe's API failed
1274  // (maybe you changed API keys recently)
1275  $error++;
1276  dol_syslog($e->getMessage(), LOG_WARNING, 0, '_stripe');
1277  } catch (\Stripe\Error\ApiConnection $e) {
1278  // Network communication with Stripe failed
1279  $error++;
1280  dol_syslog($e->getMessage(), LOG_WARNING, 0, '_stripe');
1281  } catch (\Stripe\Error\Base $e) {
1282  // Display a very generic error to the user, and maybe send
1283  // yourself an email
1284  $error++;
1285  dol_syslog($e->getMessage(), LOG_WARNING, 0, '_stripe');
1286  } catch (Exception $e) {
1287  // Something else happened, completely unrelated to Stripe
1288  $error++;
1289  dol_syslog($e->getMessage(), LOG_WARNING, 0, '_stripe');
1290  }
1291  return $return;
1292  }
1293 }
Stripe\customerStripe
customerStripe(Societe $object, $key='', $status=0, $createifnotlinkedtostripe=0)
Get the Stripe customer of a thirdparty (with option to create it in Stripe if not linked yet).
Definition: stripe.class.php:156
Societe
Class to manage third parties objects (customers, suppliers, prospects...)
Definition: societe.class.php:49
db
$conf db
API class for accounts.
Definition: inc.php:41
Stripe\getStripeAccount
getStripeAccount($mode='StripeTest', $fk_soc=0, $entity=-1)
Return main company OAuth Connect stripe account.
Definition: stripe.class.php:89
dol_trunc
dol_trunc($string, $size=40, $trunc='right', $stringencoding='UTF-8', $nodot=0, $display=0)
Truncate a string to a particular length adding '…' if string larger than length.
Definition: functions.lib.php:3949
Stripe\sepaStripe
sepaStripe($cu, CompanyPaymentMode $object, $stripeacc='', $status=0, $createifnotlinkedtostripe=0)
Get the Stripe SEPA of a company payment mode.
Definition: stripe.class.php:906
Stripe\__construct
__construct($db)
Constructor.
Definition: stripe.class.php:75
GETPOST
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
Definition: functions.lib.php:520
Stripe\createPaymentStripe
createPaymentStripe($amount, $currency, $origin, $item, $source, $customer, $account, $status=0, $usethirdpartyemailforreceiptemail=0, $capture=true)
Create charge.
Definition: stripe.class.php:1032
dol_print_error
dol_print_error($db='', $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
Definition: functions.lib.php:4993
SocieteAccount
Class for SocieteAccount.
Definition: societeaccount.class.php:35
Stripe\getSetupIntent
getSetupIntent($description, $object, $customer, $key, $status, $usethirdpartyemailforreceiptemail=0, $confirmnow=false)
Get the Stripe payment intent.
Definition: stripe.class.php:615
CMailFile
Class to send emails (with attachments or not) Usage: $mailfile = new CMailFile($subject,...
Definition: CMailFile.class.php:41
Facture
Class to manage invoices.
Definition: facture.class.php:60
CommonObject
Parent class of all other business classes (invoices, contracts, proposals, orders,...
Definition: commonobject.class.php:44
Stripe\getSelectedReader
getSelectedReader($reader, $key='', $status=0)
Get the Stripe reader Object from its ID.
Definition: stripe.class.php:301
Stripe\getStripeCustomerAccount
getStripeCustomerAccount($id, $status=0, $site_account='')
getStripeCustomerAccount
Definition: stripe.class.php:138
img_picto
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2)
Show picto whatever it's its name (generic function)
Definition: functions.lib.php:4024
Exception
code
print *****$script_file(".$version.") pid code
! Closing after partial payment: discount_vat, badcustomer or badsupplier, bankcharge,...
Definition: sync_members_ldap2dolibarr.php:60
$resql
if(isModEnabled('facture') &&!empty($user->rights->facture->lire)) if((isModEnabled('fournisseur') &&empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD) && $user->hasRight("fournisseur", "facture", "lire"))||(isModEnabled('supplier_invoice') && $user->hasRight("supplier_invoice", "lire"))) if(isModEnabled('don') &&!empty($user->rights->don->lire)) if(isModEnabled('tax') &&!empty($user->rights->tax->charges->lire)) if(isModEnabled('facture') &&isModEnabled('commande') && $user->hasRight("commande", "lire") &&empty($conf->global->WORKFLOW_DISABLE_CREATE_INVOICE_FROM_ORDER)) $resql
Social contributions to pay.
Definition: index.php:745
Commande
Class to manage customers orders.
Definition: commande.class.php:46
dol_syslog
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
Definition: functions.lib.php:1628
Stripe\getPaymentIntent
getPaymentIntent($amount, $currency_code, $tag, $description='', $object=null, $customer=null, $key=null, $status=0, $usethirdpartyemailforreceiptemail=0, $mode='automatic', $confirmnow=false, $payment_method=null, $off_session=0, $noidempotency_key=1)
Get the Stripe payment intent.
Definition: stripe.class.php:346
Stripe\cardStripe
cardStripe($cu, CompanyPaymentMode $object, $stripeacc='', $status=0, $createifnotlinkedtostripe=0)
Get the Stripe card of a company payment mode (option to create it on Stripe if not linked yet is no ...
Definition: stripe.class.php:768
Stripe\getPaymentMethodStripe
getPaymentMethodStripe($paymentmethod, $key='', $status=0)
Get the Stripe payment method Object from its ID.
Definition: stripe.class.php:273
dol_now
dol_now($mode='auto')
Return date for now.
Definition: functions.lib.php:2951
Stripe
Stripe class.
Definition: stripe.class.php:29
CompanyPaymentMode
Class for CompanyPaymentMode.
Definition: companypaymentmode.class.php:33
getDolGlobalInt
getDolGlobalInt($key, $default=0)
Return dolibarr global constant int value.
Definition: functions.lib.php:96
getUserRemoteIP
getUserRemoteIP()
Return the IP of remote user.
Definition: functions.lib.php:3632
isInEEC
isInEEC($object)
Return if a country of an object is inside the EEC (European Economic Community)
Definition: company.lib.php:780
float
div float
Buy price without taxes.
Definition: style.css.php:913
if
if(!defined( 'CSRFCHECK_WITH_TOKEN'))
Definition: journals_list.php:25