dolibarr 23.0.3
stripe.class.php
1<?php
2/* Copyright (C) 2018-2021 Thibault FOUCART <support@ptibogxiv.net>
3 * Copyright (C) 2024 Frédéric France <frederic.france@free.fr>
4 * Copyright (C) 2024-2025 MDW <mdeweerd@users.noreply.github.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 */
19
20// Put here all includes required by your class file
21require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php';
22require_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php';
23require_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php';
24require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
25require_once DOL_DOCUMENT_ROOT.'/stripe/config.php'; // This set stripe global $stripearrayofkeys and $stripearrayofkeysbyenv
26
31class Stripe extends CommonObject
32{
36 public $rowid;
37
41 public $fk_soc;
42
46 public $fk_key;
47
51 public $id; // @phpstan-ignore-line
52
56 public $mode;
57
61 public $entity;
62
66 public $type;
67
71 public $code;
72
76 public $declinecode;
77
81 public $message;
82
88 public function __construct($db)
89 {
90 $this->db = $db;
91 }
92
93
102 public function getStripeAccount($mode = 'StripeTest', $fk_soc = 0, $entity = -1)
103 {
104 global $conf;
105
106 $key = '';
107 if ($entity < 0) {
108 $entity = $conf->entity;
109 }
110
111 $sql = "SELECT tokenstring";
112 $sql .= " FROM ".MAIN_DB_PREFIX."oauth_token";
113 $sql .= " WHERE service = '".$this->db->escape($mode)."'";
114 $sql .= " AND entity = ".((int) $entity);
115 if ($fk_soc > 0) {
116 $sql .= " AND fk_soc = ".((int) $fk_soc);
117 } else {
118 $sql .= " AND fk_soc IS NULL";
119 }
120 $sql .= " AND fk_user IS NULL AND fk_adherent IS NULL";
121
122 dol_syslog(get_class($this)."::getStripeAccount", LOG_DEBUG);
123
124 $result = $this->db->query($sql);
125 if ($result) {
126 if ($this->db->num_rows($result)) {
127 $obj = $this->db->fetch_object($result);
128 $tokenstring = $obj->tokenstring;
129
130 if ($tokenstring) {
131 $tmparray = json_decode($tokenstring);
132 $key = empty($tmparray->stripe_user_id) ? '' : $tmparray->stripe_user_id;
133 }
134 } else {
135 $tokenstring = '';
136 }
137 } else {
138 dol_print_error($this->db);
139 }
140
141 dol_syslog("No dedicated Stripe Connect account available for entity ".$conf->entity);
142
143 return $key;
144 }
145
154 public function getStripeCustomerAccount($id, $status = 0, $site_account = '')
155 {
156 include_once DOL_DOCUMENT_ROOT.'/societe/class/societeaccount.class.php';
157 $societeaccount = new SocieteAccount($this->db);
158 return $societeaccount->getCustomerAccount($id, 'stripe', $status, $site_account); // Get thirdparty cus_...
159 }
160
161
172 public function customerStripe($object, $key = '', $status = 0, $createifnotlinkedtostripe = 0)
173 {
174 global $conf, $user;
175
176 if (empty($object->id)) {
177 dol_syslog("customerStripe is called with the parameter object that is not loaded");
178 return null;
179 }
180
181 $customer = null;
182
183 // Force to use the correct API key
184 global $stripearrayofkeysbyenv;
185 \Stripe\Stripe::setApiKey($stripearrayofkeysbyenv[$status]['secret_key']);
186
187 $sql = "SELECT sa.key_account as key_account, sa.entity"; // key_account is cus_....
188 $sql .= " FROM ".MAIN_DB_PREFIX."societe_account as sa";
189 $sql .= " WHERE sa.fk_soc = ".((int) $object->id);
190 $sql .= " AND sa.entity IN (".getEntity('societe').")";
191 $sql .= " AND sa.site = 'stripe' AND sa.status = ".((int) $status);
192 $sql .= " AND (sa.site_account IS NULL OR sa.site_account = '' OR sa.site_account = '".$this->db->escape($stripearrayofkeysbyenv[$status]['publishable_key'])."')";
193 $sql .= " AND sa.key_account IS NOT NULL AND sa.key_account <> ''";
194 $sql .= " ORDER BY sa.site_account DESC, sa.rowid DESC"; // To get the entry with a site_account defined in priority
195
196 dol_syslog(get_class($this)."::customerStripe search stripe customer id for thirdparty id=".$object->id, LOG_DEBUG);
197 $resql = $this->db->query($sql);
198 if ($resql) {
199 $num = $this->db->num_rows($resql);
200 if ($num) {
201 $obj = $this->db->fetch_object($resql);
202 $tiers = $obj->key_account;
203
204 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']);
205
206 try {
207 if (empty($key)) { // If the Stripe connect account not set, we use common API usage
208 //$customer = \Stripe\Customer::retrieve("$tiers");
209 $customer = \Stripe\Customer::retrieve(array('id' => "$tiers", 'expand[]' => 'sources'));
210 } else {
211 //$customer = \Stripe\Customer::retrieve("$tiers", array("stripe_account" => $key));
212 $customer = \Stripe\Customer::retrieve(array('id' => "$tiers", 'expand[]' => 'sources'), array("stripe_account" => $key));
213 }
214 } catch (Exception $e) {
215 // For example, 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.'
216 $this->error = $e->getMessage();
217 }
218 } elseif ($createifnotlinkedtostripe) {
219 $ipaddress = getUserRemoteIP();
220
221 $dataforcustomer = array(
222 "email" => $object->email,
223 "description" => $object->name,
224 "metadata" => array('dol_id' => $object->id, 'dol_version' => DOL_VERSION, 'dol_entity' => $conf->entity, 'ipaddress' => $ipaddress)
225 );
226
227 $vatcleaned = $object->tva_intra ? $object->tva_intra : null;
228
229 /*
230 $taxinfo = array('type'=>'vat');
231 if ($vatcleaned)
232 {
233 $taxinfo["tax_id"] = $vatcleaned;
234 }
235 // We force data to "null" if not defined as expected by Stripe
236 if (empty($vatcleaned)) $taxinfo=null;
237 $dataforcustomer["tax_info"] = $taxinfo;
238 */
239
240 //$a = \Stripe\Stripe::getApiKey();
241 //var_dump($a);var_dump($key);exit;
242 try {
243 // Force to use the correct API key
244 global $stripearrayofkeysbyenv;
245 \Stripe\Stripe::setApiKey($stripearrayofkeysbyenv[$status]['secret_key']);
246
247 if (empty($key)) { // If the Stripe connect account not set, we use common API usage
248 $customer = \Stripe\Customer::create($dataforcustomer);
249 } else {
250 $customer = \Stripe\Customer::create($dataforcustomer, array("stripe_account" => $key));
251 }
252
253 // Create the VAT record in Stripe
254 if (getDolGlobalString('STRIPE_SAVE_TAX_IDS')) { // We setup to save Tax info on Stripe side. Warning: This may result in error when saving customer
255 if (!empty($vatcleaned)) {
256 $isineec = isInEEC($object);
257 if ($object->country_code && $isineec) {
258 //$taxids = $customer->allTaxIds($customer);
259 $customer->createTaxId($customer->id, array('type' => 'eu_vat', 'value' => $vatcleaned));
260 }
261 }
262 }
263
264 // Create customer in Dolibarr
265 $sql = "INSERT INTO ".MAIN_DB_PREFIX."societe_account (fk_soc, login, key_account, site, site_account, status, entity, date_creation, fk_user_creat)";
266 $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).")";
267 $resql = $this->db->query($sql);
268 if (!$resql) {
269 $this->error = $this->db->lasterror();
270 }
271 } catch (Exception $e) {
272 $this->error = $e->getMessage();
273 }
274 }
275 } else {
276 dol_print_error($this->db);
277 }
278
279 return $customer;
280 }
281
290 public function getPaymentMethodStripe($paymentmethod, $key = '', $status = 0)
291 {
292 $stripepaymentmethod = null;
293
294 try {
295 // Force to use the correct API key
296 global $stripearrayofkeysbyenv;
297 \Stripe\Stripe::setApiKey($stripearrayofkeysbyenv[$status]['secret_key']);
298 if (empty($key)) { // If the Stripe connect account not set, we use common API usage
299 $stripepaymentmethod = \Stripe\PaymentMethod::retrieve((string) $paymentmethod->id);
300 } else {
301 $stripepaymentmethod = \Stripe\PaymentMethod::retrieve((string) $paymentmethod->id, array("stripe_account" => $key));
302 }
303 } catch (Exception $e) {
304 $this->error = $e->getMessage();
305 }
306
307 return $stripepaymentmethod;
308 }
309
318 public function getSelectedReader($reader, $key = '', $status = 0)
319 {
320 $selectedreader = null;
321
322 try {
323 // Force to use the correct API key
324 global $stripearrayofkeysbyenv;
325 \Stripe\Stripe::setApiKey($stripearrayofkeysbyenv[$status]['secret_key']);
326 if (empty($key)) { // If the Stripe connect account not set, we use common API usage
327 $selectedreader = \Stripe\Terminal\Reader::retrieve((string) $reader);
328 } else {
329 $stripepaymentmethod = \Stripe\Terminal\Reader::retrieve((string) $reader, array("stripe_account" => $key));
330 }
331 } catch (Exception $e) {
332 $this->error = $e->getMessage();
333 }
334
335 return $selectedreader;
336 }
337
338
347 public function convertAmount($amount, $currency_code, $direction = 0)
348 {
349 $arrayzerounitcurrency = array('BIF', 'CLP', 'DJF', 'GNF', 'JPY', 'KMF', 'KRW', 'MGA', 'PYG', 'RWF', 'VND', 'VUV', 'XAF', 'XOF', 'XPF');
350 if (!in_array($currency_code, $arrayzerounitcurrency)) {
351 if (empty($direction)) {
352 $newamount = (int) round($amount * 100); // If $amount is 79.99, doing 79.99 * 100 returns float 7998.999999999999, and "int" do a truncation into 7998 so we must first use round to get nearest integer value
353 } else {
354 $newamount = (float) ($amount / 100);
355 }
356 } else {
357 $newamount = $amount;
358 }
359
360 return $newamount;
361 }
362
363
390 public function getPaymentIntent($amount, $currency_code, $tag, $description = '', $object = null, $customer = null, $key = null, $servicestatus = 0, $usethirdpartyemailforreceiptemail = 0, $mode = 'automatic', $confirmnow = false, $payment_method = null, $off_session = 0, $noidempotency_key = 1, $did = 0)
391 {
392 global $conf, $user;
393
394 dol_syslog(get_class($this)."::getPaymentIntent description=".$description, LOG_INFO, 1);
395
396 $error = 0;
397
398 if (empty($servicestatus)) {
399 $service = 'StripeTest';
400 } else {
401 $service = 'StripeLive';
402 }
403
404 $stripeamount = $this->convertAmount($amount, $currency_code, 0);
405
406 $fee = 0;
407 if (getDolGlobalString("STRIPE_APPLICATION_FEE_PERCENT")) {
408 $fee = $amount * ((float) getDolGlobalString("STRIPE_APPLICATION_FEE_PERCENT", '0') / 100) + (float) getDolGlobalString("STRIPE_APPLICATION_FEE", '0');
409 }
410 if ($fee >= (float) getDolGlobalString("STRIPE_APPLICATION_FEE_MAXIMAL", '0') && (float) getDolGlobalString("STRIPE_APPLICATION_FEE_MAXIMAL", '0') > (float) getDolGlobalString("STRIPE_APPLICATION_FEE_MINIMAL", '0')) {
411 $fee = (float) getDolGlobalString("STRIPE_APPLICATION_FEE_MAXIMAL", '0');
412 } elseif ($fee < (float) getDolGlobalString("STRIPE_APPLICATION_FEE_MINIMAL", '0')) {
413 $fee = (float) getDolGlobalString("STRIPE_APPLICATION_FEE_MINIMAL", '0');
414 }
415 $stripefee = round($this->convertAmount($fee, $currency_code));
416
417 $paymentintent = null;
418
419 if (is_object($object) && getDolGlobalInt('STRIPE_REUSE_EXISTING_INTENT_IF_FOUND') && !getDolGlobalInt('STRIPE_CARD_PRESENT')) {
420 // Warning. If a payment was tried and failed, a payment intent was created.
421 // 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.
422 // 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
423 // automatically return the existing payment intent if idempotency is provided when we try to create the new one.
424 // 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)
425
426 // Try to retrieve the last paymentintent for invoice, but if it fails, never mind.
427 $sql = "SELECT pi.ext_payment_id, pi.entity, pi.fk_facture, pi.sourcetype, pi.ext_payment_site";
428 $sql .= " FROM ".MAIN_DB_PREFIX."prelevement_demande as pi";
429 $sql .= " WHERE pi.fk_facture = ".((int) $object->id);
430 $sql .= " AND pi.sourcetype = '".$this->db->escape($object->element)."'";
431 $sql .= " AND pi.entity IN (".getEntity('societe').")";
432 $sql .= " AND pi.ext_payment_site = '".$this->db->escape($service)."'";
433 $sql .= " ORDER BY rowid DESC";
434
435 dol_syslog(get_class($this)."::getPaymentIntent search stripe payment intent for object id = ".$object->id, LOG_DEBUG);
436
437 $resql = $this->db->query($sql);
438 if ($resql) {
439 $num = $this->db->num_rows($resql);
440 if ($num) {
441 $obj = $this->db->fetch_object($resql);
442
443 $ext_payment_intent = $obj->ext_payment_id;
444 $ext_payment_intent_array = preg_split('/[:@]/', $ext_payment_intent);
445
446 $intent = $ext_payment_intent_array[0];
447 $customerindb = (isset($ext_payment_intent_array[1]) ? $ext_payment_intent_array[1] : '');
448 $pkeyindb = (isset($ext_payment_intent_array[2]) ? $ext_payment_intent_array[2] : '');
449 // TODO Test that $pkeyindb and $customerindb match
450
451 dol_syslog(get_class($this)."::getPaymentIntent found existing payment intent record with intent=".$intent);
452
453 // Force to use the correct API key
454 global $stripearrayofkeysbyenv;
455 \Stripe\Stripe::setApiKey($stripearrayofkeysbyenv[$servicestatus]['secret_key']);
456
457 try {
458 if (empty($key)) { // If the Stripe connect account not set, we use common API usage
459 $paymentintent = \Stripe\PaymentIntent::retrieve($intent);
460 } else {
461 $paymentintent = \Stripe\PaymentIntent::retrieve($intent, array("stripe_account" => $key));
462 }
463 } catch (Exception $e) {
464 $error++;
465 $this->error = $e->getMessage();
466 }
467 }
468 }
469 }
470
471 if (empty($paymentintent)) {
472 // Try to create intent. See https://stripe.com/docs/api/payment_intents/create
473 $ipaddress = getUserRemoteIP();
474 $metadata = array('dol_version' => DOL_VERSION, 'dol_entity' => $conf->entity, 'ipaddress' => $ipaddress, 'dol_noidempotency' => (int) $noidempotency_key);
475 if (is_object($object)) {
476 $metadata['dol_type'] = $object->element;
477 $metadata['dol_id'] = $object->id;
478 if (is_object($object->thirdparty) && $object->thirdparty->id > 0) {
479 $metadata['dol_thirdparty_id'] = $object->thirdparty->id;
480 }
481 }
482
483 $stripemode = $mode;
484
485 // list of payment method types
486 $paymentmethodtypes = array("card");
487 $descriptor = dol_trunc($tag, 10, 'right', 'UTF-8', 1);
488 if (getDolGlobalInt('STRIPE_SEPA_DIRECT_DEBIT')) {
489 $paymentmethodtypes[] = "sepa_debit"; //&& ($object->thirdparty->isInEEC())
490 //$descriptor = preg_replace('/ref=[^:=]+/', '', $descriptor); // Clean ref
491 }
492 if (getDolGlobalInt('STRIPE_KLARNA')) {
493 $paymentmethodtypes[] = "klarna";
494 }
495 if (getDolGlobalInt('STRIPE_BANCONTACT')) {
496 $paymentmethodtypes[] = "bancontact";
497 }
498 if (getDolGlobalInt('STRIPE_IDEAL')) {
499 $paymentmethodtypes[] = "ideal";
500 }
501 if (getDolGlobalInt('STRIPE_GIROPAY')) {
502 $paymentmethodtypes[] = "giropay";
503 }
504 if (getDolGlobalInt('STRIPE_SOFORT')) {
505 $paymentmethodtypes[] = "sofort";
506 }
507 if ($mode == 'terminal') {
508 if (getDolGlobalInt('STRIPE_CARD_PRESENT')) {
509 $paymentmethodtypes = array("card_present");
510 }
511 $stripemode = 'manual';
512 }
513
515
516 $descriptioninpaymentintent = $description;
517
518 $dataforintent = array(
519 "confirm" => $confirmnow, // try to confirm immediately after create (if conditions are ok)
520 "confirmation_method" => $stripemode,
521 "amount" => $stripeamount,
522 "currency" => $currency_code,
523 "payment_method_types" => $paymentmethodtypes, // When payment_method_types is set, return_url is not required but payment mode can't be managed from dashboard
524 /*
525 'return_url' => $dolibarr_main_url_root.'/public/payment/paymentok.php',
526 'automatic_payment_methods' => array(
527 'enabled' => true,
528 'allow_redirects' => 'never',
529 ),
530 */
531 "description" => $descriptioninpaymentintent,
532 //"save_payment_method" => true,
533 "setup_future_usage" => "on_session",
534 "metadata" => $metadata
535 );
536 if ($descriptor) {
537 $dataforintent["statement_descriptor_suffix"] = $descriptor; // For card payment, 22 chars that appears on bank receipt (prefix into stripe setup + this suffix)
538 $dataforintent["statement_descriptor"] = $descriptor; // For SEPA, it will take only statement_descriptor, not statement_descriptor_suffix
539 }
540 if (!is_null($customer)) {
541 $dataforintent["customer"] = $customer;
542 }
543 // payment_method =
544 // payment_method_types = array('card')
545 //var_dump($dataforintent);
546 if ($off_session) {
547 unset($dataforintent['setup_future_usage']);
548 // We can't use both "setup_future_usage" = "off_session" and "off_session" = true.
549 // Because $off_session parameter is dedicated to create paymentintent off_line (and not future payment), we need to use "off_session" = true.
550 //$dataforintent["setup_future_usage"] = "off_session";
551 $dataforintent["off_session"] = true;
552 }
553 if (getDolGlobalInt('STRIPE_GIROPAY')) {
554 unset($dataforintent['setup_future_usage']);
555 }
556 if (getDolGlobalInt('STRIPE_KLARNA')) {
557 unset($dataforintent['setup_future_usage']);
558 }
559 if (getDolGlobalInt('STRIPE_CARD_PRESENT') && $mode == 'terminal') {
560 unset($dataforintent['setup_future_usage']);
561 $dataforintent["capture_method"] = "manual";
562 $dataforintent["confirmation_method"] = "manual";
563 }
564 if (!is_null($payment_method)) {
565 $dataforintent["payment_method"] = $payment_method;
566 $description .= ' - '.$payment_method;
567 }
568
569 if ($conf->entity != getDolGlobalInt('STRIPECONNECT_PRINCIPAL') && $stripefee > 0) {
570 $dataforintent["application_fee_amount"] = $stripefee;
571 }
572 if ($usethirdpartyemailforreceiptemail && is_object($object) && $object->thirdparty->email) {
573 $dataforintent["receipt_email"] = $object->thirdparty->email;
574 }
575
576 try {
577 // Force to use the correct API key
578 global $stripearrayofkeysbyenv;
579 \Stripe\Stripe::setApiKey($stripearrayofkeysbyenv[$servicestatus]['secret_key']);
580
581 $arrayofoptions = array();
582 if (empty($noidempotency_key)) {
583 $arrayofoptions["idempotency_key"] = $descriptioninpaymentintent;
584 }
585 // 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.
586 if (!empty($key)) { // If the Stripe connect account not set, we use common API usage
587 $arrayofoptions["stripe_account"] = $key;
588 }
589
590 dol_syslog(get_class($this)."::getPaymentIntent ".$stripearrayofkeysbyenv[$servicestatus]['publishable_key'], LOG_DEBUG);
591 dol_syslog(get_class($this)."::getPaymentIntent dataforintent to create paymentintent = ".var_export($dataforintent, true));
592
593 $paymentintent = \Stripe\PaymentIntent::create($dataforintent, $arrayofoptions);
594
595 if ($paymentintent instanceof \Stripe\PaymentIntent) {
596 dol_syslog(get_class($this)."::getPaymentIntent paymentintent is a defined object");
597
598 // Store the payment intent
599 if (is_object($object)) {
600 $paymentintentalreadyexists = 0;
601
602 // Get $customerid and $pkey
603 $customerid = $paymentintent->customer;
604 $pkey = '';
605 if (isset($stripearrayofkeysbyenv[$servicestatus]['publishable_key'])) {
606 $pkey = $stripearrayofkeysbyenv[$servicestatus]['publishable_key'];
607 }
608
609 $LONGTRANSACTIONID = $paymentintent->id.':'.$customerid.'@'.$pkey;
610
611
612 if ($did > 0) {
613 // If a payment request line provided, we do not need to recreate one, we just update it
614 dol_syslog(get_class($this)."::getPaymentIntent search if payment intent already in prelevement_demande", LOG_DEBUG);
615
616 $sql = "UPDATE ".MAIN_DB_PREFIX."prelevement_demande SET";
617 $sql .= " ext_payment_site = '".$this->db->escape($service)."',";
618 $sql .= " ext_payment_id = '".$this->db->escape($paymentintent->id)."'"; // TODO Save the long transaction id
619 $sql .= " WHERE rowid = ".((int) $did);
620
621 $resql = $this->db->query($sql);
622 if ($resql) {
623 $paymentintentalreadyexists++;
624 } else {
625 $error++;
626 dol_print_error($this->db);
627 }
628 } else {
629 // Check that payment intent $paymentintent->id is not already recorded.
630 dol_syslog(get_class($this)."::getPaymentIntent search if payment intent already in prelevement_demande", LOG_DEBUG);
631
632 $sql = "SELECT pi.rowid";
633 $sql .= " FROM ".MAIN_DB_PREFIX."prelevement_demande as pi";
634 $sql .= " WHERE pi.entity IN (".getEntity('societe').")";
635 $sql .= " AND pi.ext_payment_site = '".$this->db->escape($service)."'";
636 $sql .= " AND (pi.ext_payment_id = '".$this->db->escape($paymentintent->id)."' OR pi.ext_payment_id = '".$this->db->escape($LONGTRANSACTIONID)."')";
637
638 $resql = $this->db->query($sql);
639 if ($resql) {
640 $num = $this->db->num_rows($resql);
641 if ($num) {
642 $obj = $this->db->fetch_object($resql);
643 if ($obj) {
644 $paymentintentalreadyexists++;
645 }
646 }
647 } else {
648 $error++;
649 dol_print_error($this->db);
650 }
651 }
652
653 // If not, we create it.
654 if (!$error && !$paymentintentalreadyexists) {
655 $now = dol_now();
656 $sql = "INSERT INTO ".MAIN_DB_PREFIX."prelevement_demande (date_demande, fk_user_demande, ext_payment_id, fk_facture, sourcetype, entity, ext_payment_site, amount)";
657 // TODO Save the long transaction id in ext_payment_id
658 $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).")";
659 $resql = $this->db->query($sql);
660 if (!$resql) {
661 $error++;
662 $this->error = $this->db->lasterror();
663 dol_syslog(get_class($this)."::PaymentIntent failed to insert paymentintent with id=".$paymentintent->id." into database.", LOG_ERR);
664 }
665 }
666 } else {
667 $_SESSION["stripe_payment_intent"] = $paymentintent;
668 }
669 } else {
670 dol_syslog(get_class($this)."::getPaymentIntent create paymentintent did not returned a Stripe\PaymentIntent object", LOG_ERR);
671 }
672 } catch (Stripe\Exception\CardException $e) {
673 $error++;
674 $this->error = $e->getMessage();
675 $this->code = $e->getStripeCode();
676 $this->declinecode = $e->getDeclineCode();
677 } catch (Exception $e) {
678 //var_dump($dataforintent);
679 //var_dump($description);
680 //var_dump($key);
681 //var_dump($paymentintent);
682 //var_dump($e->getMessage());
683 //var_dump($e);
684 $error++;
685 $this->error = $e->getMessage();
686 $this->code = '';
687 $this->declinecode = '';
688 }
689 }
690
691 dol_syslog(get_class($this)."::getPaymentIntent return error=".$error." this->error=".$this->error, LOG_INFO, -1);
692
693 if (!$error) {
694 return $paymentintent;
695 } else {
696 return null;
697 }
698 }
699
718 public function getSetupIntent($description, $object, $customer, $key, $servicestatus, $usethirdpartyemailforreceiptemail = 0, $confirmnow = false)
719 {
720 global $conf;
721
722 $noidempotency_key = 1;
723
724 dol_syslog("getSetupIntent description=".$description.' confirmnow='.json_encode($confirmnow), LOG_INFO, 1);
725
726 $error = 0;
727
728 if (empty($servicestatus)) {
729 $service = 'StripeTest';
730 } else {
731 $service = 'StripeLive';
732 }
733
734 $setupintent = null;
735
736 if (empty($setupintent)) { // @phan-suppress-current-line PhanPluginConstantVariableNull
737 $ipaddress = getUserRemoteIP();
738 $metadata = array('dol_version' => DOL_VERSION, 'dol_entity' => $conf->entity, 'ipaddress' => $ipaddress, 'dol_noidempotency' => (int) $noidempotency_key);
739 if (is_object($object)) {
740 $metadata['dol_type'] = $object->element;
741 $metadata['dol_id'] = $object->id;
742 if (is_object($object->thirdparty) && $object->thirdparty->id > 0) {
743 $metadata['dol_thirdparty_id'] = $object->thirdparty->id;
744 }
745 }
746
747 // list of payment method types
748 $paymentmethodtypes = array("card");
749 if (getDolGlobalString('STRIPE_SEPA_DIRECT_DEBIT')) {
750 $paymentmethodtypes[] = "sepa_debit"; //&& ($object->thirdparty->isInEEC())
751 }
752 if (getDolGlobalString('STRIPE_BANCONTACT')) {
753 $paymentmethodtypes[] = "bancontact";
754 }
755 if (getDolGlobalString('STRIPE_IDEAL')) {
756 $paymentmethodtypes[] = "ideal";
757 }
758 // Giropay not possible for setup intent
759 if (getDolGlobalString('STRIPE_SOFORT')) {
760 $paymentmethodtypes[] = "sofort";
761 }
762
764
765 $descriptioninsetupintent = $description;
766
767 $dataforintent = array(
768 "confirm" => $confirmnow, // Do not confirm immediately during creation of intent
769 "payment_method_types" => $paymentmethodtypes, // When payment_method_types is set, return_url is not required but payment mode can't be managed from dashboard
770 /*
771 'return_url' => $dolibarr_main_url_root.'/public/payment/paymentok.php',
772 'automatic_payment_methods' => array(
773 'enabled' => true,
774 'allow_redirects' => 'never',
775 ),
776 */
777 "usage" => "off_session",
778 "metadata" => $metadata
779 );
780 if (!is_null($customer)) {
781 $dataforintent["customer"] = $customer;
782 }
783 if (!is_null($description)) {
784 $dataforintent["description"] = $descriptioninsetupintent;
785 }
786 // payment_method =
787 // payment_method_types = array('card')
788 //var_dump($dataforintent);
789
790 if ($usethirdpartyemailforreceiptemail && is_object($object) && $object->thirdparty->email) {
791 $dataforintent["receipt_email"] = $object->thirdparty->email;
792 }
793
794 try {
795 // Force to use the correct API key
796 global $stripearrayofkeysbyenv;
797 \Stripe\Stripe::setApiKey($stripearrayofkeysbyenv[$servicestatus]['secret_key']);
798
799 dol_syslog(get_class($this)."::getSetupIntent ".$stripearrayofkeysbyenv[$servicestatus]['publishable_key'], LOG_DEBUG);
800 dol_syslog(get_class($this)."::getSetupIntent dataforintent to create setupintent = ".var_export($dataforintent, true));
801
802 // Note: If all data for payment intent are same than a previous one, even if we use 'create', Stripe will return ID of the old existing payment intent.
803 if (empty($key)) { // If the Stripe connect account not set, we use common API usage
804 //$setupintent = \Stripe\SetupIntent::create($dataforintent, array("idempotency_key" => "$description"));
805 $setupintent = \Stripe\SetupIntent::create($dataforintent, array());
806 } else {
807 //$setupintent = \Stripe\SetupIntent::create($dataforintent, array("idempotency_key" => "$description", "stripe_account" => $key));
808 $setupintent = \Stripe\SetupIntent::create($dataforintent, array("stripe_account" => $key));
809 }
810 //var_dump($setupintent->id);
811
812 // Store the setup intent
813 /*if (is_object($object))
814 {
815 $setupintentalreadyexists = 0;
816 // Check that payment intent $setupintent->id is not already recorded.
817 $sql = "SELECT pi.rowid";
818 $sql.= " FROM " . MAIN_DB_PREFIX . "prelevement_demande as pi";
819 $sql.= " WHERE pi.entity IN (".getEntity('societe').")";
820 $sql.= " AND pi.ext_payment_site = '" . $this->db->escape($service) . "'";
821 $sql.= " AND pi.ext_payment_id = '".$this->db->escape($setupintent->id)."'";
822
823 dol_syslog(get_class($this) . "::getPaymentIntent search if payment intent already in prelevement_demande", LOG_DEBUG);
824 $resql = $this->db->query($sql);
825 if ($resql) {
826 $num = $this->db->num_rows($resql);
827 if ($num)
828 {
829 $obj = $this->db->fetch_object($resql);
830 if ($obj) $setupintentalreadyexists++;
831 }
832 }
833 else dol_print_error($this->db);
834
835 // If not, we create it.
836 if (! $setupintentalreadyexists)
837 {
838 $now=dol_now();
839 $sql = "INSERT INTO " . MAIN_DB_PREFIX . "prelevement_demande (date_demande, fk_user_demande, ext_payment_id, fk_facture, sourcetype, entity, ext_payment_site)";
840 $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).")";
841 $resql = $this->db->query($sql);
842 if (! $resql)
843 {
844 $error++;
845 $this->error = $this->db->lasterror();
846 dol_syslog(get_class($this) . "::PaymentIntent failed to insert paymentintent with id=".$setupintent->id." into database.");
847 }
848 }
849 }
850 else
851 {
852 $_SESSION["stripe_setup_intent"] = $setupintent;
853 }*/
854 } catch (Exception $e) {
855 //var_dump($dataforintent);
856 //var_dump($description);
857 //var_dump($key);
858 //var_dump($setupintent);
859 //var_dump($e->getMessage());
860 $error++;
861 $this->error = $e->getMessage();
862 }
863 }
864
865 if (!$error) {
866 dol_syslog("getSetupIntent ".(is_object($setupintent) ? $setupintent->id : ''), LOG_INFO, -1);
867 return $setupintent;
868 } else {
869 dol_syslog("getSetupIntent return error=".$error, LOG_INFO, -1);
870 return null;
871 }
872 }
873
874
885 public function cardStripe($cu, CompanyPaymentMode $object, $stripeacc = '', $status = 0, $createifnotlinkedtostripe = 0)
886 {
887 global $conf, $langs;
888
889 $card = null;
890
891 $sql = "SELECT sa.stripe_card_ref, sa.proprio as owner_name, sa.exp_date_month, sa.exp_date_year, sa.number, sa.cvn"; // stripe_card_ref is card_....
892 $sql .= " FROM ".MAIN_DB_PREFIX."societe_rib as sa";
893 $sql .= " WHERE sa.rowid = ".((int) $object->id); // We get record from ID, no need for filter on entity
894 $sql .= " AND sa.type = 'card'";
895
896 dol_syslog(get_class($this)."::cardStripe search stripe card id for paymentmode id=".$object->id.", stripeacc=".$stripeacc.", status=".$status.", createifnotlinkedtostripe=".$createifnotlinkedtostripe, LOG_DEBUG);
897 $resql = $this->db->query($sql);
898 if ($resql) {
899 $num = $this->db->num_rows($resql);
900 if ($num) {
901 $obj = $this->db->fetch_object($resql);
902 $cardref = $obj->stripe_card_ref;
903 dol_syslog(get_class($this)."::cardStripe cardref=".$cardref);
904 if ($cardref) {
905 try {
906 if (empty($stripeacc)) { // If the Stripe connect account not set, we use common API usage
907 if (!preg_match('/^pm_/', $cardref) && !empty($cu->sources)) {
908 $card = $cu->sources->retrieve($cardref);
909 } else {
910 $card = \Stripe\PaymentMethod::retrieve($cardref);
911 }
912 } else {
913 if (!preg_match('/^pm_/', $cardref) && !empty($cu->sources)) {
914 //$card = $cu->sources->retrieve($cardref, array("stripe_account" => $stripeacc)); // this API fails when array stripe_account is provided
915 $card = $cu->sources->retrieve($cardref);
916 } else {
917 //$card = \Stripe\PaymentMethod::retrieve($cardref, array("stripe_account" => $stripeacc)); // Don't know if this works
918 $card = \Stripe\PaymentMethod::retrieve($cardref);
919 }
920 }
921 } catch (Exception $e) {
922 $this->error = $e->getMessage();
923 dol_syslog($this->error, LOG_WARNING);
924 }
925 } elseif ($createifnotlinkedtostripe) {
926 // Deprecated with new Stripe API and SCA. We should not use anymore this part of code now.
927 $exp_date_month = $obj->exp_date_month;
928 $exp_date_year = $obj->exp_date_year;
929 $number = $obj->number;
930 $cvc = $obj->cvn; // cvn in database, cvc for stripe
931 $cardholdername = $obj->owner_name;
932
933 $ipaddress = getUserRemoteIP();
934
935 $dataforcard = array(
936 "source" => array(
937 'object' => 'card',
938 'exp_month' => $exp_date_month,
939 'exp_year' => $exp_date_year,
940 'number' => $number,
941 'cvc' => $cvc,
942 'name' => $cardholdername
943 ),
944 "metadata" => array(
945 'dol_type' => $object->element,
946 'dol_id' => $object->id,
947 'dol_version' => DOL_VERSION,
948 'dol_entity' => $conf->entity,
949 'ipaddress' => $ipaddress
950 )
951 );
952
953 //$a = \Stripe\Stripe::getApiKey();
954 //var_dump($a);
955 //var_dump($stripeacc);exit;
956 try {
957 if (empty($stripeacc)) { // If the Stripe connect account not set, we use common API usage
958 if (!getDolGlobalString('STRIPE_USE_INTENT_WITH_AUTOMATIC_CONFIRMATION')) {
959 dol_syslog("Try to create card with dataforcard = ".json_encode($dataforcard));
960 $card = $cu->sources->create($dataforcard);
961 if (!$card) {
962 $this->error = 'Creation of card on Stripe has failed';
963 }
964 } else {
965 $connect = '';
966 if (!empty($stripeacc)) {
967 $connect = $stripeacc.'/';
968 }
969 $url = 'https://dashboard.stripe.com/'.$connect.'test/customers/'.$cu->id;
970 if ($status) {
971 $url = 'https://dashboard.stripe.com/'.$connect.'customers/'.$cu->id;
972 }
973 $urtoswitchonstripe = '<a href="'.$url.'" target="_stripe">'.img_picto($langs->trans('ShowInStripe'), 'globe').'</a>';
974
975 //dol_syslog("Error: This case is not supported", LOG_ERR);
976 $this->error = str_replace('{s1}', $urtoswitchonstripe, $langs->trans('CreationOfPaymentModeMustBeDoneFromStripeInterface', '{s1}'));
977 }
978 } else {
979 if (!getDolGlobalString('STRIPE_USE_INTENT_WITH_AUTOMATIC_CONFIRMATION')) {
980 dol_syslog("Try to create card with dataforcard = ".json_encode($dataforcard));
981 $card = $cu->sources->create($dataforcard, array("stripe_account" => $stripeacc));
982 if (!$card) {
983 $this->error = 'Creation of card on Stripe has failed';
984 }
985 } else {
986 $connect = '';
987 if (!empty($stripeacc)) {
988 $connect = $stripeacc.'/';
989 }
990 $url = 'https://dashboard.stripe.com/'.$connect.'test/customers/'.$cu->id;
991 if ($status) {
992 $url = 'https://dashboard.stripe.com/'.$connect.'customers/'.$cu->id;
993 }
994 $urtoswitchonstripe = '<a href="'.$url.'" target="_stripe">'.img_picto($langs->trans('ShowInStripe'), 'globe').'</a>';
995
996 //dol_syslog("Error: This case is not supported", LOG_ERR);
997 $this->error = str_replace('{s1}', $urtoswitchonstripe, $langs->trans('CreationOfPaymentModeMustBeDoneFromStripeInterface', '{s1}'));
998 }
999 }
1000
1001 if ($card) {
1002 $sql = "UPDATE ".MAIN_DB_PREFIX."societe_rib";
1003 $sql .= " SET stripe_card_ref = '".$this->db->escape($card->id)."', card_type = '".$this->db->escape($card->brand)."',";
1004 $sql .= " country_code = '".$this->db->escape($card->country)."',";
1005 $sql .= " approved = ".($card->cvc_check == 'pass' ? 1 : 0);
1006 $sql .= " WHERE rowid = ".((int) $object->id);
1007 $sql .= " AND type = 'card'";
1008 $resql = $this->db->query($sql);
1009 if (!$resql) {
1010 $this->error = $this->db->lasterror();
1011 }
1012 }
1013 } catch (Exception $e) {
1014 $this->error = $e->getMessage();
1015 dol_syslog($this->error, LOG_WARNING);
1016 }
1017 }
1018 }
1019 } else {
1020 dol_print_error($this->db);
1021 }
1022
1023 return $card;
1024 }
1025
1026
1037 public function sepaStripe($cu, CompanyPaymentMode $object, $stripeacc = '', $status = 0, $createifnotlinkedtostripe = 0)
1038 {
1039 global $conf;
1040 $sepa = null;
1041
1042 $sql = "SELECT sa.stripe_card_ref, sa.proprio, sa.iban_prefix as iban, sa.rum"; // stripe_card_ref is 'src_...' for Stripe SEPA
1043 $sql .= " FROM ".MAIN_DB_PREFIX."societe_rib as sa";
1044 $sql .= " WHERE sa.rowid = ".((int) $object->id); // We get record from ID, no need for filter on entity
1045 $sql .= " AND sa.type = 'ban'"; //type ban to get normal bank account of customer (prelevement)
1046
1047 $soc = new Societe($this->db);
1048 $soc->fetch($object->fk_soc);
1049
1050 dol_syslog(get_class($this)."::sepaStripe search stripe ban id for paymentmode id=".$object->id.", stripeacc=".$stripeacc.", status=".$status.", createifnotlinkedtostripe=".$createifnotlinkedtostripe, LOG_DEBUG);
1051 $resql = $this->db->query($sql);
1052 if ($resql) {
1053 $num = $this->db->num_rows($resql);
1054 if ($num) {
1055 $obj = $this->db->fetch_object($resql);
1056 $cardref = $obj->stripe_card_ref;
1057
1058 dol_syslog(get_class($this)."::sepaStripe paymentmode=".$cardref);
1059
1060 if ($cardref) {
1061 try {
1062 if (empty($stripeacc)) { // If the Stripe connect account not set, we use common API usage
1063 if (!preg_match('/^pm_/', $cardref) && !empty($cu->sources)) {
1064 $sepa = $cu->sources->retrieve($cardref);
1065 } else {
1066 $sepa = \Stripe\PaymentMethod::retrieve($cardref);
1067 }
1068 } else {
1069 if (!preg_match('/^pm_/', $cardref) && !empty($cu->sources)) {
1070 //$sepa = $cu->sources->retrieve($cardref, array("stripe_account" => $stripeacc)); // this API fails when array stripe_account is provided
1071 $sepa = $cu->sources->retrieve($cardref);
1072 } else {
1073 //$sepa = \Stripe\PaymentMethod::retrieve($cardref, array("stripe_account" => $stripeacc)); // Don't know if this works
1074 $sepa = \Stripe\PaymentMethod::retrieve($cardref);
1075 }
1076 }
1077 } catch (Exception $e) {
1078 $this->error = $e->getMessage();
1079 dol_syslog($this->error, LOG_WARNING);
1080 }
1081 } elseif ($createifnotlinkedtostripe) {
1082 $iban = dolDecrypt($obj->iban);
1083 $ipaddress = getUserRemoteIP();
1084 $metadata = array('dol_version' => DOL_VERSION, 'dol_entity' => $conf->entity, 'ipaddress' => $ipaddress);
1085 if (is_object($object)) {
1086 $metadata['dol_type'] = $object->element;
1087 $metadata['dol_id'] = $object->id;
1088 $metadata['dol_thirdparty_id'] = $soc->id;
1089 }
1090
1091 $description = 'SEPA for IBAN '.$iban;
1092
1093 $dataforcard = array(
1094 'type' => 'sepa_debit',
1095 "sepa_debit" => array('iban' => $iban),
1096 'billing_details' => array(
1097 'name' => $soc->name,
1098 'email' => !empty($soc->email) ? $soc->email : "",
1099 ),
1100 "metadata" => $metadata
1101 );
1102 // Complete owner name
1103 if (!empty($soc->town)) {
1104 $dataforcard['billing_details']['address']['city'] = $soc->town;
1105 }
1106 if (!empty($soc->country_code)) {
1107 $dataforcard['billing_details']['address']['country'] = $soc->country_code;
1108 }
1109 if (!empty($soc->address)) {
1110 $dataforcard['billing_details']['address']['line1'] = $soc->address;
1111 }
1112 if (!empty($soc->zip)) {
1113 $dataforcard['billing_details']['address']['postal_code'] = $soc->zip;
1114 }
1115 if (!empty($soc->state)) {
1116 $dataforcard['billing_details']['address']['state'] = $soc->state;
1117 }
1118
1119 //$a = \Stripe\Stripe::getApiKey();
1120 //var_dump($a);var_dump($stripeacc);exit;
1121 try {
1122 dol_syslog("Try to create sepa_debit");
1123
1124 $service = 'StripeTest';
1125 $servicestatus = 0;
1126 if (getDolGlobalString('STRIPE_LIVE')/* && !GETPOST('forcesandbox', 'alpha') */) {
1127 $service = 'StripeLive';
1128 $servicestatus = 1;
1129 }
1130 // Force to use the correct API key
1131 global $stripearrayofkeysbyenv;
1132 $stripeacc = $stripearrayofkeysbyenv[$servicestatus]['secret_key'];
1133
1134 dol_syslog("Try to create sepa_debit with data = ".json_encode($dataforcard));
1135
1136 $s = new \Stripe\StripeClient($stripeacc);
1137
1138 //var_dump($dataforcard);exit;
1139
1140 $sepa = $s->paymentMethods->create($dataforcard);
1141 if (!$sepa) {
1142 $this->error = 'Creation of payment method sepa_debit on Stripe has failed';
1143 dol_syslog($this->error, LOG_ERR);
1144 } else {
1145 // link customer and src
1146 //$cs = $this->getSetupIntent($description, $soc, $cu, '', $status);
1147 $dataforintent = array(0 => ['description' => $description, 'payment_method_types' => ['sepa_debit'], 'customer' => $cu->id, 'payment_method' => $sepa->id], 'metadata' => $metadata);
1148
1149 $cs = $s->setupIntents->create($dataforintent);
1150 //$cs = $s->setupIntents->update($cs->id, ['payment_method' => $sepa->id]);
1151 $cs = $s->setupIntents->confirm($cs->id, ['mandate_data' => ['customer_acceptance' => ['type' => 'offline']]]);
1152 // note: $cs->mandate contains ID of mandate on Stripe side
1153
1154 if (!$cs) {
1155 $this->error = 'Link SEPA <-> Customer failed';
1156 dol_syslog($this->error, LOG_ERR);
1157 } else {
1158 dol_syslog("Update the payment mode of the customer");
1159
1160 // print json_encode($sepa);
1161
1162 // Save the Stripe payment mode ID into the Dolibarr database
1163 $sql = "UPDATE ".MAIN_DB_PREFIX."societe_rib";
1164 $sql .= " SET stripe_card_ref = '".$this->db->escape($sepa->id)."',";
1165 $sql .= " card_type = 'sepa_debit',";
1166 $sql .= " stripe_account= '" . $this->db->escape($cu->id . "@" . $stripeacc) . "',";
1167 $sql .= " ext_payment_site = '".$this->db->escape($service)."'";
1168 if (!empty($cs->mandate)) {
1169 $mandateservice = new \Stripe\Mandate($stripeacc);
1170 $mandate = $mandateservice->retrieve($cs->mandate);
1171 if (is_object($mandate) && is_object($mandate->payment_method_details) && is_object($mandate->payment_method_details->sepa_debit)) {
1172 $refmandate = $mandate->payment_method_details->sepa_debit->reference;
1173 //$urlmandate = $mandate->payment_method_details->sepa_debit->url;
1174 $sql .= ", rum = '".$this->db->escape($refmandate)."'";
1175 }
1176 $sql .= ", comment = '".$this->db->escape($cs->mandate)."'";
1177 $sql .= ", date_rum = '".$this->db->idate(dol_now())."'";
1178 }
1179 $sql .= " WHERE rowid = ".((int) $object->id);
1180 $sql .= " AND type = 'ban'";
1181 $resql = $this->db->query($sql);
1182 if (!$resql) {
1183 $this->error = $this->db->lasterror();
1184 }
1185 }
1186 }
1187 } catch (Exception $e) {
1188 $sepa = null;
1189 $this->error = 'Stripe error: '.$e->getMessage().'. Check the BAN information.';
1190 dol_syslog($this->error, LOG_WARNING); // Error from Stripe, so a warning on Dolibarr
1191 }
1192 }
1193 }
1194 } else {
1195 dol_print_error($this->db);
1196 }
1197
1198 return $sepa;
1199 }
1200}
if(! $sortfield) if(! $sortorder) $object
Definition account.php:100
global $dolibarr_main_url_root
Parent class of all other business classes (invoices, contracts, proposals, orders,...
Class for CompanyPaymentMode.
Class for SocieteAccount.
Class to manage third parties objects (customers, suppliers, prospects...)
Stripe class @TODO No reason to extend CommonObject.
convertAmount($amount, $currency_code, $direction=0)
Convert an amount in Stripe format into an amount into standard amount.
getPaymentMethodStripe($paymentmethod, $key='', $status=0)
Get the Stripe payment method Object from its ID.
sepaStripe($cu, CompanyPaymentMode $object, $stripeacc='', $status=0, $createifnotlinkedtostripe=0)
Get the Stripe SEPA of a company payment mode (create it if it doesn't exists and $createifnotlinkedt...
customerStripe($object, $key='', $status=0, $createifnotlinkedtostripe=0)
Get the Stripe customer of a thirdparty (with option to create it in Stripe if not linked yet).
getStripeCustomerAccount($id, $status=0, $site_account='')
getStripeCustomerAccount
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 ...
__construct($db)
Constructor.
getPaymentIntent($amount, $currency_code, $tag, $description='', $object=null, $customer=null, $key=null, $servicestatus=0, $usethirdpartyemailforreceiptemail=0, $mode='automatic', $confirmnow=false, $payment_method=null, $off_session=0, $noidempotency_key=1, $did=0)
Get the Stripe payment intent.
getStripeAccount($mode='StripeTest', $fk_soc=0, $entity=-1)
Return main company OAuth Connect stripe account.
getSetupIntent($description, $object, $customer, $key, $servicestatus, $usethirdpartyemailforreceiptemail=0, $confirmnow=false)
Get the Stripe payment intent.
getSelectedReader($reader, $key='', $status=0)
Get the Stripe reader Object from its ID.
isInEEC($object)
Return if a country of an object is inside the EEC (European Economic Community)
dol_now($mode='gmt')
Return date for now.
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2, $allowothertags=array())
Show picto whatever it's its name (generic function)
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
getUserRemoteIP($trusted=0)
Return the real IP of remote user.
dol_print_error($db=null, $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
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.
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
dolDecrypt($chain, $key='')
Decode a string with a symmetric encryption.