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