Passed
Push — EXTRACT_CLASSES ( ae6b5c...83d77a )
by Rafael
60:14 queued 23:58
created

Stripe::sepaStripe()   F

Complexity

Conditions 28
Paths 8461

Size

Total Lines 158
Code Lines 104

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 28
eloc 104
nc 8461
nop 5
dl 0
loc 158
rs 0
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/* Copyright (C) 2018-2021  Thibault FOUCART            <[email protected]>
4
 * Copyright (C) 2024       Frédéric France             <[email protected]>
5
 * Copyright (C) 2024		MDW							<[email protected]>
6
 * Copyright (C) 2024       Rafael San José             <[email protected]>
7
 *
8
 * This program is free software; you can redistribute it and/or modify
9
 * it under the terms of the GNU General Public License as published by
10
 * the Free Software Foundation; either version 3 of the License, or
11
 * (at your option) any later version.
12
 *
13
 * This program is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 * GNU General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU General Public License
19
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
20
 */
21
22
namespace Dolibarr\Code\Stripe\Classes;
23
24
use Dolibarr\Core\Base\CommonObject;
25
26
// Put here all includes required by your class file
27
use Dolibarr\Code\Societe\Classes\Societe;
28
use Dolibarr\Code\Adherents\Classes\Adherent;
29
require_once constant('DOL_DOCUMENT_ROOT') . '/compta/facture/class/facture.class.php';
30
require_once constant('DOL_DOCUMENT_ROOT') . '/stripe/config.php'; // This set stripe global env
31
32
33
/**
34
 *  Stripe class
35
 *  @TODO No reason to extends CommonObject
36
 */
37
class Stripe extends CommonObject
38
{
39
    /**
40
     * @var int ID
41
     */
42
    public $rowid;
43
44
    /**
45
     * @var int Thirdparty ID
46
     */
47
    public $fk_soc;
48
49
    /**
50
     * @var int ID
51
     */
52
    public $fk_key;
53
54
    /**
55
     * @var int ID
56
     */
57
    public $id;
58
59
    /**
60
     * @var string
61
     */
62
    public $mode;
63
64
    /**
65
     * @var int Entity
66
     */
67
    public $entity;
68
69
    /**
70
     * @var string
71
     * @deprecated Was used by createPaymentStripe only that is deprecated
72
     */
73
    public $result;
74
75
    /**
76
     * @var string
77
     */
78
    public $type;
79
80
    /**
81
     * @var string
82
     */
83
    public $code;
84
85
    /**
86
     * @var string
87
     */
88
    public $declinecode;
89
90
    /**
91
     * @var string Message
92
     */
93
    public $message;
94
95
    /**
96
     *  Constructor
97
     *
98
     *  @param  DoliDB      $db         Database handler
0 ignored issues
show
Bug introduced by
The type Dolibarr\Code\Stripe\Classes\DoliDB was not found. Did you mean DoliDB? If so, make sure to prefix the type with \.
Loading history...
99
     */
100
    public function __construct($db)
101
    {
102
        $this->db = $db;
103
    }
104
105
106
    /**
107
     * Return main company OAuth Connect stripe account
108
     *
109
     * @param   string  $mode       'StripeTest' or 'StripeLive'
110
     * @param   int     $fk_soc     Id of thirdparty
111
     * @param   int     $entity     Id of entity (-1 = current environment)
112
     * @return  string              Stripe account 'acc_....' or '' if no OAuth token found
113
     */
114
    public function getStripeAccount($mode = 'StripeTest', $fk_soc = 0, $entity = -1)
115
    {
116
        global $conf;
117
118
        $key = '';
119
        if ($entity < 0) {
120
            $entity = $conf->entity;
121
        }
122
123
        $sql = "SELECT tokenstring";
124
        $sql .= " FROM " . MAIN_DB_PREFIX . "oauth_token";
125
        $sql .= " WHERE service = '" . $this->db->escape($mode) . "'";
126
        $sql .= " AND entity = " . ((int) $entity);
127
        if ($fk_soc > 0) {
128
            $sql .= " AND fk_soc = " . ((int) $fk_soc);
129
        } else {
130
            $sql .= " AND fk_soc IS NULL";
131
        }
132
        $sql .= " AND fk_user IS NULL AND fk_adherent IS NULL";
133
134
        dol_syslog(get_class($this) . "::getStripeAccount", LOG_DEBUG);
135
136
        $result = $this->db->query($sql);
137
        if ($result) {
138
            if ($this->db->num_rows($result)) {
139
                $obj = $this->db->fetch_object($result);
140
                $tokenstring = $obj->tokenstring;
141
142
                if ($tokenstring) {
143
                    $tmparray = json_decode($tokenstring);
144
                    $key = empty($tmparray->stripe_user_id) ? '' : $tmparray->stripe_user_id;
145
                }
146
            } else {
147
                $tokenstring = '';
148
            }
149
        } else {
150
            dol_print_error($this->db);
151
        }
152
153
        dol_syslog("No dedicated Stripe Connect account available for entity " . $conf->entity);
154
155
        return $key;
156
    }
157
158
    /**
159
     * getStripeCustomerAccount
160
     *
161
     * @param   int     $id             Id of third party
162
     * @param   int     $status         Status
163
     * @param   string  $site_account   Value to use to identify with account to use on site when site can offer several accounts. For example: 'pk_live_123456' when using Stripe service.
164
     * @return  string                  Stripe customer ref 'cu_xxxxxxxxxxxxx' or ''
165
     */
166
    public function getStripeCustomerAccount($id, $status = 0, $site_account = '')
167
    {
168
        include_once DOL_DOCUMENT_ROOT . '/societe/class/societeaccount.class.php';
169
        $societeaccount = new SocieteAccount($this->db);
170
        return $societeaccount->getCustomerAccount($id, 'stripe', $status, $site_account); // Get thirdparty cus_...
171
    }
172
173
174
    /**
175
     * Get the Stripe customer of a thirdparty (with option to create it in Stripe if not linked yet).
176
     * Search on site_account = 0 or = $stripearrayofkeysbyenv[$status]['publishable_key']
177
     *
178
     * @param   CommonObject    $object                         Object thirdparty to check, or create on stripe (create on stripe also update the stripe_account table for current entity).  Used for AdherentType and Societe.
179
     * @param   string  $key                            ''=Use common API. If not '', it is the Stripe connect account 'acc_....' to use Stripe connect
180
     * @param   int     $status                         Status (0=test, 1=live)
181
     * @param   int     $createifnotlinkedtostripe      1=Create the stripe customer and the link if the thirdparty is not yet linked to a stripe customer
182
     * @return  \Stripe\Customer|null                   Stripe Customer or null if not found
183
     */
184
    public function customerStripe(CommonObject $object, $key = '', $status = 0, $createifnotlinkedtostripe = 0)
185
    {
186
        global $conf, $user;
187
188
        if (empty($object->id)) {
189
            dol_syslog("customerStripe is called with the parameter object that is not loaded");
190
            return null;
191
        }
192
193
        $customer = null;
194
195
        // Force to use the correct API key
196
        global $stripearrayofkeysbyenv;
197
        \Stripe\Stripe::setApiKey($stripearrayofkeysbyenv[$status]['secret_key']);
198
199
        $sql = "SELECT sa.key_account as key_account, sa.entity"; // key_account is cus_....
200
        $sql .= " FROM " . MAIN_DB_PREFIX . "societe_account as sa";
201
        $sql .= " WHERE sa.fk_soc = " . ((int) $object->id);
202
        $sql .= " AND sa.entity IN (" . getEntity('societe') . ")";
203
        $sql .= " AND sa.site = 'stripe' AND sa.status = " . ((int) $status);
204
        $sql .= " AND (sa.site_account IS NULL OR sa.site_account = '' OR sa.site_account = '" . $this->db->escape($stripearrayofkeysbyenv[$status]['publishable_key']) . "')";
205
        $sql .= " AND sa.key_account IS NOT NULL AND sa.key_account <> ''";
206
207
        dol_syslog(get_class($this) . "::customerStripe search stripe customer id for thirdparty id=" . $object->id, LOG_DEBUG);
208
        $resql = $this->db->query($sql);
209
        if ($resql) {
210
            $num = $this->db->num_rows($resql);
211
            if ($num) {
212
                $obj = $this->db->fetch_object($resql);
213
                $tiers = $obj->key_account;
214
215
                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']);
216
217
                try {
218
                    if (empty($key)) {              // If the Stripe connect account not set, we use common API usage
219
                        //$customer = \Stripe\Customer::retrieve("$tiers");
220
                        $customer = \Stripe\Customer::retrieve(array('id' => "$tiers", 'expand[]' => 'sources'));
221
                    } else {
222
                        //$customer = \Stripe\Customer::retrieve("$tiers", array("stripe_account" => $key));
223
                        $customer = \Stripe\Customer::retrieve(array('id' => "$tiers", 'expand[]' => 'sources'), array("stripe_account" => $key));
224
                    }
225
                } catch (Exception $e) {
0 ignored issues
show
Bug introduced by
The type Dolibarr\Code\Stripe\Classes\Exception was not found. Did you mean Exception? If so, make sure to prefix the type with \.
Loading history...
226
                    // 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.'
227
                    $this->error = $e->getMessage();
228
                }
229
            } elseif ($createifnotlinkedtostripe) {
230
                $ipaddress = getUserRemoteIP();
231
232
                $dataforcustomer = array(
233
                    "email" => $object->email,
0 ignored issues
show
Bug Best Practice introduced by
The property email does not exist on Dolibarr\Core\Base\CommonObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
234
                    "description" => $object->name,
235
                    "metadata" => array('dol_id' => $object->id, 'dol_version' => DOL_VERSION, 'dol_entity' => $conf->entity, 'ipaddress' => $ipaddress)
236
                );
237
238
                $vatcleaned = $object->tva_intra ? $object->tva_intra : null;
0 ignored issues
show
Bug Best Practice introduced by
The property tva_intra does not exist on Dolibarr\Core\Base\CommonObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
239
240
                /*
241
                $taxinfo = array('type'=>'vat');
242
                if ($vatcleaned)
243
                {
244
                    $taxinfo["tax_id"] = $vatcleaned;
245
                }
246
                // We force data to "null" if not defined as expected by Stripe
247
                if (empty($vatcleaned)) $taxinfo=null;
248
                $dataforcustomer["tax_info"] = $taxinfo;
249
                */
250
251
                //$a = \Stripe\Stripe::getApiKey();
252
                //var_dump($a);var_dump($key);exit;
253
                try {
254
                    // Force to use the correct API key
255
                    global $stripearrayofkeysbyenv;
256
                    \Stripe\Stripe::setApiKey($stripearrayofkeysbyenv[$status]['secret_key']);
257
258
                    if (empty($key)) {              // If the Stripe connect account not set, we use common API usage
259
                        $customer = \Stripe\Customer::create($dataforcustomer);
260
                    } else {
261
                        $customer = \Stripe\Customer::create($dataforcustomer, array("stripe_account" => $key));
262
                    }
263
264
                    // Create the VAT record in Stripe
265
                    if (getDolGlobalString('STRIPE_SAVE_TAX_IDS')) {    // We setup to save Tax info on Stripe side. Warning: This may result in error when saving customer
266
                        if (!empty($vatcleaned)) {
267
                            $isineec = isInEEC($object);
268
                            if ($object->country_code && $isineec) {
269
                                //$taxids = $customer->allTaxIds($customer->id);
270
                                $customer->createTaxId($customer->id, array('type' => 'eu_vat', 'value' => $vatcleaned));
0 ignored issues
show
Bug introduced by
The method createTaxId() does not exist on Stripe\StripeObject. It seems like you code against a sub-type of Stripe\StripeObject such as Stripe\Customer. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

270
                                $customer->/** @scrutinizer ignore-call */ 
271
                                           createTaxId($customer->id, array('type' => 'eu_vat', 'value' => $vatcleaned));
Loading history...
271
                            }
272
                        }
273
                    }
274
275
                    // Create customer in Dolibarr
276
                    $sql = "INSERT INTO " . MAIN_DB_PREFIX . "societe_account (fk_soc, login, key_account, site, site_account, status, entity, date_creation, fk_user_creat)";
277
                    $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) . ")";
278
                    $resql = $this->db->query($sql);
279
                    if (!$resql) {
280
                        $this->error = $this->db->lasterror();
281
                    }
282
                } catch (Exception $e) {
283
                    $this->error = $e->getMessage();
284
                }
285
            }
286
        } else {
287
            dol_print_error($this->db);
288
        }
289
290
        return $customer;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $customer also could return the type array which is incompatible with the documented return type Stripe\Customer|null.
Loading history...
291
    }
292
293
    /**
294
     * Get the Stripe payment method Object from its ID
295
     *
296
     * @param   string  $paymentmethod              Payment Method ID
297
     * @param   string  $key                        ''=Use common API. If not '', it is the Stripe connect account 'acc_....' to use Stripe connect
298
     * @param   int     $status                     Status (0=test, 1=live)
299
     * @return  \Stripe\PaymentMethod|null          Stripe PaymentMethod or null if not found
300
     */
301
    public function getPaymentMethodStripe($paymentmethod, $key = '', $status = 0)
302
    {
303
        $stripepaymentmethod = 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
                $stripepaymentmethod = \Stripe\PaymentMethod::retrieve((string) $paymentmethod->id);
0 ignored issues
show
Bug introduced by
The property id does not exist on string.
Loading history...
311
            } else {
312
                $stripepaymentmethod = \Stripe\PaymentMethod::retrieve((string) $paymentmethod->id, array("stripe_account" => $key));
313
            }
314
        } catch (Exception $e) {
315
            $this->error = $e->getMessage();
316
        }
317
318
        return $stripepaymentmethod;
319
    }
320
321
    /**
322
     * Get the Stripe reader Object from its ID
323
     *
324
     * @param   string  $reader             Reader ID
325
     * @param   string  $key                ''=Use common API. If not '', it is the Stripe connect account 'acc_....' to use Stripe connect
326
     * @param   int $status             Status (0=test, 1=live)
327
     * @return  \Stripe\Terminal\Reader|null        Stripe Reader or null if not found
328
     */
329
    public function getSelectedReader($reader, $key = '', $status = 0)
330
    {
331
        $selectedreader = null;
332
333
        try {
334
            // Force to use the correct API key
335
            global $stripearrayofkeysbyenv;
336
            \Stripe\Stripe::setApiKey($stripearrayofkeysbyenv[$status]['secret_key']);
337
            if (empty($key)) {              // If the Stripe connect account not set, we use common API usage
338
                $selectedreader = \Stripe\Terminal\Reader::retrieve((string) $reader);
339
            } else {
340
                $stripepaymentmethod = \Stripe\Terminal\Reader::retrieve((string) $reader, array("stripe_account" => $key));
341
            }
342
        } catch (Exception $e) {
343
            $this->error = $e->getMessage();
344
        }
345
346
        return $selectedreader;
347
    }
348
349
    /**
350
     * Get the Stripe payment intent. Create it with confirmnow=false
351
     * Warning. If a payment was tried and failed, a payment intent was created.
352
     * But if we change something on object to pay (amount or other), reusing same payment intent is not allowed by Stripe.
353
     * Recommended solution is to recreate a new payment intent each time we need one (old one will be automatically closed after a delay),
354
     * that's why i 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)
355
     * Note: This is used when option STRIPE_USE_INTENT_WITH_AUTOMATIC_CONFIRMATION is on when making a payment from the public/payment/newpayment.php page
356
     * but not when using the STRIPE_USE_NEW_CHECKOUT.
357
     *
358
     * @param   double  $amount                             Amount
359
     * @param   string  $currency_code                      Currency code
360
     * @param   string  $tag                                Tag
361
     * @param   string  $description                        Description
362
     * @param   mixed   $object                             Object to pay with Stripe
363
     * @param   string  $customer                           Stripe customer ref 'cus_xxxxxxxxxxxxx' via customerStripe()
364
     * @param   string  $key                                ''=Use common API. If not '', it is the Stripe connect account 'acc_....' to use Stripe connect
365
     * @param   int     $status                             Status (0=test, 1=live)
366
     * @param   int     $usethirdpartyemailforreceiptemail  1=use thirdparty email for receipt
367
     * @param   string  $mode                               automatic=automatic confirmation/payment when conditions are ok, manual=need to call confirm() on intent
368
     * @param   boolean $confirmnow                         false=default, true=try to confirm immediately after create (if conditions are ok)
369
     * @param   string  $payment_method                     'pm_....' (if known)
370
     * @param   int     $off_session                        If we use an already known payment method to pay when customer is not available during the checkout flow.
371
     * @param   int     $noidempotency_key                  Do not use the idempotency_key when creating the PaymentIntent
372
     * @param   int     $did                                ID of an existing line into llx_prelevement_demande (Dolibarr intent). If provided, no new line will be created.
373
     * @return  \Stripe\PaymentIntent|null                  Stripe PaymentIntent or null if not found and failed to create
374
     */
375
    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, $did = 0)
376
    {
377
        global $conf, $user;
378
379
        dol_syslog(get_class($this) . "::getPaymentIntent", LOG_INFO, 1);
380
381
        $error = 0;
382
383
        if (empty($status)) {
384
            $service = 'StripeTest';
385
        } else {
386
            $service = 'StripeLive';
387
        }
388
389
        $arrayzerounitcurrency = array('BIF', 'CLP', 'DJF', 'GNF', 'JPY', 'KMF', 'KRW', 'MGA', 'PYG', 'RWF', 'VND', 'VUV', 'XAF', 'XOF', 'XPF');
390
        if (!in_array($currency_code, $arrayzerounitcurrency)) {
391
            $stripeamount = $amount * 100;
392
        } else {
393
            $stripeamount = $amount;
394
        }
395
396
        $fee = 0;
397
        if (getDolGlobalString("STRIPE_APPLICATION_FEE_PERCENT")) {
398
            $fee = $amount * ((float) getDolGlobalString("STRIPE_APPLICATION_FEE_PERCENT", '0') / 100) + (float) getDolGlobalString("STRIPE_APPLICATION_FEE", '0');
399
        }
400
        if ($fee >= (float) getDolGlobalString("STRIPE_APPLICATION_FEE_MAXIMAL", '0') && (float) getDolGlobalString("STRIPE_APPLICATION_FEE_MAXIMAL", '0') > (float) getDolGlobalString("STRIPE_APPLICATION_FEE_MINIMAL", '0')) {
401
            $fee = (float) getDolGlobalString("STRIPE_APPLICATION_FEE_MAXIMAL", '0');
402
        } elseif ($fee < (float) getDolGlobalString("STRIPE_APPLICATION_FEE_MINIMAL", '0')) {
403
            $fee = (float) getDolGlobalString("STRIPE_APPLICATION_FEE_MINIMAL", '0');
404
        }
405
        if (!in_array($currency_code, $arrayzerounitcurrency)) {
406
            $stripefee = round($fee * 100);
407
        } else {
408
            $stripefee = round($fee);
409
        }
410
411
        $paymentintent = null;
412
413
        if (is_object($object) && getDolGlobalInt('STRIPE_REUSE_EXISTING_INTENT_IF_FOUND') && !getDolGlobalInt('STRIPE_CARD_PRESENT')) {
414
            // Warning. If a payment was tried and failed, a payment intent was created.
415
            // 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.
416
            // 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
417
            // automatically return the existing payment intent if idempotency is provided when we try to create the new one.
418
            // 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)
419
420
            $sql = "SELECT pi.ext_payment_id, pi.entity, pi.fk_facture, pi.sourcetype, pi.ext_payment_site";
421
            $sql .= " FROM " . MAIN_DB_PREFIX . "prelevement_demande as pi";
422
            $sql .= " WHERE pi.fk_facture = " . ((int) $object->id);
423
            $sql .= " AND pi.sourcetype = '" . $this->db->escape($object->element) . "'";
424
            $sql .= " AND pi.entity IN (" . getEntity('societe') . ")";
425
            $sql .= " AND pi.ext_payment_site = '" . $this->db->escape($service) . "'";
426
427
            dol_syslog(get_class($this) . "::getPaymentIntent search stripe payment intent for object id = " . $object->id, LOG_DEBUG);
428
            $resql = $this->db->query($sql);
429
            if ($resql) {
430
                $num = $this->db->num_rows($resql);
431
                if ($num) {
432
                    $obj = $this->db->fetch_object($resql);
433
                    $intent = $obj->ext_payment_id;
434
435
                    dol_syslog(get_class($this) . "::getPaymentIntent found existing payment intent record");
436
437
                    // Force to use the correct API key
438
                    global $stripearrayofkeysbyenv;
439
                    \Stripe\Stripe::setApiKey($stripearrayofkeysbyenv[$status]['secret_key']);
440
441
                    try {
442
                        if (empty($key)) {              // If the Stripe connect account not set, we use common API usage
443
                            $paymentintent = \Stripe\PaymentIntent::retrieve($intent);
444
                        } else {
445
                            $paymentintent = \Stripe\PaymentIntent::retrieve($intent, array("stripe_account" => $key));
446
                        }
447
                    } catch (Exception $e) {
448
                        $error++;
449
                        $this->error = $e->getMessage();
450
                    }
451
                }
452
            }
453
        }
454
455
        if (empty($paymentintent)) {
456
            // Try to create intent. See https://stripe.com/docs/api/payment_intents/create
457
            $ipaddress = getUserRemoteIP();
458
            $metadata = array('dol_version' => DOL_VERSION, 'dol_entity' => $conf->entity, 'ipaddress' => $ipaddress);
459
            if (is_object($object)) {
460
                $metadata['dol_type'] = $object->element;
461
                $metadata['dol_id'] = $object->id;
462
                if (is_object($object->thirdparty) && $object->thirdparty->id > 0) {
463
                    $metadata['dol_thirdparty_id'] = $object->thirdparty->id;
464
                }
465
            }
466
467
            // list of payment method types
468
            $paymentmethodtypes = array("card");
469
            $descriptor = dol_trunc($tag, 10, 'right', 'UTF-8', 1);
470
            if (getDolGlobalInt('STRIPE_SEPA_DIRECT_DEBIT')) {
471
                $paymentmethodtypes[] = "sepa_debit"; //&& ($object->thirdparty->isInEEC())
472
                //$descriptor = preg_replace('/ref=[^:=]+/', '', $descriptor);  // Clean ref
473
            }
474
            if (getDolGlobalInt('STRIPE_KLARNA')) {
475
                $paymentmethodtypes[] = "klarna";
476
            }
477
            if (getDolGlobalInt('STRIPE_BANCONTACT')) {
478
                $paymentmethodtypes[] = "bancontact";
479
            }
480
            if (getDolGlobalInt('STRIPE_IDEAL')) {
481
                $paymentmethodtypes[] = "ideal";
482
            }
483
            if (getDolGlobalInt('STRIPE_GIROPAY')) {
484
                $paymentmethodtypes[] = "giropay";
485
            }
486
            if (getDolGlobalInt('STRIPE_SOFORT')) {
487
                $paymentmethodtypes[] = "sofort";
488
            }
489
            if (getDolGlobalInt('STRIPE_CARD_PRESENT') && $mode == 'terminal') {
490
                $paymentmethodtypes = array("card_present");
491
            }
492
493
            global $dolibarr_main_url_root;
494
495
            $dataforintent = array(
496
                "confirm" => $confirmnow, // try to confirm immediately after create (if conditions are ok)
497
                "confirmation_method" => $mode,
498
                "amount" => $stripeamount,
499
                "currency" => $currency_code,
500
                "payment_method_types" => $paymentmethodtypes,  // When payment_method_types is set, return_url is not required but payment mode can't be managed from dashboard
501
                /*
502
                'return_url' => $dolibarr_main_url_root.'/public/payment/paymentok.php',
503
                'automatic_payment_methods' => array(
504
                    'enabled' => true,
505
                    'allow_redirects' => 'never',
506
                ),
507
                */
508
                "description" => $description,
509
                //"save_payment_method" => true,
510
                "setup_future_usage" => "on_session",
511
                "metadata" => $metadata
512
            );
513
            if ($descriptor) {
514
                $dataforintent["statement_descriptor_suffix"] = $descriptor; // For card payment, 22 chars that appears on bank receipt (prefix into stripe setup + this suffix)
515
                $dataforintent["statement_descriptor"] = $descriptor;   // For SEPA, it will take only statement_descriptor, not statement_descriptor_suffix
516
            }
517
            if (!is_null($customer)) {
518
                $dataforintent["customer"] = $customer;
519
            }
520
            // payment_method =
521
            // payment_method_types = array('card')
522
            //var_dump($dataforintent);
523
            if ($off_session) {
524
                unset($dataforintent['setup_future_usage']);
525
                // We can't use both "setup_future_usage" = "off_session" and "off_session" = true.
526
                // Because $off_session parameter is dedicated to create paymentintent off_line (and not future payment), we need to use "off_session" = true.
527
                //$dataforintent["setup_future_usage"] = "off_session";
528
                $dataforintent["off_session"] = true;
529
            }
530
            if (getDolGlobalInt('STRIPE_GIROPAY')) {
531
                unset($dataforintent['setup_future_usage']);
532
            }
533
            if (getDolGlobalInt('STRIPE_KLARNA')) {
534
                unset($dataforintent['setup_future_usage']);
535
            }
536
            if (getDolGlobalInt('STRIPE_CARD_PRESENT') && $mode == 'terminal') {
537
                unset($dataforintent['setup_future_usage']);
538
                $dataforintent["capture_method"] = "manual";
539
                $dataforintent["confirmation_method"] = "manual";
540
            }
541
            if (!is_null($payment_method)) {
542
                $dataforintent["payment_method"] = $payment_method;
543
                $description .= ' - ' . $payment_method;
544
            }
545
546
            if ($conf->entity != getDolGlobalInt('STRIPECONNECT_PRINCIPAL') && $stripefee > 0) {
547
                $dataforintent["application_fee_amount"] = $stripefee;
548
            }
549
            if ($usethirdpartyemailforreceiptemail && is_object($object) && $object->thirdparty->email) {
550
                $dataforintent["receipt_email"] = $object->thirdparty->email;
551
            }
552
553
            try {
554
                // Force to use the correct API key
555
                global $stripearrayofkeysbyenv;
556
                \Stripe\Stripe::setApiKey($stripearrayofkeysbyenv[$status]['secret_key']);
557
558
                $arrayofoptions = array();
559
                if (empty($noidempotency_key)) {
560
                    $arrayofoptions["idempotency_key"] = $description;
561
                }
562
                // 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.
563
                if (!empty($key)) {             // If the Stripe connect account not set, we use common API usage
564
                    $arrayofoptions["stripe_account"] = $key;
565
                }
566
567
                dol_syslog("dataforintent to create paymentintent = " . var_export($dataforintent, true));
568
569
                $paymentintent = \Stripe\PaymentIntent::create($dataforintent, $arrayofoptions);
570
571
                // Store the payment intent
572
                if (is_object($object)) {
573
                    $paymentintentalreadyexists = 0;
574
575
                    if ($did > 0) {
576
                        // If a payment request line provided, we do not need to recreate one, we just update it
577
                        dol_syslog(get_class($this) . "::getPaymentIntent search if payment intent already in prelevement_demande", LOG_DEBUG);
578
579
                        $sql = "UPDATE " . MAIN_DB_PREFIX . "prelevement_demande SET";
580
                        $sql .= " ext_payment_site = '" . $this->db->escape($service) . "',";
581
                        $sql .= " ext_payment_id = '" . $this->db->escape($paymentintent->id) . "'";
582
                        $sql .= " WHERE rowid = " . ((int) $did);
583
584
                        $resql = $this->db->query($sql);
585
                        if ($resql) {
586
                            $paymentintentalreadyexists++;
587
                        } else {
588
                            $error++;
589
                            dol_print_error($this->db);
590
                        }
591
                    } else {
592
                        // Check that payment intent $paymentintent->id is not already recorded.
593
                        dol_syslog(get_class($this) . "::getPaymentIntent search if payment intent already in prelevement_demande", LOG_DEBUG);
594
595
                        $sql = "SELECT pi.rowid";
596
                        $sql .= " FROM " . MAIN_DB_PREFIX . "prelevement_demande as pi";
597
                        $sql .= " WHERE pi.entity IN (" . getEntity('societe') . ")";
598
                        $sql .= " AND pi.ext_payment_site = '" . $this->db->escape($service) . "'";
599
                        $sql .= " AND pi.ext_payment_id = '" . $this->db->escape($paymentintent->id) . "'";
600
601
                        $resql = $this->db->query($sql);
602
                        if ($resql) {
603
                            $num = $this->db->num_rows($resql);
604
                            if ($num) {
605
                                $obj = $this->db->fetch_object($resql);
606
                                if ($obj) {
607
                                    $paymentintentalreadyexists++;
608
                                }
609
                            }
610
                        } else {
611
                            $error++;
612
                            dol_print_error($this->db);
613
                        }
614
                    }
615
616
                    // If not, we create it.
617
                    if (!$error && !$paymentintentalreadyexists) {
618
                        $now = dol_now();
619
                        $sql = "INSERT INTO " . MAIN_DB_PREFIX . "prelevement_demande (date_demande, fk_user_demande, ext_payment_id, fk_facture, sourcetype, entity, ext_payment_site, amount)";
620
                        $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) . ")";
621
                        $resql = $this->db->query($sql);
622
                        if (!$resql) {
623
                            $error++;
624
                            $this->error = $this->db->lasterror();
625
                            dol_syslog(get_class($this) . "::PaymentIntent failed to insert paymentintent with id=" . $paymentintent->id . " into database.", LOG_ERR);
626
                        }
627
                    }
628
                } else {
629
                    $_SESSION["stripe_payment_intent"] = $paymentintent;
630
                }
631
            } catch (Stripe\Exception\CardException $e) {
0 ignored issues
show
Bug introduced by
The type Dolibarr\Code\Stripe\Cla...Exception\CardException was not found. Did you mean Stripe\Exception\CardException? If so, make sure to prefix the type with \.
Loading history...
632
                $error++;
633
                $this->error = $e->getMessage();
634
                $this->code = $e->getStripeCode();
635
                $this->declinecode = $e->getDeclineCode();
636
            } catch (Exception $e) {
637
                //var_dump($dataforintent);
638
                //var_dump($description);
639
                //var_dump($key);
640
                //var_dump($paymentintent);
641
                //var_dump($e->getMessage());
642
                //var_dump($e);
643
                $error++;
644
                $this->error = $e->getMessage();
645
                $this->code = '';
646
                $this->declinecode = '';
647
            }
648
        }
649
650
        dol_syslog(get_class($this) . "::getPaymentIntent return error=" . $error . " this->error=" . $this->error, LOG_INFO, -1);
651
652
        if (!$error) {
653
            return $paymentintent;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $paymentintent also could return the type array which is incompatible with the documented return type Stripe\PaymentIntent|null.
Loading history...
654
        } else {
655
            return null;
656
        }
657
    }
658
659
    /**
660
     * Get the Stripe payment intent. Create it with confirmnow=false
661
     * Warning. If a payment was tried and failed, a payment intent was created.
662
     * But if we change something on object to pay (amount or other), reusing same payment intent is not allowed.
663
     * Recommended solution is to recreate a new payment intent each time we need one (old one will be automatically closed after a delay),
664
     * that's why i 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)
665
     * Note: This is used when option STRIPE_USE_INTENT_WITH_AUTOMATIC_CONFIRMATION is on when making a payment from the public/payment/newpayment.php page
666
     * but not when using the STRIPE_USE_NEW_CHECKOUT.
667
     *
668
     * @param   string  $description                        Description
669
     * @param   Societe $object                             Object of company to link the Stripe payment mode with
670
     * @param   string  $customer                           Stripe customer ref 'cus_xxxxxxxxxxxxx' via customerStripe()
671
     * @param   string  $key                                ''=Use common API. If not '', it is the Stripe connect account 'acc_....' to use Stripe connect
672
     * @param   int     $status                             Status (0=test, 1=live)
673
     * @param   int     $usethirdpartyemailforreceiptemail  1=use thirdparty email for receipt
674
     * @param   boolean $confirmnow                         false=default, true=try to confirm immediately after create (if conditions are ok)
675
     * @return  \Stripe\SetupIntent|null                    Stripe SetupIntent or null if not found and failed to create
676
     */
677
    public function getSetupIntent($description, $object, $customer, $key, $status, $usethirdpartyemailforreceiptemail = 0, $confirmnow = false)
678
    {
679
        global $conf;
680
681
        dol_syslog("getSetupIntent description=" . $description . ' confirmnow=' . json_encode($confirmnow), LOG_INFO, 1);
682
683
        $error = 0;
684
685
        if (empty($status)) {
686
            $service = 'StripeTest';
687
        } else {
688
            $service = 'StripeLive';
689
        }
690
691
        $setupintent = null;
692
693
        if (empty($setupintent)) {
694
            $ipaddress = getUserRemoteIP();
695
            $metadata = array('dol_version' => DOL_VERSION, 'dol_entity' => $conf->entity, 'ipaddress' => $ipaddress);
696
            if (is_object($object)) {
697
                $metadata['dol_type'] = $object->element;
698
                $metadata['dol_id'] = $object->id;
699
                if (is_object($object->thirdparty) && $object->thirdparty->id > 0) {
700
                    $metadata['dol_thirdparty_id'] = $object->thirdparty->id;
701
                }
702
            }
703
704
            // list of payment method types
705
            $paymentmethodtypes = array("card");
706
            if (getDolGlobalString('STRIPE_SEPA_DIRECT_DEBIT')) {
707
                $paymentmethodtypes[] = "sepa_debit"; //&& ($object->thirdparty->isInEEC())
708
            }
709
            if (getDolGlobalString('STRIPE_BANCONTACT')) {
710
                $paymentmethodtypes[] = "bancontact";
711
            }
712
            if (getDolGlobalString('STRIPE_IDEAL')) {
713
                $paymentmethodtypes[] = "ideal";
714
            }
715
            // Giropay not possible for setup intent
716
            if (getDolGlobalString('STRIPE_SOFORT')) {
717
                $paymentmethodtypes[] = "sofort";
718
            }
719
720
            global $dolibarr_main_url_root;
721
722
            $dataforintent = array(
723
                "confirm" => $confirmnow, // Do not confirm immediately during creation of intent
724
                "payment_method_types" => $paymentmethodtypes,  // When payment_method_types is set, return_url is not required but payment mode can't be managed from dashboard
725
                /*
726
                 'return_url' => $dolibarr_main_url_root.'/public/payment/paymentok.php',
727
                 'automatic_payment_methods' => array(
728
                 'enabled' => true,
729
                 'allow_redirects' => 'never',
730
                 ),
731
                 */
732
                "usage" => "off_session",
733
                "metadata" => $metadata
734
            );
735
            if (!is_null($customer)) {
736
                $dataforintent["customer"] = $customer;
737
            }
738
            if (!is_null($description)) {
739
                $dataforintent["description"] = $description;
740
            }
741
            // payment_method =
742
            // payment_method_types = array('card')
743
            //var_dump($dataforintent);
744
745
            if ($usethirdpartyemailforreceiptemail && is_object($object) && $object->thirdparty->email) {
746
                $dataforintent["receipt_email"] = $object->thirdparty->email;
747
            }
748
749
            try {
750
                // Force to use the correct API key
751
                global $stripearrayofkeysbyenv;
752
                \Stripe\Stripe::setApiKey($stripearrayofkeysbyenv[$status]['secret_key']);
753
754
                dol_syslog("getSetupIntent " . $stripearrayofkeysbyenv[$status]['publishable_key'], LOG_DEBUG);
755
756
                // 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.
757
                if (empty($key)) {              // If the Stripe connect account not set, we use common API usage
758
                    //$setupintent = \Stripe\SetupIntent::create($dataforintent, array("idempotency_key" => "$description"));
759
                    $setupintent = \Stripe\SetupIntent::create($dataforintent, array());
760
                } else {
761
                    //$setupintent = \Stripe\SetupIntent::create($dataforintent, array("idempotency_key" => "$description", "stripe_account" => $key));
762
                    $setupintent = \Stripe\SetupIntent::create($dataforintent, array("stripe_account" => $key));
763
                }
764
                //var_dump($setupintent->id);
765
766
                // Store the setup intent
767
                /*if (is_object($object))
768
                {
769
                    $setupintentalreadyexists = 0;
770
                    // Check that payment intent $setupintent->id is not already recorded.
771
                    $sql = "SELECT pi.rowid";
772
                    $sql.= " FROM " . MAIN_DB_PREFIX . "prelevement_demande as pi";
773
                    $sql.= " WHERE pi.entity IN (".getEntity('societe').")";
774
                    $sql.= " AND pi.ext_payment_site = '" . $this->db->escape($service) . "'";
775
                    $sql.= " AND pi.ext_payment_id = '".$this->db->escape($setupintent->id)."'";
776
777
                    dol_syslog(get_class($this) . "::getPaymentIntent search if payment intent already in prelevement_demande", LOG_DEBUG);
778
                    $resql = $this->db->query($sql);
779
                    if ($resql) {
780
                        $num = $this->db->num_rows($resql);
781
                        if ($num)
782
                        {
783
                            $obj = $this->db->fetch_object($resql);
784
                            if ($obj) $setupintentalreadyexists++;
785
                        }
786
                    }
787
                    else dol_print_error($this->db);
788
789
                    // If not, we create it.
790
                    if (! $setupintentalreadyexists)
791
                    {
792
                        $now=dol_now();
793
                        $sql = "INSERT INTO " . MAIN_DB_PREFIX . "prelevement_demande (date_demande, fk_user_demande, ext_payment_id, fk_facture, sourcetype, entity, ext_payment_site)";
794
                        $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).")";
795
                        $resql = $this->db->query($sql);
796
                        if (! $resql)
797
                        {
798
                            $error++;
799
                            $this->error = $this->db->lasterror();
800
                            dol_syslog(get_class($this) . "::PaymentIntent failed to insert paymentintent with id=".$setupintent->id." into database.");
801
                        }
802
                    }
803
                }
804
                else
805
                {
806
                    $_SESSION["stripe_setup_intent"] = $setupintent;
807
                }*/
808
            } catch (Exception $e) {
809
                //var_dump($dataforintent);
810
                //var_dump($description);
811
                //var_dump($key);
812
                //var_dump($setupintent);
813
                //var_dump($e->getMessage());
814
                $error++;
815
                $this->error = $e->getMessage();
816
            }
817
        }
818
819
        if (!$error) {
820
            dol_syslog("getSetupIntent " . (is_object($setupintent) ? $setupintent->id : ''), LOG_INFO, -1);
821
            return $setupintent;
822
        } else {
823
            dol_syslog("getSetupIntent return error=" . $error, LOG_INFO, -1);
824
            return null;
825
        }
826
    }
827
828
829
    /**
830
     * Get the Stripe card of a company payment mode (option to create it on Stripe if not linked yet is no more available on new Stripe API)
831
     *
832
     * @param   \Stripe\Customer        $cu                             Object stripe customer.
833
     * @param   CompanyPaymentMode      $object                         Object companypaymentmode to check, or create on stripe (create on stripe also update the societe_rib table for current entity)
834
     * @param   string                  $stripeacc                      ''=Use common API. If not '', it is the Stripe connect account 'acc_....' to use Stripe connect
835
     * @param   int                     $status                         Status (0=test, 1=live)
836
     * @param   int                     $createifnotlinkedtostripe      1=Create the stripe card and the link if the card is not yet linked to a stripe card. Deprecated with new Stripe API and SCA.
837
     * @return  \Stripe\Card|\Stripe\PaymentMethod|null                 Stripe Card or null if not found
838
     */
839
    public function cardStripe($cu, CompanyPaymentMode $object, $stripeacc = '', $status = 0, $createifnotlinkedtostripe = 0)
840
    {
841
        global $conf, $user, $langs;
842
843
        $card = null;
844
845
        $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_....
846
        $sql .= " FROM " . MAIN_DB_PREFIX . "societe_rib as sa";
847
        $sql .= " WHERE sa.rowid = " . ((int) $object->id); // We get record from ID, no need for filter on entity
848
        $sql .= " AND sa.type = 'card'";
849
850
        dol_syslog(get_class($this) . "::cardStripe search stripe card id for paymentmode id=" . $object->id . ", stripeacc=" . $stripeacc . ", status=" . $status . ", createifnotlinkedtostripe=" . $createifnotlinkedtostripe, LOG_DEBUG);
851
        $resql = $this->db->query($sql);
852
        if ($resql) {
853
            $num = $this->db->num_rows($resql);
854
            if ($num) {
855
                $obj = $this->db->fetch_object($resql);
856
                $cardref = $obj->stripe_card_ref;
857
                dol_syslog(get_class($this) . "::cardStripe cardref=" . $cardref);
858
                if ($cardref) {
859
                    try {
860
                        if (empty($stripeacc)) {                // If the Stripe connect account not set, we use common API usage
861
                            if (!preg_match('/^pm_/', $cardref) && !empty($cu->sources)) {
862
                                $card = $cu->sources->retrieve($cardref);
863
                            } else {
864
                                $card = \Stripe\PaymentMethod::retrieve($cardref);
865
                            }
866
                        } else {
867
                            if (!preg_match('/^pm_/', $cardref) && !empty($cu->sources)) {
868
                                //$card = $cu->sources->retrieve($cardref, array("stripe_account" => $stripeacc));      // this API fails when array stripe_account is provided
869
                                $card = $cu->sources->retrieve($cardref);
870
                            } else {
871
                                //$card = \Stripe\PaymentMethod::retrieve($cardref, array("stripe_account" => $stripeacc));     // Don't know if this works
872
                                $card = \Stripe\PaymentMethod::retrieve($cardref);
873
                            }
874
                        }
875
                    } catch (Exception $e) {
876
                        $this->error = $e->getMessage();
877
                        dol_syslog($this->error, LOG_WARNING);
878
                    }
879
                } elseif ($createifnotlinkedtostripe) {
880
                    // Deprecated with new Stripe API and SCA. We should not use anymore this part of code now.
881
                    $exp_date_month = $obj->exp_date_month;
882
                    $exp_date_year = $obj->exp_date_year;
883
                    $number = $obj->number;
884
                    $cvc = $obj->cvn; // cvn in database, cvc for stripe
885
                    $cardholdername = $obj->proprio;
886
887
                    $ipaddress = getUserRemoteIP();
888
889
                    $dataforcard = array(
890
                        "source" => array(
891
                            'object' => 'card',
892
                            'exp_month' => $exp_date_month,
893
                            'exp_year' => $exp_date_year,
894
                            'number' => $number,
895
                            'cvc' => $cvc,
896
                            'name' => $cardholdername
897
                        ),
898
                        "metadata" => array(
899
                            'dol_type' => $object->element,
900
                            'dol_id' => $object->id,
901
                            'dol_version' => DOL_VERSION,
902
                            'dol_entity' => $conf->entity,
903
                            'ipaddress' => $ipaddress
904
                        )
905
                    );
906
907
                    //$a = \Stripe\Stripe::getApiKey();
908
                    //var_dump($a);
909
                    //var_dump($stripeacc);exit;
910
                    try {
911
                        if (empty($stripeacc)) {                // If the Stripe connect account not set, we use common API usage
912
                            if (!getDolGlobalString('STRIPE_USE_INTENT_WITH_AUTOMATIC_CONFIRMATION')) {
913
                                dol_syslog("Try to create card with dataforcard = " . json_encode($dataforcard));
914
                                $card = $cu->sources->create($dataforcard);
0 ignored issues
show
Bug introduced by
The method create() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

914
                                /** @scrutinizer ignore-call */ 
915
                                $card = $cu->sources->create($dataforcard);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
915
                                if (!$card) {
916
                                    $this->error = 'Creation of card on Stripe has failed';
917
                                }
918
                            } else {
919
                                $connect = '';
920
                                if (!empty($stripeacc)) {
921
                                    $connect = $stripeacc . '/';
922
                                }
923
                                $url = 'https://dashboard.stripe.com/' . $connect . 'test/customers/' . $cu->id;
924
                                if ($status) {
925
                                    $url = 'https://dashboard.stripe.com/' . $connect . 'customers/' . $cu->id;
926
                                }
927
                                $urtoswitchonstripe = '<a href="' . $url . '" target="_stripe">' . img_picto($langs->trans('ShowInStripe'), 'globe') . '</a>';
928
929
                                //dol_syslog("Error: This case is not supported", LOG_ERR);
930
                                $this->error = str_replace('{s1}', $urtoswitchonstripe, $langs->trans('CreationOfPaymentModeMustBeDoneFromStripeInterface', '{s1}'));
931
                            }
932
                        } else {
933
                            if (!getDolGlobalString('STRIPE_USE_INTENT_WITH_AUTOMATIC_CONFIRMATION')) {
934
                                dol_syslog("Try to create card with dataforcard = " . json_encode($dataforcard));
935
                                $card = $cu->sources->create($dataforcard, array("stripe_account" => $stripeacc));
936
                                if (!$card) {
937
                                    $this->error = 'Creation of card on Stripe has failed';
938
                                }
939
                            } else {
940
                                $connect = '';
941
                                if (!empty($stripeacc)) {
942
                                    $connect = $stripeacc . '/';
943
                                }
944
                                $url = 'https://dashboard.stripe.com/' . $connect . 'test/customers/' . $cu->id;
945
                                if ($status) {
946
                                    $url = 'https://dashboard.stripe.com/' . $connect . 'customers/' . $cu->id;
947
                                }
948
                                $urtoswitchonstripe = '<a href="' . $url . '" target="_stripe">' . img_picto($langs->trans('ShowInStripe'), 'globe') . '</a>';
949
950
                                //dol_syslog("Error: This case is not supported", LOG_ERR);
951
                                $this->error = str_replace('{s1}', $urtoswitchonstripe, $langs->trans('CreationOfPaymentModeMustBeDoneFromStripeInterface', '{s1}'));
952
                            }
953
                        }
954
955
                        if ($card) {
956
                            $sql = "UPDATE " . MAIN_DB_PREFIX . "societe_rib";
957
                            $sql .= " SET stripe_card_ref = '" . $this->db->escape($card->id) . "', card_type = '" . $this->db->escape($card->brand) . "',";
958
                            $sql .= " country_code = '" . $this->db->escape($card->country) . "',";
959
                            $sql .= " approved = " . ($card->cvc_check == 'pass' ? 1 : 0);
960
                            $sql .= " WHERE rowid = " . ((int) $object->id);
961
                            $sql .= " AND type = 'card'";
962
                            $resql = $this->db->query($sql);
963
                            if (!$resql) {
964
                                $this->error = $this->db->lasterror();
965
                            }
966
                        }
967
                    } catch (Exception $e) {
968
                        $this->error = $e->getMessage();
969
                        dol_syslog($this->error, LOG_WARNING);
970
                    }
971
                }
972
            }
973
        } else {
974
            dol_print_error($this->db);
975
        }
976
977
        return $card;
978
    }
979
980
981
    /**
982
     * Get the Stripe SEPA of a company payment mode (create it if it doesn't exists and $createifnotlinkedtostripe is set)
983
     *
984
     * @param   \Stripe\Customer        $cu                             Object stripe customer.
985
     * @param   CompanyPaymentMode      $object                         Object companypaymentmode to check, or create on stripe (create on stripe also update the societe_rib table for current entity)
986
     * @param   string                  $stripeacc                      ''=Use common API. If not '', it is the Stripe connect account 'acc_....' to use Stripe connect
987
     * @param   int                     $status                         Status (0=test, 1=live)
988
     * @param   int                     $createifnotlinkedtostripe      1=Create the stripe sepa and the link if the sepa is not yet linked to a stripe sepa. Used by the "Create bank to Stripe" feature.
989
     * @return  \Stripe\PaymentMethod|null                              Stripe SEPA or null if not found
990
     */
991
    public function sepaStripe($cu, CompanyPaymentMode $object, $stripeacc = '', $status = 0, $createifnotlinkedtostripe = 0)
992
    {
993
        global $conf;
994
        $sepa = null;
995
996
        $sql = "SELECT sa.stripe_card_ref, sa.proprio, sa.iban_prefix as iban, sa.rum"; // stripe_card_ref is 'src_...' for Stripe SEPA
997
        $sql .= " FROM " . MAIN_DB_PREFIX . "societe_rib as sa";
998
        $sql .= " WHERE sa.rowid = " . ((int) $object->id); // We get record from ID, no need for filter on entity
999
        $sql .= " AND sa.type = 'ban'"; //type ban to get normal bank account of customer (prelevement)
1000
1001
        $soc = new Societe($this->db);
1002
        $soc->fetch($object->fk_soc);
1003
1004
        dol_syslog(get_class($this) . "::sepaStripe search stripe ban id for paymentmode id=" . $object->id . ", stripeacc=" . $stripeacc . ", status=" . $status . ", createifnotlinkedtostripe=" . $createifnotlinkedtostripe, LOG_DEBUG);
1005
        $resql = $this->db->query($sql);
1006
        if ($resql) {
1007
            $num = $this->db->num_rows($resql);
1008
            if ($num) {
1009
                $obj = $this->db->fetch_object($resql);
1010
                $cardref = $obj->stripe_card_ref;
1011
                dol_syslog(get_class($this) . "::sepaStripe paymentmode=" . $cardref);
1012
                if ($cardref) {
1013
                    try {
1014
                        if (empty($stripeacc)) {                // If the Stripe connect account not set, we use common API usage
1015
                            if (!preg_match('/^pm_/', $cardref) && !empty($cu->sources)) {
1016
                                $sepa = $cu->sources->retrieve($cardref);
1017
                            } else {
1018
                                $sepa = \Stripe\PaymentMethod::retrieve($cardref);
1019
                            }
1020
                        } else {
1021
                            if (!preg_match('/^pm_/', $cardref) && !empty($cu->sources)) {
1022
                                //$sepa = $cu->sources->retrieve($cardref, array("stripe_account" => $stripeacc));      // this API fails when array stripe_account is provided
1023
                                $sepa = $cu->sources->retrieve($cardref);
1024
                            } else {
1025
                                //$sepa = \Stripe\PaymentMethod::retrieve($cardref, array("stripe_account" => $stripeacc));     // Don't know if this works
1026
                                $sepa = \Stripe\PaymentMethod::retrieve($cardref);
1027
                            }
1028
                        }
1029
                    } catch (Exception $e) {
1030
                        $this->error = $e->getMessage();
1031
                        dol_syslog($this->error, LOG_WARNING);
1032
                    }
1033
                } elseif ($createifnotlinkedtostripe) {
1034
                    $iban = $obj->iban;
1035
                    $ipaddress = getUserRemoteIP();
1036
                    $metadata = array('dol_version' => DOL_VERSION, 'dol_entity' => $conf->entity, 'ipaddress' => $ipaddress);
1037
                    if (is_object($object)) {
1038
                        $metadata['dol_type'] = $object->element;
1039
                        $metadata['dol_id'] = $object->id;
1040
                        $metadata['dol_thirdparty_id'] = $soc->id;
1041
                    }
1042
1043
                    $description = 'SEPA for IBAN ' . $iban;
1044
1045
                    $dataforcard = array(
1046
                        'type' => 'sepa_debit',
1047
                        "sepa_debit" => array('iban' => $iban),
1048
                        'billing_details' => array(
1049
                            'name' => $soc->name,
1050
                            'email' => !empty($soc->email) ? $soc->email : "",
1051
                        ),
1052
                        "metadata" => $metadata
1053
                    );
1054
                    // Complete owner name
1055
                    if (!empty($soc->town)) {
1056
                        $dataforcard['billing_details']['address']['city'] = $soc->town;
1057
                    }
1058
                    if (!empty($soc->country_code)) {
1059
                        $dataforcard['billing_details']['address']['country'] = $soc->country_code;
1060
                    }
1061
                    if (!empty($soc->address)) {
1062
                        $dataforcard['billing_details']['address']['line1'] = $soc->address;
1063
                    }
1064
                    if (!empty($soc->zip)) {
1065
                        $dataforcard['billing_details']['address']['postal_code'] = $soc->zip;
1066
                    }
1067
                    if (!empty($soc->state)) {
1068
                        $dataforcard['billing_details']['address']['state'] = $soc->state;
1069
                    }
1070
1071
                    //$a = \Stripe\Stripe::getApiKey();
1072
                    //var_dump($a);var_dump($stripeacc);exit;
1073
                    try {
1074
                        dol_syslog("Try to create sepa_debit");
1075
1076
                        $service = 'StripeTest';
1077
                        $servicestatus = 0;
1078
                        if (getDolGlobalString('STRIPE_LIVE') && !GETPOST('forcesandbox', 'alpha')) {
1079
                            $service = 'StripeLive';
1080
                            $servicestatus = 1;
1081
                        }
1082
                        // Force to use the correct API key
1083
                        global $stripearrayofkeysbyenv;
1084
                        $stripeacc = $stripearrayofkeysbyenv[$servicestatus]['secret_key'];
1085
1086
                        dol_syslog("Try to create sepa_debit with data = " . json_encode($dataforcard));
1087
1088
                        $s = new \Stripe\StripeClient($stripeacc);
1089
1090
                        //var_dump($dataforcard);exit;
1091
1092
                        $sepa = $s->paymentMethods->create($dataforcard);
1093
                        if (!$sepa) {
1094
                            $this->error = 'Creation of payment method sepa_debit on Stripe has failed';
1095
                        } else {
1096
                            // link customer and src
1097
                            //$cs = $this->getSetupIntent($description, $soc, $cu, '', $status);
1098
                            $dataforintent = array(0 => ['description' => $description, 'payment_method_types' => ['sepa_debit'], 'customer' => $cu->id, 'payment_method' => $sepa->id], 'metadata' => $metadata);
1099
1100
                            $cs = $s->setupIntents->create($dataforintent);
1101
                            //$cs = $s->setupIntents->update($cs->id, ['payment_method' => $sepa->id]);
1102
                            $cs = $s->setupIntents->confirm($cs->id, ['mandate_data' => ['customer_acceptance' => ['type' => 'offline']]]);
1103
                            // note: $cs->mandate contains ID of mandate on Stripe side
1104
1105
                            if (!$cs) {
1106
                                $this->error = 'Link SEPA <-> Customer failed';
1107
                            } else {
1108
                                dol_syslog("Update the payment mode of the customer");
1109
1110
                                // print json_encode($sepa);
1111
1112
                                // Save the Stripe payment mode ID into the Dolibarr database
1113
                                $sql = "UPDATE " . MAIN_DB_PREFIX . "societe_rib";
1114
                                $sql .= " SET stripe_card_ref = '" . $this->db->escape($sepa->id) . "',";
1115
                                $sql .= " card_type = 'sepa_debit',";
1116
                                $sql .= " stripe_account= '" . $this->db->escape($cu->id . "@" . $stripeacc) . "',";
1117
                                $sql .= " ext_payment_site = '" . $this->db->escape($service) . "'";
1118
                                if (!empty($cs->mandate)) {
1119
                                    $mandateservice = new \Stripe\Mandate($stripeacc);
1120
                                    $mandate = $mandateservice->retrieve($cs->mandate);
1121
                                    if (is_object($mandate) && is_object($mandate->payment_method_details) && is_object($mandate->payment_method_details->sepa_debit)) {
1122
                                        $refmandate = $mandate->payment_method_details->sepa_debit->reference;
1123
                                        //$urlmandate = $mandate->payment_method_details->sepa_debit->url;
1124
                                        $sql .= ", rum = '" . $this->db->escape($refmandate) . "'";
1125
                                    }
1126
                                    $sql .= ", comment = '" . $this->db->escape($cs->mandate) . "'";
1127
                                    $sql .= ", date_rum = '" . $this->db->idate(dol_now()) . "'";
1128
                                }
1129
                                $sql .= " WHERE rowid = " . ((int) $object->id);
1130
                                $sql .= " AND type = 'ban'";
1131
                                $resql = $this->db->query($sql);
1132
                                if (!$resql) {
1133
                                    $this->error = $this->db->lasterror();
1134
                                }
1135
                            }
1136
                        }
1137
                    } catch (Exception $e) {
1138
                        $sepa = null;
1139
                        $this->error = 'Stripe error: ' . $e->getMessage() . '. Check the BAN information.';
1140
                        dol_syslog($this->error, LOG_WARNING);  // Error from Stripe, so a warning on Dolibarr
1141
                    }
1142
                }
1143
            }
1144
        } else {
1145
            dol_print_error($this->db);
1146
        }
1147
1148
        return $sepa;
1149
    }
1150
1151
1152
    /**
1153
     * Create charge.
1154
     * This was called by page htdocs/stripe/payment.php and may be deprecated.
1155
     *
1156
     * @param   int     $amount                                 Amount to pay
1157
     * @param   string  $currency                               EUR, GPB...
1158
     * @param   string  $origin                                 Object type to pay (order, invoice, contract...)
1159
     * @param   int     $item                                   Object id to pay
1160
     * @param   string  $source                                 src_xxxxx or card_xxxxx or pm_xxxxx
1161
     * @param   string  $customer                               Stripe customer ref 'cus_xxxxxxxxxxxxx' via customerStripe()
1162
     * @param   string  $account                                Stripe account ref 'acc_xxxxxxxxxxxxx' via  getStripeAccount()
1163
     * @param   int     $status                                 Status (0=test, 1=live)
1164
     * @param   int     $usethirdpartyemailforreceiptemail      Use thirdparty email as receipt email
1165
     * @param   boolean $capture                                Set capture flag to true (take payment) or false (wait)
1166
     * @return Stripe
1167
     * @deprecated
1168
     */
1169
    public function createPaymentStripe($amount, $currency, $origin, $item, $source, $customer, $account, $status = 0, $usethirdpartyemailforreceiptemail = 0, $capture = true)
1170
    {
1171
        global $conf;
1172
1173
        $error = 0;
1174
1175
        if (empty($status)) {
1176
            $service = 'StripeTest';
1177
        } else {
1178
            $service = 'StripeLive';
1179
        }
1180
1181
        $sql = "SELECT sa.key_account as key_account, sa.fk_soc, sa.entity";
1182
        $sql .= " FROM " . MAIN_DB_PREFIX . "societe_account as sa";
1183
        $sql .= " WHERE sa.key_account = '" . $this->db->escape($customer) . "'";
1184
        //$sql.= " AND sa.entity IN (".getEntity('societe').")";
1185
        $sql .= " AND sa.site = 'stripe' AND sa.status = " . ((int) $status);
1186
1187
        dol_syslog(get_class($this) . "::fetch", LOG_DEBUG);
1188
        $result = $this->db->query($sql);
1189
        if ($result) {
1190
            if ($this->db->num_rows($result)) {
1191
                $obj = $this->db->fetch_object($result);
1192
                $key = $obj->fk_soc;
1193
            } else {
1194
                $key = null;
1195
            }
1196
        } else {
1197
            $key = null;
1198
        }
1199
1200
        $arrayzerounitcurrency = array('BIF', 'CLP', 'DJF', 'GNF', 'JPY', 'KMF', 'KRW', 'MGA', 'PYG', 'RWF', 'VND', 'VUV', 'XAF', 'XOF', 'XPF');
1201
        if (!in_array($currency, $arrayzerounitcurrency)) {
1202
            $stripeamount = $amount * 100;
1203
        } else {
1204
            $stripeamount = $amount;
1205
        }
1206
1207
        $societe = new Societe($this->db);
1208
        if ($key > 0) {
1209
            $societe->fetch($key);
1210
        }
1211
1212
        $description = "";
1213
        $ref = "";
1214
        if ($origin == 'order') {
1215
            $order = new Commande($this->db);
1216
            $order->fetch($item);
1217
            $ref = $order->ref;
1218
            $description = "ORD=" . $ref . ".CUS=" . $societe->id . ".PM=stripe";
1219
        } elseif ($origin == 'invoice') {
1220
            $invoice = new Facture($this->db);
0 ignored issues
show
Bug introduced by
The type Dolibarr\Code\Stripe\Classes\Facture was not found. Did you mean Facture? If so, make sure to prefix the type with \.
Loading history...
1221
            $invoice->fetch($item);
1222
            $ref = $invoice->ref;
1223
            $description = "INV=" . $ref . ".CUS=" . $societe->id . ".PM=stripe";
1224
        }
1225
1226
        $ipaddress = getUserRemoteIP();
1227
1228
        $metadata = array(
1229
            "dol_id" => (string) $item,
1230
            "dol_type" => (string) $origin,
1231
            "dol_thirdparty_id" => (string) $societe->id,
1232
            'dol_thirdparty_name' => $societe->name,
1233
            'dol_version' => DOL_VERSION,
1234
            'dol_entity' => $conf->entity,
1235
            'ipaddress' => $ipaddress
1236
        );
1237
        $return = new Stripe($this->db);
1238
        try {
1239
            // Force to use the correct API key
1240
            global $stripearrayofkeysbyenv;
1241
            \Stripe\Stripe::setApiKey($stripearrayofkeysbyenv[$status]['secret_key']);
1242
1243
            if (empty($conf->stripeconnect->enabled)) { // With a common Stripe account
1244
                if (preg_match('/pm_/i', $source)) {
1245
                    $stripecard = $source;
1246
                    $amountstripe = $stripeamount;
1247
                    $FULLTAG = 'PFBO'; // Payment From Back Office
1248
                    $stripe = $return;
1249
                    $amounttopay = $amount;
1250
                    $servicestatus = $status;
1251
1252
                    dol_syslog("* createPaymentStripe get stripeacc", LOG_DEBUG);
1253
                    $stripeacc = $stripe->getStripeAccount($service); // Get Stripe OAuth connect account if it exists (no network access here)
1254
1255
                    dol_syslog("* createPaymentStripe Create payment for customer " . $customer->id . " on source card " . $stripecard->id . ", amounttopay=" . $amounttopay . ", amountstripe=" . $amountstripe . ", FULLTAG=" . $FULLTAG, LOG_DEBUG);
0 ignored issues
show
Bug introduced by
The property id does not exist on string.
Loading history...
1256
1257
                    // Create payment intent and charge payment (confirmnow = true)
1258
                    $paymentintent = $stripe->getPaymentIntent($amounttopay, $currency, $FULLTAG, $description, $invoice, $customer->id, $stripeacc, $servicestatus, 0, 'automatic', true, $stripecard->id, 1);
1259
1260
                    $charge = new stdClass();
0 ignored issues
show
Bug introduced by
The type Dolibarr\Code\Stripe\Classes\stdClass was not found. Did you mean stdClass? If so, make sure to prefix the type with \.
Loading history...
1261
                    if ($paymentintent->status == 'succeeded') {
1262
                        $charge->status = 'ok';
1263
                    } else {
1264
                        $charge->status = 'failed';
1265
                        $charge->failure_code = $stripe->code;
1266
                        $charge->failure_message = $stripe->error;
1267
                        $charge->failure_declinecode = $stripe->declinecode;
1268
                        $stripefailurecode = $stripe->code;
1269
                        $stripefailuremessage = $stripe->error;
1270
                        $stripefailuredeclinecode = $stripe->declinecode;
1271
                    }
1272
                } elseif (preg_match('/acct_/i', $source)) {
1273
                    $charge = \Stripe\Charge::create(array(
1274
                        "amount" => "$stripeamount",
1275
                        "currency" => "$currency",
1276
                        "statement_descriptor_suffix" => dol_trunc($description, 10, 'right', 'UTF-8', 1), // 22 chars that appears on bank receipt (company + description)
1277
                        "description" => "Stripe payment: " . $description,
1278
                        "capture"  => $capture,
1279
                        "metadata" => $metadata,
1280
                        "source" => "$source"
1281
                    ));
1282
                } else {
1283
                    $paymentarray = array(
1284
                        "amount" => "$stripeamount",
1285
                        "currency" => "$currency",
1286
                        "statement_descriptor_suffix" => dol_trunc($description, 10, 'right', 'UTF-8', 1), // 22 chars that appears on bank receipt (company + description)
1287
                        "description" => "Stripe payment: " . $description,
1288
                        "capture"  => $capture,
1289
                        "metadata" => $metadata,
1290
                        "source" => "$source",
1291
                        "customer" => "$customer"
1292
                    );
1293
1294
                    if ($societe->email && $usethirdpartyemailforreceiptemail) {
1295
                        $paymentarray["receipt_email"] = $societe->email;
1296
                    }
1297
1298
                    $charge = \Stripe\Charge::create($paymentarray, array("idempotency_key" => "$description"));
1299
                }
1300
            } else {
1301
                // With Stripe Connect
1302
                $fee = $amount * ($conf->global->STRIPE_APPLICATION_FEE_PERCENT / 100) + $conf->global->STRIPE_APPLICATION_FEE;
1303
                if ($fee >= $conf->global->STRIPE_APPLICATION_FEE_MAXIMAL && $conf->global->STRIPE_APPLICATION_FEE_MAXIMAL > $conf->global->STRIPE_APPLICATION_FEE_MINIMAL) {
1304
                    $fee = getDolGlobalString('STRIPE_APPLICATION_FEE_MAXIMAL');
1305
                } elseif ($fee < $conf->global->STRIPE_APPLICATION_FEE_MINIMAL) {
1306
                    $fee = getDolGlobalString('STRIPE_APPLICATION_FEE_MINIMAL');
1307
                }
1308
1309
                if (!in_array($currency, $arrayzerounitcurrency)) {
1310
                    $stripefee = round($fee * 100);
1311
                } else {
1312
                    $stripefee = round($fee);
1313
                }
1314
1315
                $paymentarray = array(
1316
                    "amount" => "$stripeamount",
1317
                    "currency" => "$currency",
1318
                "statement_descriptor_suffix" => dol_trunc($description, 10, 'right', 'UTF-8', 1), // 22 chars that appears on bank receipt (company + description)
1319
                    "description" => "Stripe payment: " . $description,
1320
                    "capture"  => $capture,
1321
                    "metadata" => $metadata,
1322
                    "source" => "$source",
1323
                    "customer" => "$customer"
1324
                );
1325
                if ($conf->entity != $conf->global->STRIPECONNECT_PRINCIPAL && $stripefee > 0) {
1326
                    $paymentarray["application_fee_amount"] = $stripefee;
1327
                }
1328
                if ($societe->email && $usethirdpartyemailforreceiptemail) {
1329
                    $paymentarray["receipt_email"] = $societe->email;
1330
                }
1331
1332
                if (preg_match('/pm_/i', $source)) {
1333
                    $stripecard = $source;
1334
                    $amountstripe = $stripeamount;
1335
                    $FULLTAG = 'PFBO'; // Payment From Back Office
1336
                    $stripe = $return;
1337
                    $amounttopay = $amount;
1338
                    $servicestatus = $status;
1339
1340
                    dol_syslog("* createPaymentStripe get stripeacc", LOG_DEBUG);
1341
                    $stripeacc = $stripe->getStripeAccount($service); // Get Stripe OAuth connect account if it exists (no network access here)
1342
1343
                    dol_syslog("* createPaymentStripe Create payment on card " . $stripecard->id . ", amounttopay=" . $amounttopay . ", amountstripe=" . $amountstripe . ", FULLTAG=" . $FULLTAG, LOG_DEBUG);
1344
1345
                    // Create payment intent and charge payment (confirmnow = true)
1346
                    $paymentintent = $stripe->getPaymentIntent($amounttopay, $currency, $FULLTAG, $description, $invoice, $customer->id, $stripeacc, $servicestatus, 0, 'automatic', true, $stripecard->id, 1);
1347
1348
                    $charge = new stdClass();
1349
                    if ($paymentintent->status == 'succeeded') {
1350
                        $charge->status = 'ok';
1351
                        $charge->id = $paymentintent->id;
1352
                    } else {
1353
                        $charge->status = 'failed';
1354
                        $charge->failure_code = $stripe->code;
1355
                        $charge->failure_message = $stripe->error;
1356
                        $charge->failure_declinecode = $stripe->declinecode;
1357
                    }
1358
                } else {
1359
                    $charge = \Stripe\Charge::create($paymentarray, array("idempotency_key" => "$description", "stripe_account" => "$account"));
1360
                }
1361
            }
1362
            if (isset($charge->id)) {
1363
            }
1364
1365
            $return->result = 'success';
0 ignored issues
show
Deprecated Code introduced by
The property Dolibarr\Code\Stripe\Classes\Stripe::$result has been deprecated: Was used by createPaymentStripe only that is deprecated ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

1365
            /** @scrutinizer ignore-deprecated */ $return->result = 'success';

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
1366
            $return->id = $charge->id;
0 ignored issues
show
Documentation Bug introduced by
It seems like $charge->id can also be of type string. However, the property $id is declared as type integer. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
1367
1368
            if (preg_match('/pm_/i', $source)) {
1369
                $return->message = 'Payment retrieved by card status = ' . $charge->status;
1370
            } else {
1371
                if ($charge->source->type == 'card') {
1372
                    $return->message = $charge->source->card->brand . " ...." . $charge->source->card->last4;
1373
                } elseif ($charge->source->type == 'three_d_secure') {
1374
                    $stripe = new Stripe($this->db);
1375
                    $src = \Stripe\Source::retrieve("" . $charge->source->three_d_secure->card, array(
1376
                    "stripe_account" => $stripe->getStripeAccount($service)
1377
                    ));
1378
                    $return->message = $src->card->brand . " ...." . $src->card->last4;
1379
                } else {
1380
                    $return->message = $charge->id;
1381
                }
1382
            }
1383
        } catch (\Stripe\Exception\CardException $e) {
1384
            include DOL_DOCUMENT_ROOT . '/core/class/CMailFile.class.php';
1385
            // Since it's a decline, \Stripe\Exception\Card will be caught
1386
            $body = $e->getJsonBody();
1387
            $err = $body['error'];
1388
1389
            $return->result = 'error';
0 ignored issues
show
Deprecated Code introduced by
The property Dolibarr\Code\Stripe\Classes\Stripe::$result has been deprecated: Was used by createPaymentStripe only that is deprecated ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

1389
            /** @scrutinizer ignore-deprecated */ $return->result = 'error';

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
1390
            $return->id = $err['charge'];
1391
            $return->type = $err['type'];
1392
            $return->code = $err['code'];
1393
            $return->message = $err['message'];
1394
            $body = "Error: <br>" . $return->id . " " . $return->message . " ";
1395
            $subject = '[Alert] Payment error using Stripe';
1396
            $cmailfile = new CMailFile($subject, $conf->global->ONLINE_PAYMENT_SENDEMAIL, $conf->global->MAIN_INFO_SOCIETE_MAIL, $body);
1397
            $cmailfile->sendfile();
1398
1399
            $error++;
1400
            dol_syslog($e->getMessage(), LOG_WARNING, 0, '_stripe');
1401
        } catch (\Stripe\Exception\RateLimitException $e) {
1402
            // Too many requests made to the API too quickly
1403
            $error++;
1404
            dol_syslog($e->getMessage(), LOG_WARNING, 0, '_stripe');
1405
        } catch (\Stripe\Exception\InvalidRequestException $e) {
1406
            // Invalid parameters were supplied to Stripe's API
1407
            $error++;
1408
            dol_syslog($e->getMessage(), LOG_WARNING, 0, '_stripe');
1409
        } catch (\Stripe\Exception\AuthenticationException $e) {
1410
            // Authentication with Stripe's API failed
1411
            // (maybe you changed API keys recently)
1412
            $error++;
1413
            dol_syslog($e->getMessage(), LOG_WARNING, 0, '_stripe');
1414
        } catch (\Stripe\Exception\ApiConnectionException $e) {
1415
            // Network communication with Stripe failed
1416
            $error++;
1417
            dol_syslog($e->getMessage(), LOG_WARNING, 0, '_stripe');
1418
        } catch (\Stripe\Exception\ExceptionInterface $e) {
1419
            // Display a very generic error to the user, and maybe send
1420
            // yourself an email
1421
            $error++;
1422
            dol_syslog($e->getMessage(), LOG_WARNING, 0, '_stripe');
0 ignored issues
show
Bug introduced by
The method getMessage() does not exist on Stripe\Exception\ExceptionInterface. It seems like you code against a sub-type of said class. However, the method does not exist in Stripe\Exception\OAuth\ExceptionInterface. Are you sure you never get one of those? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

1422
            dol_syslog($e->/** @scrutinizer ignore-call */ getMessage(), LOG_WARNING, 0, '_stripe');
Loading history...
1423
        } catch (Exception $e) {
1424
            // Something else happened, completely unrelated to Stripe
1425
            $error++;
1426
            dol_syslog($e->getMessage(), LOG_WARNING, 0, '_stripe');
1427
        }
1428
        return $return;
1429
    }
1430
}
1431