19if (!defined(
'NOLOGIN')) {
22if (!defined(
'NOCSRFCHECK')) {
23 define(
"NOCSRFCHECK", 1);
25if (!defined(
'NOIPCHECK')) {
26 define(
'NOIPCHECK',
'1');
28if (!defined(
'NOBROWSERNOTIF')) {
29 define(
'NOBROWSERNOTIF',
'1');
32$entity = (!empty($_GET[
'entity']) ? (int) $_GET[
'entity'] : (!empty($_POST[
'entity']) ? (int) $_POST[
'entity'] : 1));
33if (is_numeric($entity)) {
34 define(
"DOLENTITY", $entity);
38if (!defined(
'USESUFFIXINLOG')) {
39 define(
'USESUFFIXINLOG',
'_stripeipn');
43require
'../../main.inc.php';
44require_once DOL_DOCUMENT_ROOT.
'/core/lib/admin.lib.php';
45require_once DOL_DOCUMENT_ROOT.
'/user/class/user.class.php';
46require_once DOL_DOCUMENT_ROOT.
'/core/class/ccountry.class.php';
47require_once DOL_DOCUMENT_ROOT.
'/commande/class/commande.class.php';
48require_once DOL_DOCUMENT_ROOT.
'/compta/paiement/class/paiement.class.php';
49require_once DOL_DOCUMENT_ROOT.
'/compta/facture/class/facture.class.php';
50require_once DOL_DOCUMENT_ROOT.
'/compta/bank/class/account.class.php';
51require_once DOL_DOCUMENT_ROOT.
'/compta/prelevement/class/bonprelevement.class.php';
52require_once DOL_DOCUMENT_ROOT.
'/societe/class/societe.class.php';
53require_once DOL_DOCUMENT_ROOT.
'/core/class/CMailFile.class.php';
54require_once DOL_DOCUMENT_ROOT.
'/includes/stripe/stripe-php/init.php';
55require_once DOL_DOCUMENT_ROOT.
'/stripe/class/stripe.class.php';
59if (isset($_GET[
'connect'])) {
60 if (isset($_GET[
'test'])) {
61 $endpoint_secret = $conf->global->STRIPE_TEST_WEBHOOK_CONNECT_KEY;
62 $service =
'StripeTest';
65 $endpoint_secret = $conf->global->STRIPE_LIVE_WEBHOOK_CONNECT_KEY;
66 $service =
'StripeLive';
70 if (isset($_GET[
'test'])) {
71 $endpoint_secret = $conf->global->STRIPE_TEST_WEBHOOK_KEY;
72 $service =
'StripeTest';
75 $endpoint_secret = $conf->global->STRIPE_LIVE_WEBHOOK_KEY;
76 $service =
'StripeLive';
81if (!isModEnabled(
'stripe')) {
85if (empty($endpoint_secret)) {
89if (!empty($conf->global->STRIPE_USER_ACCOUNT_FOR_ACTIONS)) {
91 $user =
new User($db);
92 $user->fetch($conf->global->STRIPE_USER_ACCOUNT_FOR_ACTIONS);
107$payload = @file_get_contents(
"php://input");
108$sig_header = empty($_SERVER[
"HTTP_STRIPE_SIGNATURE"]) ?
'' : $_SERVER[
"HTTP_STRIPE_SIGNATURE"];
112 $fh = fopen(DOL_DATA_ROOT.
'/dolibarr_stripeipn_payload.log',
'w+');
114 fwrite($fh,
dol_print_date(
dol_now(
'gmt'),
'standard').
' IPN Called. service='.$service.
' HTTP_STRIPE_SIGNATURE='.$sig_header.
"\n");
115 fwrite($fh, $payload);
117 dolChmod(DOL_DATA_ROOT.
'/dolibarr_stripeipn_payload.log');
124 $event = \Stripe\Webhook::constructEvent($payload, $sig_header, $endpoint_secret);
125}
catch (UnexpectedValueException $e) {
129 httponly_accessforbidden(
'Invalid signature. May be a hook for an event created by another Stripe env ? Check setup of your keys whsec_...', 400);
139if (isModEnabled(
'multicompany') && !empty($conf->stripeconnect->enabled) && is_object($mc)) {
140 $sql =
"SELECT entity";
141 $sql .=
" FROM ".MAIN_DB_PREFIX.
"oauth_token";
142 $sql .=
" WHERE service = '".$db->escape($service).
"' and tokenstring LIKE '%".$db->escape($db->escapeforlike($event->account)).
"%'";
144 dol_syslog(get_class($db).
"::fetch", LOG_DEBUG);
145 $result = $db->query($sql);
147 if ($db->num_rows($result)) {
148 $obj = $db->fetch_object($result);
156 $ret = $mc->switchEntity($key);
163$societeName = $conf->global->MAIN_INFO_SOCIETE_NOM;
164if (!empty($conf->global->MAIN_APPLICATION_TITLE)) {
165 $societeName = $conf->global->MAIN_APPLICATION_TITLE;
170dol_syslog(
"***** Stripe IPN was called with event->type = ".$event->type);
173if ($event->type ==
'payout.created') {
176 $result =
dolibarr_set_const($db, $service.
"_NEXTPAYOUT", date(
'Y-m-d H:i:s', $event->data->object->arrival_date),
'chaine', 0,
'', $conf->entity);
179 $subject = $societeName.
' - [NOTIFICATION] Stripe payout scheduled';
180 if (!empty($user->email)) {
183 $sendto = $conf->global->MAIN_INFO_SOCIETE_MAIL.
'" <'.$conf->global->MAIN_INFO_SOCIETE_MAIL.
'>';
187 if (!empty($conf->global->ONLINE_PAYMENT_SENDEMAIL)) {
188 $sendtocc = $conf->global->ONLINE_PAYMENT_SENDEMAIL.
'" <'.$conf->global->ONLINE_PAYMENT_SENDEMAIL.
'>';
191 $message =
"A bank transfer of ".price2num($event->data->object->amount / 100).
" ".$event->data->object->currency.
" should arrive in your account the ".
dol_print_date($event->data->object->arrival_date,
'dayhour');
207 $ret = $mailfile->sendfile();
212 http_response_code(500);
215} elseif ($event->type ==
'payout.paid') {
217 $result =
dolibarr_set_const($db, $service.
"_NEXTPAYOUT",
null,
'chaine', 0,
'', $conf->entity);
219 $langs->load(
"errors");
222 $label = $event->data->object->description;
223 $amount = $event->data->object->amount / 100;
224 $amount_to = $event->data->object->amount / 100;
225 require_once DOL_DOCUMENT_ROOT.
'/compta/bank/class/account.class.php';
227 $accountfrom =
new Account($db);
228 $accountfrom->fetch($conf->global->STRIPE_BANK_ACCOUNT_FOR_PAYMENTS);
231 $accountto->fetch($conf->global->STRIPE_BANK_ACCOUNT_FOR_BANKTRANSFERS);
233 if (($accountto->id != $accountfrom->id) && empty($error)) {
234 $bank_line_id_from = 0;
235 $bank_line_id_to = 0;
243 $bank_line_id_from = $accountfrom->addline($dateo, $typefrom, $label, -1 *
price2num($amount),
'',
'', $user);
245 if (!($bank_line_id_from > 0)) {
249 $bank_line_id_to = $accountto->addline($dateo, $typeto, $label,
price2num($amount),
'',
'', $user);
251 if (!($bank_line_id_to > 0)) {
256 $result = $accountfrom->add_url_line($bank_line_id_from, $bank_line_id_to, DOL_URL_ROOT.
'/compta/bank/line.php?rowid=',
'(banktransfert)',
'banktransfert');
258 if (!($result > 0)) {
262 $result = $accountto->add_url_line($bank_line_id_to, $bank_line_id_from, DOL_URL_ROOT.
'/compta/bank/line.php?rowid=',
'(banktransfert)',
'banktransfert');
264 if (!($result > 0)) {
269 $subject = $societeName.
' - [NOTIFICATION] Stripe payout done';
270 if (!empty($user->email)) {
273 $sendto = $conf->global->MAIN_INFO_SOCIETE_MAIL.
'" <'.$conf->global->MAIN_INFO_SOCIETE_MAIL.
'>';
277 if (!empty($conf->global->ONLINE_PAYMENT_SENDEMAIL)) {
278 $sendtocc = $conf->global->ONLINE_PAYMENT_SENDEMAIL.
'" <'.$conf->global->ONLINE_PAYMENT_SENDEMAIL.
'>';
281 $message =
"A bank transfer of ".price2num($event->data->object->amount / 100).
" ".$event->data->object->currency.
" has been done to your account the ".
dol_print_date($event->data->object->arrival_date,
'dayhour');
297 $ret = $mailfile->sendfile();
302 http_response_code(500);
305} elseif ($event->type ==
'customer.source.created') {
307} elseif ($event->type ==
'customer.source.updated') {
309} elseif ($event->type ==
'customer.source.delete') {
311} elseif ($event->type ==
'customer.deleted') {
313 $sql =
"DELETE FROM ".MAIN_DB_PREFIX.
"societe_account WHERE key_account = '".$db->escape($event->data->object->id).
"' and site='stripe'";
316} elseif ($event->type ==
'payment_intent.succeeded') {
318 include_once DOL_DOCUMENT_ROOT .
'/compta/paiement/class/paiement.class.php';
319 global $stripearrayofkeysbyenv;
321 $object = $event->data->object;
322 $TRANSACTIONID = $object->id;
323 $ipaddress = $object->metadata->ipaddress;
325 $currencyCodeType = strtoupper($object->currency);
326 $paymentmethodstripeid = $object->payment_method;
327 $customer_id = $object->customer;
332 dol_syslog(
"Try to find the payment in database for the payment id = ".$TRANSACTIONID);
334 $sql =
"SELECT pi.fk_facture, pi.fk_prelevement_bons, pi.amount, pi.type";
335 $sql .=
" FROM llx_prelevement_demande as pi";
336 $sql .=
" WHERE pi.ext_payment_id = '".$db->escape($TRANSACTIONID).
"'";
337 $sql .=
" AND pi.traite = '1'";
338 $sql .=
" AND pi.ext_payment_site = '".$db->escape($service).
"'";
340 $result = $db->query($sql);
342 $obj = $db->fetch_object($result);
344 $invoice_id = $obj->fk_facture;
345 $prelevement_bons_id = $obj->fk_prelevement_bons;
346 $payment_amount = $obj->amount;
347 $paymentTypeId = $obj->type;
350 http_response_code(500);
351 print $db->lasterror();
355 $stripeacc = $stripearrayofkeysbyenv[$servicestatus][
'secret_key'];
357 dol_syslog(
"Get the Stripe payment object for the payment method id = ".json_encode($paymentmethodstripeid));
359 $s = new \Stripe\StripeClient($stripeacc);
361 $paymentmethodstripe = $s->paymentMethods->retrieve($paymentmethodstripeid);
362 $paymentTypeId = $paymentmethodstripe->type;
363 if ($paymentTypeId ==
"ban" || $paymentTypeId ==
"sepa_debit") {
364 $paymentTypeId =
"PRE";
365 } elseif ($paymentTypeId ==
"card") {
366 $paymentTypeId =
"CB";
369 if ($paymentTypeId ==
"PRE") {
371 $paiement->datepaye = $now;
372 $paiement->date = $now;
373 if ($currencyCodeType == $conf->currency) {
374 $paiement->amounts = [$invoice_id => $payment_amount];
376 $paiement->multicurrency_amounts = [$invoice_id => $payment_amount];
378 $postactionmessages[] =
'Payment was done in a different currency than currency expected of company';
379 $ispostactionok = -1;
383 $paiement->paiementid = $paymentTypeId;
384 $paiement->num_payment =
'';
385 $paiement->note_public =
'';
386 $paiement->note_private =
'StripeSepa payment ' .
dol_print_date($now,
'standard') .
' using ' . $servicestatus . ($ipaddress ?
' from ip ' . $ipaddress :
'') .
' - Transaction ID = ' . $TRANSACTIONID;
387 $paiement->ext_payment_id = $TRANSACTIONID.
':'.$customer_id.
'@'.$stripearrayofkeysbyenv[$servicestatus][
'publishable_key'];
388 $paiement->ext_payment_site = $service;
391 $sql =
"SELECT p.rowid FROM llx_paiement as p";
392 $sql .=
" WHERE p.ext_payment_id = '".$db->escape($paiement->ext_payment_id).
"'";
393 $sql .=
" AND p.ext_payment_site = '".$db->escape($paiement->ext_payment_site).
"'";
394 $result = $db->query($sql);
396 if ($db->num_rows($result)) {
398 dol_syslog(
'* Payment for ext_payment_id '.$paiement->ext_payment_id.
' already done. We do not recreate the payment');
404 if (!$error && !$ispaymentdone) {
405 dol_syslog(
'* Record payment for invoice id ' . $invoice_id .
'. It includes closing of invoice and regenerating document');
408 $paiement_id = $paiement->create($user, 1);
409 if ($paiement_id < 0) {
410 $postactionmessages[] = $paiement->error . ($paiement->error ?
' ' :
'') . join(
"<br>\n", $paiement->errors);
411 $ispostactionok = -1;
414 dol_syslog(
"Failed to create the payment for invoice id " . $invoice_id);
416 $postactionmessages[] =
'Payment created';
418 dol_syslog(
"The payment has been created for invoice id " . $invoice_id);
422 if (!$error && isModEnabled(
'banque')) {
425 $sql =
"SELECT p.rowid, p.fk_bank FROM llx_paiement as p";
426 $sql .=
" WHERE p.ext_payment_id = '".$db->escape($paiement->ext_payment_id).
"'";
427 $sql .=
" AND p.ext_payment_site = '".$db->escape($paiement->ext_payment_site).
"'";
428 $sql .=
" AND p.fk_bank <> 0";
429 $result = $db->query($sql);
431 if ($db->num_rows($result)) {
433 $obj = $db->fetch_object($result);
434 dol_syslog(
'* Payment already linked to bank record '.$obj->fk_bank.
' . We do not recreate the link');
437 if (!$ispaymentdone) {
441 $paymentmethod =
'stripe';
444 if ($bankaccountid > 0) {
445 $label =
'(CustomerInvoicePayment)';
446 $result = $paiement->addPaymentToBank($user,
'payment', $label, $bankaccountid, $customer_id,
'');
448 $postactionmessages[] = $paiement->error . ($paiement->error ?
' ' :
'') . join(
"<br>\n", $paiement->errors);
449 $ispostactionok = -1;
452 $postactionmessages[] =
'Bank transaction of payment created (by makeStripeSepaRequest)';
455 $postactionmessages[] =
'Setup of bank account to use in module ' . $paymentmethod .
' was not set. No way to record the payment.';
456 $ispostactionok = -1;
462 if (!$error && isModEnabled(
'prelevement')) {
465 $sql =
"SELECT dp.fk_prelevement_bons as idbon";
466 $sql .=
" FROM ".MAIN_DB_PREFIX.
"prelevement_demande as dp";
467 $sql .=
" JOIN ".MAIN_DB_PREFIX.
"prelevement_bons as pb";
468 $sql .=
" ON pb.rowid = dp.fk_prelevement_bons";
469 $sql .=
" WHERE dp.fk_facture = ".((int) $invoice_id);
470 $sql .=
" AND dp.sourcetype = 'facture'";
471 $sql .=
" AND dp.ext_payment_id = '".$db->escape($TRANSACTIONID).
"'";
472 $sql .=
" AND dp.traite = 1";
473 $sql .=
" AND statut = ".((int) $bon::STATUS_TRANSFERED);
474 $result = $db->query($sql);
476 if ($db->num_rows($result)) {
477 $obj = $db->fetch_object($result);
478 $idbon = $obj->idbon;
481 dol_syslog(
'* Prelevement not found or already credited');
484 $postactionmessages[] = $db->lasterror();
485 $ispostactionok = -1;
489 if (!$error && !empty($idbon)) {
490 $sql =
"UPDATE ".MAIN_DB_PREFIX.
"prelevement_bons";
491 $sql .=
" SET fk_user_credit = ".((int) $user->id);
492 $sql .=
", statut = ".((int) $bon::STATUS_CREDITED);
493 $sql .=
", date_credit = '".$db->idate($now).
"'";
494 $sql .=
", credite = 1";
495 $sql .=
" WHERE rowid = ".((int) $idbon);
496 $sql .=
" AND statut = ".((int) $bon::STATUS_TRANSFERED);
498 $result = $db->query($sql);
500 $postactionmessages[] = $db->lasterror();
501 $ispostactionok = -1;
506 if (!$error && !empty($idbon)) {
507 $sql =
"UPDATE ".MAIN_DB_PREFIX.
"prelevement_lignes";
508 $sql .=
" SET statut = 2";
509 $sql .=
" WHERE fk_prelevement_bons = ".((int) $idbon);
510 $result = $db->query($sql);
512 $postactionmessages[] = $db->lasterror();
513 $ispostactionok = -1;
521 http_response_code(200);
525 http_response_code(500);
529 dol_syslog(
"The payment mode of this payment is ".$paymentTypeId.
". This payment mode is not managed by the IPN");
531} elseif ($event->type ==
'payment_intent.payment_failed') {
532 dol_syslog(
"A try to make a payment has failed");
533} elseif ($event->type ==
'checkout.session.completed') {
535} elseif ($event->type ==
'payment_method.attached') {
536 require_once DOL_DOCUMENT_ROOT.
'/societe/class/companypaymentmode.class.php';
537 require_once DOL_DOCUMENT_ROOT.
'/societe/class/societeaccount.class.php';
542 $idthirdparty = $societeaccount->getThirdPartyID($db->escape($event->data->object->customer),
'stripe', $servicestatus);
543 if ($idthirdparty > 0) {
546 $companypaymentmode->stripe_card_ref = $db->escape($event->data->object->id);
547 $companypaymentmode->fk_soc = $idthirdparty;
548 $companypaymentmode->bank =
null;
549 $companypaymentmode->label =
null;
550 $companypaymentmode->number = $db->escape($event->data->object->id);
551 $companypaymentmode->last_four = $db->escape($event->data->object->card->last4);
552 $companypaymentmode->card_type = $db->escape($event->data->object->card->branding);
553 $companypaymentmode->proprio = $db->escape($event->data->object->billing_details->name);
554 $companypaymentmode->exp_date_month = $db->escape($event->data->object->card->exp_month);
555 $companypaymentmode->exp_date_year = $db->escape($event->data->object->card->exp_year);
556 $companypaymentmode->cvn =
null;
557 $companypaymentmode->datec = $db->escape($event->data->object->created);
558 $companypaymentmode->default_rib = 0;
559 $companypaymentmode->type = $db->escape($event->data->object->type);
560 $companypaymentmode->country_code = $db->escape($event->data->object->card->country);
561 $companypaymentmode->status = $servicestatus;
567 $result = $companypaymentmode->create($user);
578} elseif ($event->type ==
'payment_method.updated') {
579 require_once DOL_DOCUMENT_ROOT.
'/societe/class/companypaymentmode.class.php';
581 $companypaymentmode->fetch(0,
'', 0,
'',
" AND stripe_card_ref = '".$db->escape($event->data->object->id).
"'");
582 if ($companypaymentmode->id > 0) {
584 $companypaymentmode->bank =
null;
585 $companypaymentmode->label =
null;
586 $companypaymentmode->number = $db->escape($event->data->object->id);
587 $companypaymentmode->last_four = $db->escape($event->data->object->card->last4);
588 $companypaymentmode->proprio = $db->escape($event->data->object->billing_details->name);
589 $companypaymentmode->exp_date_month = $db->escape($event->data->object->card->exp_month);
590 $companypaymentmode->exp_date_year = $db->escape($event->data->object->card->exp_year);
591 $companypaymentmode->cvn =
null;
592 $companypaymentmode->datec = $db->escape($event->data->object->created);
593 $companypaymentmode->default_rib = 0;
594 $companypaymentmode->type = $db->escape($event->data->object->type);
595 $companypaymentmode->country_code = $db->escape($event->data->object->card->country);
596 $companypaymentmode->status = $servicestatus;
600 $result = $companypaymentmode->update($user);
611} elseif ($event->type ==
'payment_method.detached') {
613 $sql =
"DELETE FROM ".MAIN_DB_PREFIX.
"societe_rib WHERE number = '".$db->escape($event->data->object->id).
"' and status = ".((int) $servicestatus);
616} elseif ($event->type ==
'charge.succeeded') {
619} elseif ($event->type ==
'charge.failed') {
621} elseif (($event->type ==
'source.chargeable') && ($event->data->object->type ==
'three_d_secure') && ($event->data->object->three_d_secure->authenticated ==
true)) {
dolibarr_set_const($db, $name, $value, $type='chaine', $visible=0, $note='', $entity=1)
Insert a parameter (key,value) into database (delete old key then insert it again).
Class to manage bank accounts.
Class to manage withdrawal receipts.
Class to send emails (with attachments or not) Usage: $mailfile = new CMailFile($subject,...
Class for CompanyPaymentMode.
Class to manage payments of customer invoices.
Class for SocieteAccount.
Class to manage Dolibarr users.
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs='', $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
dolChmod($filepath, $newmask='')
Change mod of a file.
dol_now($mode='auto')
Return date for now.
getDolGlobalInt($key, $default=0)
Return dolibarr global constant int value.
dolGetFirstLastname($firstname, $lastname, $nameorder=-1)
Return firstname and lastname in correct order.
getDolGlobalString($key, $default='')
Return dolibarr global constant string value.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0, $cleanalsojavascript=0)
Returns text escaped for inclusion in HTML alt or title or value tags, or into values of HTML input f...
if(!defined( 'NOREQUIREMENU')) if(!empty(GETPOST('seteventmessages', 'alpha'))) if(!function_exists("llxHeader")) top_httphead($contenttype='text/html', $forcenocache=0)
Show HTTP header.
httponly_accessforbidden($message=1, $http_response_code=403, $stringalreadysanitized=0)
Show a message to say access is forbidden and stop program.