21if (!defined(
'NOLOGIN')) {
24if (!defined(
'NOCSRFCHECK')) {
25 define(
"NOCSRFCHECK", 1);
27if (!defined(
'NOIPCHECK')) {
28 define(
'NOIPCHECK',
'1');
30if (!defined(
'NOBROWSERNOTIF')) {
31 define(
'NOBROWSERNOTIF',
'1');
35$entity = (!empty($_GET[
'entity']) ? (int) $_GET[
'entity'] : (!empty($_POST[
'entity']) ? (int) $_POST[
'entity'] : 1));
36if (is_numeric($entity)) {
37 define(
"DOLENTITY", $entity);
41if (!defined(
'USESUFFIXINLOG')) {
42 define(
'USESUFFIXINLOG',
'_stripeipn');
46require
'../../main.inc.php';
54require_once DOL_DOCUMENT_ROOT.
'/core/lib/admin.lib.php';
55require_once DOL_DOCUMENT_ROOT.
'/user/class/user.class.php';
56require_once DOL_DOCUMENT_ROOT.
'/core/class/ccountry.class.php';
57require_once DOL_DOCUMENT_ROOT.
'/commande/class/commande.class.php';
58require_once DOL_DOCUMENT_ROOT.
'/compta/paiement/class/paiement.class.php';
59require_once DOL_DOCUMENT_ROOT.
'/compta/facture/class/facture.class.php';
60require_once DOL_DOCUMENT_ROOT.
'/compta/bank/class/account.class.php';
61require_once DOL_DOCUMENT_ROOT.
'/compta/prelevement/class/bonprelevement.class.php';
62require_once DOL_DOCUMENT_ROOT.
'/societe/class/societe.class.php';
63require_once DOL_DOCUMENT_ROOT.
'/core/class/CMailFile.class.php';
64require_once DOL_DOCUMENT_ROOT.
'/includes/stripe/stripe-php/init.php';
65require_once DOL_DOCUMENT_ROOT.
'/stripe/class/stripe.class.php';
68if (GETPOSTISSET(
'connect')) {
69 if (GETPOSTISSET(
'test')) {
71 $service =
'StripeTest';
75 $service =
'StripeLive';
79 if (GETPOSTISSET(
'test')) {
81 $service =
'StripeTest';
85 $service =
'StripeLive';
94if (empty($endpoint_secret)) {
117$payload = @file_get_contents(
"php://input");
118$sig_header = empty($_SERVER[
"HTTP_STRIPE_SIGNATURE"]) ?
'' : $_SERVER[
"HTTP_STRIPE_SIGNATURE"];
122 $fh = fopen(DOL_DATA_ROOT.
'/dolibarr_stripeipn_payload.log',
'w+');
124 fwrite($fh,
dol_print_date(
dol_now(
'gmt'),
'standard').
' IPN Called. service='.$service.
' HTTP_STRIPE_SIGNATURE='.$sig_header.
"\n");
125 fwrite($fh, $payload);
127 dolChmod(DOL_DATA_ROOT.
'/dolibarr_stripeipn_payload.log');
134 $event = \Stripe\Webhook::constructEvent($payload, $sig_header, $endpoint_secret);
135}
catch (UnexpectedValueException $e) {
137 dol_syslog(
"***** Stripe IPN was called with UnexpectedValueException (invalid payload) service=".$service);
138 dol_syslog(
"***** Stripe IPN was called with UnexpectedValueException (invalid payload) service=".$service, LOG_DEBUG, 0,
'_payment');
141 dol_syslog(
"***** Stripe IPN was called with SignatureVerificationException service=".$service);
142 dol_syslog(
"***** Stripe IPN was called with SignatureVerificationException service=".$service, LOG_DEBUG, 0,
'_payment');
143 httponly_accessforbidden(
'Invalid signature. May be a hook for an event created by another Stripe env or a hack attempt ? Check setup of your keys whsec_...', 400);
145 dol_syslog(
"***** Stripe IPN was called with Exception (".$e->getMessage().
") service=".$service);
146 dol_syslog(
"***** Stripe IPN was called with Exception (".$e->getMessage().
") service=".$service, LOG_DEBUG, 0,
'_payment');
155if (
isModEnabled(
'multicompany') && !empty(
$conf->stripeconnect->enabled) && isset($mc) && is_object($mc)) {
156 $sql =
"SELECT entity";
157 $sql .=
" FROM ".MAIN_DB_PREFIX.
"oauth_token";
158 $sql .=
" WHERE service = '".$db->escape($service).
"' and tokenstring LIKE '%".
$db->escape(
$db->escapeforlike($event->account)).
"%'";
160 dol_syslog(get_class(
$db).
"::fetch", LOG_DEBUG, 0,
'_payment');
162 $result =
$db->query($sql);
164 if (
$db->num_rows($result)) {
165 $obj =
$db->fetch_object($result);
173 $ret = $mc->switchEntity($key);
191dol_syslog(
"***** Stripe IPN was called with event->type=".$event->type.
" service=".$service);
192dol_syslog(
"***** Stripe IPN was called with event->type=".$event->type.
" service=".$service, LOG_DEBUG, 0,
'_payment');
197$hookmanager->initHooks(array(
'stripeipn'));
198$parameters = array(
'event' => $event,
'servicestatus' => $servicestatus,
'service' => $service);
199$reshook = $hookmanager->executeHooks(
'stripeWebhookEvent', $parameters, $event->data->object, $event->type);
202 http_response_code(200);
207if ($event->type ==
'payout.created' &&
getDolGlobalString(
'STRIPE_AUTO_RECORD_PAYOUT')) {
214 $result =
dolibarr_set_const(
$db, $service.
"_NEXTPAYOUT",
date(
'Y-m-d H:i:s', $event->data->object->arrival_date),
'chaine', 0,
'',
$conf->entity);
217 $subject =
'['.$societeName.
'] Notification - Stripe payout scheduled';
218 if (!empty($user->email)) {
229 $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');
245 $ret = $mailfile->sendfile();
250 http_response_code(500);
253} elseif ($event->type ==
'payout.paid' &&
getDolGlobalString(
'STRIPE_AUTO_RECORD_PAYOUT')) {
261 $langs->load(
"errors");
266 $label = $event->data->object->description.
' - '.
getDolGlobalString(
'STRIPE_AUTO_RECORD_PAYOUT_LABEL',
'autorecord by IPN, see Stripe setup');
267 $amount = $stripe->convertAmount($event->data->object->amount, $currency_code, 1);
269 require_once DOL_DOCUMENT_ROOT.
'/compta/bank/class/account.class.php';
272 $accountfrom->fetch(
getDolGlobalInt(
'STRIPE_BANK_ACCOUNT_FOR_PAYMENTS'));
275 $accountto->fetch(
getDolGlobalInt(
'STRIPE_BANK_ACCOUNT_FOR_BANKTRANSFERS'));
277 if (($accountto->id != $accountfrom->id) && empty($error)) {
278 $bank_line_id_from = 0;
279 $bank_line_id_to = 0;
291 $bank_line_id_from = $accountfrom->addline($dateo, $typefrom, $label, -1 * (
float)
price2num($amount), $numChqOrOpe, 0, $user,
'',
'',
'',
null,
'',
null,
'Record payout from public/stripe/ipn.php');
293 if (!($bank_line_id_from > 0)) {
297 $bank_line_id_to = $accountto->addline($dateo, $typeto, $label, (
float)
price2num($amount), $numChqOrOpe, 0, $user,
'',
'',
'',
null,
'',
null,
'Record payout from public/stripe/ipn.php');
299 if (!($bank_line_id_to > 0)) {
305 $result = $accountfrom->add_url_line($bank_line_id_from, $bank_line_id_to, DOL_URL_ROOT.
'/compta/bank/line.php?rowid=',
'(banktransfert)',
'banktransfert');
307 if (!($result > 0)) {
311 $result = $accountto->add_url_line($bank_line_id_to, $bank_line_id_from, DOL_URL_ROOT.
'/compta/bank/line.php?rowid=',
'(banktransfert)',
'banktransfert');
313 if (!($result > 0)) {
325 $subject =
'['.$societeName.
'] Notification - Stripe payout done';
326 if (!empty($user->email)) {
337 $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');
353 $ret = $mailfile->sendfile();
360 http_response_code(500);
363} elseif ($event->type ==
'customer.source.created') {
365} elseif ($event->type ==
'customer.source.updated') {
367} elseif ($event->type ==
'customer.source.delete') {
369} elseif ($event->type ==
'customer.deleted') {
372 $sql =
"DELETE FROM ".MAIN_DB_PREFIX.
"societe_account WHERE key_account = '".
$db->escape($event->data->object->id).
"' AND site = 'stripe'";
375} elseif ($event->type ==
'payment_intent.succeeded') {
380 include_once DOL_DOCUMENT_ROOT .
'/compta/paiement/class/paiement.class.php';
381 global $stripearrayofkeysbyenv;
383 $object = $event->data->object;
384 $objectType =
$object->metadata->dol_type;
386 $ipaddress =
$object->metadata->ipaddress;
389 $currencyCodeType = strtoupper(
$object->currency);
390 $paymentmethodstripeid =
$object->payment_method;
391 $customer_id =
$object->customer;
393 $supplierinvoice_id = 0;
395 $paymentTypeCode =
"";
396 $paymentTypeCodeInDolibarr =
"";
398 $payment_amountInDolibarr = 0;
400 dol_syslog(
"Try to find a payment in database for the payment_intent id = ".$TRANSACTIONID);
401 dol_syslog(
"Try to find a payment in database for the payment_intent id = ".$TRANSACTIONID, LOG_DEBUG, 0,
'_payment');
403 $sql =
"SELECT pi.rowid, pi.fk_facture, fk_facture_fourn, fk_salary, pi.fk_prelevement_bons, pi.amount, pi.type, pi.traite";
404 $sql .=
" FROM ".MAIN_DB_PREFIX.
"prelevement_demande as pi";
405 $sql .=
" WHERE pi.ext_payment_id = '".$db->escape($TRANSACTIONID).
"'";
406 $sql .=
" AND pi.ext_payment_site = '".$db->escape($service).
"'";
408 $result =
$db->query($sql);
410 $obj =
$db->fetch_object($result);
412 if ($obj->type ==
'ban') {
414 $directdebitorcreditransfer_id = $obj->fk_prelevement_bons;
416 if ($obj->traite == 1) {
419 $invoice_id = $obj->fk_facture;
420 $supplierinvoice_id = $obj->fk_facture_fourn;
421 $salary_id = $obj->fk_salary;
422 $payment_amountInDolibarr = $obj->amount;
423 $paymentTypeCodeInDolibarr = $obj->type;
425 dol_syslog(
"Found a request in database to pay with direct debit generated (pdid = ".$pdid.
" directdebitorcreditransfer_id=".$directdebitorcreditransfer_id.
")");
426 dol_syslog(
"Found a request in database to pay with direct debit generated (pdid = ".$pdid.
" directdebitorcreditransfer_id=".$directdebitorcreditransfer_id.
")", LOG_DEBUG, 0,
'_payment');
428 dol_syslog(
"Found a request in database not yet generated (pdid = ".$pdid.
" directdebitorcreditransfer_id=".$directdebitorcreditransfer_id.
"). Was the order deleted after being sent ?", LOG_WARNING);
429 dol_syslog(
"Found a request in database not yet generated (pdid = ".$pdid.
" directdebitorcreditransfer_id=".$directdebitorcreditransfer_id.
"). Was the order deleted after being sent ?", LOG_WARNING, 0,
'_payment');
432 if ($obj->type ==
'card' || empty($obj->type)) {
434 if ($obj->traite == 0) {
436 $invoice_id = $obj->fk_facture;
437 $payment_amountInDolibarr = $obj->amount;
438 $paymentTypeCodeInDolibarr = empty($obj->type) ?
'card' : $obj->type;
440 dol_syslog(
"Found a request in database to pay with card (pdid = ".$pdid.
"). We should fix status traite to 1");
441 dol_syslog(
"Found a request in database to pay with card (pdid = ".$pdid.
"). We should fix status traite to 1", LOG_DEBUG, 0,
'_payment');
443 dol_syslog(
"Found a request in database to pay with card (pdid = ".$pdid.
") already set to traite=1. Nothing to fix.");
444 dol_syslog(
"Found a request in database to pay with card (pdid = ".$pdid.
") already set to traite=1. Nothing to fix.", LOG_DEBUG, 0,
'_payment');
448 dol_syslog(
"Payment intent ".$TRANSACTIONID.
" not found into database, so ignored.");
449 dol_syslog(
"Payment intent ".$TRANSACTIONID.
" not found into database, so ignored.", LOG_DEBUG, 0,
'_payment');
450 http_response_code(200);
451 print
"Payment intent ".$TRANSACTIONID.
" not found into database, so ignored.";
455 http_response_code(500);
456 print
$db->lasterror();
460 if ($paymentTypeCodeInDolibarr) {
463 $stripeacc = $stripearrayofkeysbyenv[$servicestatus][
'secret_key'];
466 dol_syslog(
"Get the Stripe payment object for the payment method id = ".
formatLogObject($paymentmethodstripeid), LOG_DEBUG, 0,
'_payment');
468 $s = new \Stripe\StripeClient($stripeacc);
470 $paymentmethodstripe = $s->paymentMethods->retrieve($paymentmethodstripeid);
471 $paymentTypeCode = $paymentmethodstripe->type;
472 if ($paymentTypeCode ==
"ban" || $paymentTypeCode ==
"sepa_debit") {
473 $paymentTypeCode =
"PRE";
474 } elseif ($paymentTypeCode ==
"card") {
475 $paymentTypeCode =
"CB";
478 $payment_amount = $payment_amountInDolibarr;
484 $postactionmessages = array();
486 if ($paymentTypeCode ==
"CB" && ($paymentTypeCodeInDolibarr ==
'card' || empty($paymentTypeCodeInDolibarr))) {
491 $paiement_ext_payment_id = $TRANSACTIONID.
':'.$customer_id.
'@'.$stripearrayofkeysbyenv[$servicestatus][
'publishable_key'];
492 $paiement_ext_payment_idold = $TRANSACTIONID;
493 $paiement_ext_payment_site = $service;
496 $sql =
"UPDATE ".MAIN_DB_PREFIX.
"prelevement_demande SET traite = 1 WHERE traite = 0";
497 $sql .=
" AND (type = '' OR type = 'card')";
498 $sql .=
" AND (ext_payment_id = '".$db->escape($paiement_ext_payment_id).
"' OR ext_payment_id = '".
$db->escape($paiement_ext_payment_idold).
"')";
499 $sql .=
" AND ext_payment_site = '".$db->escape($paiement_ext_payment_site).
"'";
500 $sql .=
" AND fk_facture = ".((int) $invoice_id);
501 $sql .=
" AND sourcetype = 'facture'";
503 dol_syslog(
"TODO update flag traite to 1 sql=".$sql);
504 dol_syslog(
"TODO update flag traite to 1 sql=".$sql, LOG_DEBUG, 0,
'_payment');
506 } elseif ($paymentTypeCode ==
"PRE" && $paymentTypeCodeInDolibarr ==
'ban') {
512 $paiement->datepaye = $now;
513 $paiement->date = $now;
515 $paiement->amounts = [$invoice_id => $payment_amount];
517 $paiement->multicurrency_amounts = [$invoice_id => $payment_amount];
519 $postactionmessages[] =
'Payment was done in a currency ('.$currencyCodeType.
') other than the expected currency of company ('.
getDolCurrency().
')';
520 $ispostactionok = -1;
526 $paiement->paiementcode = $paymentTypeCode;
527 $sql =
"SELECT id FROM ".MAIN_DB_PREFIX.
"c_paiement";
528 $sql .=
" WHERE code = '".$db->escape($paymentTypeCode).
"'";
529 $sql .=
" AND entity IN (".getEntity(
'c_paiement').
")";
530 $resql =
$db->query($sql);
532 $obj =
$db->fetch_object($resql);
533 $paiement->paiementid = $obj->id;
538 $paiement->num_payment =
'';
539 $paiement->note_public =
'';
540 $paiement->note_private =
'Stripe Sepa payment received by IPN service listening webhooks - ' .
dol_print_date($now,
'standard') .
' (TZ server) using servicestatus=' . $servicestatus . ($remoteipaddress ?
' remote ip ' . $remoteipaddress :
'').($ipaddress ?
' user ip ' . $ipaddress :
'') .
' - Transaction ID = ' . $TRANSACTIONID;
542 $paiement->ext_payment_id = $TRANSACTIONID.
':'.$customer_id.
'@'.$stripearrayofkeysbyenv[$servicestatus][
'publishable_key'];
543 $paiement->ext_payment_site = $service;
546 $sql =
"SELECT p.rowid FROM ".MAIN_DB_PREFIX.
"paiement as p";
547 $sql .=
" WHERE (p.ext_payment_id = '".$db->escape($paiement->ext_payment_id).
"' OR p.ext_payment_id = '".
$db->escape($TRANSACTIONID).
"')";
548 $sql .=
" AND p.ext_payment_site = '".$db->escape($paiement->ext_payment_site).
"'";
549 $result =
$db->query($sql);
551 if (
$db->num_rows($result)) {
553 dol_syslog(
'* Payment for ext_payment_id '.$paiement->ext_payment_id.
' already done. We do not recreate the payment');
554 dol_syslog(
'* Payment for ext_payment_id '.$paiement->ext_payment_id.
' already done. We do not recreate the payment', LOG_DEBUG, 0,
'_payment');
560 if (!$error && !$ispaymentdone) {
561 dol_syslog(
'* Record payment type PRE for invoice id ' . $invoice_id .
'. It includes closing of invoice and regenerating document.');
562 dol_syslog(
'* Record payment type PRE for invoice id ' . $invoice_id .
'. It includes closing of invoice and regenerating document.', LOG_DEBUG, 0,
'_payment');
565 $thirdpartyofpayment =
null;
567 $paiement_id = $paiement->create($user, 1, $thirdpartyofpayment);
568 if ($paiement_id < 0) {
569 $postactionmessages[] = $paiement->error . ($paiement->error ?
' ' :
'') . implode(
"<br>\n", $paiement->errors);
570 $ispostactionok = -1;
573 dol_syslog(
"Failed to create the payment for invoice id " . $invoice_id);
574 dol_syslog(
"Failed to create the payment for invoice id " . $invoice_id, LOG_DEBUG, 0,
'_payment');
576 $postactionmessages[] =
'Payment created';
578 dol_syslog(
"The payment has been created for invoice id " . $invoice_id);
579 dol_syslog(
"The payment has been created for invoice id " . $invoice_id, LOG_DEBUG, 0,
'_payment');
586 $sql =
"SELECT p.rowid, p.fk_bank FROM ".MAIN_DB_PREFIX.
"paiement as p";
587 $sql .=
" WHERE (p.ext_payment_id = '".$db->escape($paiement->ext_payment_id).
"' OR p.ext_payment_id = '".
$db->escape($TRANSACTIONID).
"')";
588 $sql .=
" AND p.ext_payment_site = '".$db->escape($paiement->ext_payment_site).
"'";
589 $sql .=
" AND p.fk_bank <> 0";
590 $result =
$db->query($sql);
592 if (
$db->num_rows($result)) {
594 $obj =
$db->fetch_object($result);
595 dol_syslog(
'* Payment already linked to bank record '.$obj->fk_bank.
' . We do not recreate the link');
596 dol_syslog(
'* Payment already linked to bank record '.$obj->fk_bank.
' . We do not recreate the link', LOG_DEBUG, 0,
'_payment');
599 if (!$ispaymentdone) {
601 dol_syslog(
'* Add payment to bank', LOG_DEBUG, 0,
'_payment');
604 $paymentmethod =
'stripe';
607 if ($bankaccountid > 0) {
608 $label =
'(CustomerInvoicePayment)';
609 $result = $paiement->addPaymentToBank($user,
'payment', $label, $bankaccountid, $customer_id,
'');
611 $postactionmessages[] = $paiement->error . ($paiement->error ?
' ' :
'') . implode(
"<br>\n", $paiement->errors);
612 $ispostactionok = -1;
615 $postactionmessages[] =
'Bank transaction of payment created (by ipn.php file)';
618 $postactionmessages[] =
'Setup of bank account to use in module ' . $paymentmethod .
' was not set. No way to record the payment.';
619 $ispostactionok = -1;
628 $sql =
"SELECT dp.fk_prelevement_bons as idbon";
629 $sql .=
" FROM ".MAIN_DB_PREFIX.
"prelevement_demande as dp";
630 $sql .=
" JOIN ".MAIN_DB_PREFIX.
"prelevement_bons as pb";
631 $sql .=
" ON pb.rowid = dp.fk_prelevement_bons";
632 $sql .=
" WHERE dp.fk_facture = ".((int) $invoice_id);
633 $sql .=
" AND dp.sourcetype = 'facture'";
634 $sql .=
" AND (dp.ext_payment_id = '".$db->escape($paiement->ext_payment_id).
"' OR dp.ext_payment_id = '".
$db->escape($TRANSACTIONID).
"')";
635 $sql .=
" AND dp.traite = 1";
636 $sql .=
" AND statut = ".((int) $bon::STATUS_TRANSFERED);
637 $result =
$db->query($sql);
639 if (
$db->num_rows($result)) {
640 $obj =
$db->fetch_object($result);
641 $idbon = $obj->idbon;
642 dol_syslog(
'* Prelevement must be set to credited');
643 dol_syslog(
'* Prelevement must be set to credited', LOG_DEBUG, 0,
'_payment');
645 dol_syslog(
'* Prelevement not found or already credited');
646 dol_syslog(
'* Prelevement not found or already credited', LOG_DEBUG, 0,
'_payment');
649 $postactionmessages[] =
$db->lasterror();
650 $ispostactionok = -1;
654 if (!$error && !empty($idbon)) {
655 $sql =
"UPDATE ".MAIN_DB_PREFIX.
"prelevement_bons";
656 $sql .=
" SET fk_user_credit = ".((int) $user->id);
657 $sql .=
", statut = ".((int) $bon::STATUS_CREDITED);
658 $sql .=
", date_credit = '".$db->idate($now).
"'";
659 $sql .=
", credite = 1";
660 $sql .=
" WHERE rowid = ".((int) $idbon);
661 $sql .=
" AND statut = ".((int) $bon::STATUS_TRANSFERED);
663 $result =
$db->query($sql);
665 $postactionmessages[] =
$db->lasterror();
666 $ispostactionok = -1;
671 if (!$error && !empty($idbon)) {
672 $sql =
"UPDATE ".MAIN_DB_PREFIX.
"prelevement_lignes";
673 $sql .=
" SET statut = 2";
674 $sql .=
" WHERE fk_prelevement_bons = ".((int) $idbon);
675 $result =
$db->query($sql);
677 $postactionmessages[] =
$db->lasterror();
678 $ispostactionok = -1;
688 http_response_code(500);
696 $labeltouse =
getDolGlobalString(
'STRIPE_IPN_SEND_EMAIL_ON_DIRECT_DEBIT_CONFIRMATION');
700 $invoice->fetch($invoice_id);
701 $invoice->fetch_thirdparty();
705 $outputlangs->setDefaultLang(empty($invoice->thirdparty->default_lang) ?
$mysoc->default_lang : $invoice->thirdparty->default_lang);
706 $outputlangs->loadLangs(array(
"main",
"members",
"bills"));
709 $arraydefaultmessage =
null;
711 include_once DOL_DOCUMENT_ROOT.
'/core/class/html.formmail.class.php';
714 $arraydefaultmessage = $formmail->getEMailTemplate(
$db,
'facture_send', $user, $outputlangs, 0, 1, $labeltouse);
718 $subject =
'['.$appli.
'] Invoice direct debit payment recevied';
719 $msg =
'An invoice direct debit payment for invoice '.$invoice->ref.
' has been recevied';
720 if (is_object($arraydefaultmessage) && $arraydefaultmessage->id > 0) {
721 $subject = $arraydefaultmessage->topic;
722 $msg = $arraydefaultmessage->content;
725 $substitutionarray = getCommonSubstitutionArray($outputlangs, 0,
null, $invoice);
731 $foundcontract =
null;
732 $invoice->fetchObjectLinked(
null,
'',
null,
'',
'OR', 1,
'sourcetype', 1);
734 if (is_array($invoice->linkedObjects[
'contrat']) && count($invoice->linkedObjects[
'contrat']) > 0) {
736 foreach ($invoice->linkedObjects[
'contrat'] as $contract) {
738 '@phan-var-force Contrat $contract';
739 $substitutionarray[
'__CONTRACT_REF__'] = $contract->ref_customer;
740 $substitutionarray[
'__REFCLIENT__'] = $contract->ref_customer;
741 $substitutionarray[
'__REF_CLIENT__'] = $contract->ref_customer;
742 $substitutionarray[
'__REF_CUSTOMER__'] = $contract->ref_customer;
743 $foundcontract = $contract;
748 dol_syslog(
'__DIRECTDOWNLOAD_URL_INVOICE__='.$substitutionarray[
'__DIRECTDOWNLOAD_URL_INVOICE__']);
754 $listofpaths = array();
755 $listofnames = array();
756 $listofmimes = array();
773 $trackid =
'inv'.$invoice->id;
774 $moreinheader =
'X-Dolibarr-Info: public stripe ipn.php'.
"\r\n";
776 if (!empty($invoice->thirdparty->array_options[
'options_emailccinvoice'])) {
777 dol_syslog(
"We add the recipient ".$invoice->thirdparty->array_options[
'options_emailccinvoice'].
" as CC", LOG_DEBUG);
778 $addr_cc = $invoice->thirdparty->array_options[
'options_emailccinvoice'];
782 include_once DOL_DOCUMENT_ROOT.
'/core/class/CMailFile.class.php';
783 $mailfile =
new CMailFile($subjecttosend, $invoice->thirdparty->email, $from, $texttosend, $listofpaths, $listofmimes, $listofnames, $addr_cc,
'', 0, -1,
'',
'', $trackid, $moreinheader);
784 if (empty($mailfile->error) && $mailfile->sendfile()) {
787 dol_syslog(
"Option STRIPE_IPN_SEND_EMAIL_ON_DIRECT_DEBIT_CONFIRMATION: Email sent");
788 dol_syslog(
"Option STRIPE_IPN_SEND_EMAIL_ON_DIRECT_DEBIT_CONFIRMATION: Email sent", LOG_DEBUG, 0,
'_payment');
790 $errmsg =
'Option STRIPE_IPN_SEND_EMAIL_ON_DIRECT_DEBIT_CONFIRMATION: '.$langs->trans(
"ErrorFailedToSendMail", $from, $invoice->thirdparty->email).
'. '.$mailfile->error;
793 dol_syslog($errmsg, LOG_WARNING, 0,
'_payment');
798 dol_syslog(
"Option STRIPE_IPN_SEND_EMAIL_ON_DIRECT_DEBIT_CONFIRMATION not set to the template label. No email sent.");
799 dol_syslog(
"Option STRIPE_IPN_SEND_EMAIL_ON_DIRECT_DEBIT_CONFIRMATION not set to the template label. No email sent.", LOG_DEBUG, 0,
'_payment');
802 dol_syslog(
"The payment mode of this payment is ".$paymentTypeCode.
" in Stripe and ".$paymentTypeCodeInDolibarr.
" in Dolibarr. This case is not managed by the IPN");
803 dol_syslog(
"The payment mode of this payment is ".$paymentTypeCode.
" in Stripe and ".$paymentTypeCodeInDolibarr.
" in Dolibarr. This case is not managed by the IPN", LOG_DEBUG, 0,
'_payment');
806 dol_syslog(
"Nothing to do in database because we don't know paymentTypeIdInDolibarr");
807 dol_syslog(
"Nothing to do in database because we don't know paymentTypeIdInDolibarr", LOG_DEBUG, 0,
'_payment');
809} elseif ($event->type ==
'payment_intent.payment_failed') {
811 dol_syslog(
"A try to make a payment has failed");
812 dol_syslog(
"A try to make a payment has failed", LOG_DEBUG, 0,
'_payment');
814 $object = $event->data->object;
815 $ipaddress =
$object->metadata->ipaddress;
817 $currencyCodeType = strtoupper(
$object->currency);
818 $paymentmethodstripeid =
$object->payment_method;
819 $customer_id =
$object->customer;
821 $chargesdataarray = array();
827 $objpaymentmodetype =
'';
828 if (!empty(
$object->charges)) {
829 $chargesdataarray =
$object->charges->data;
830 foreach ($chargesdataarray as $chargesdata) {
831 $objpayid = $chargesdata->id;
832 $objpaydesc = $chargesdata->description;
834 if ($chargesdata->metadata->dol_type ==
'facture') {
835 $objinvoiceid = $chargesdata->metadata->dol_id;
837 $objerrcode = $chargesdata->outcome->reason;
838 $objerrmessage = $chargesdata->outcome->seller_message;
840 $objpaymentmodetype = $chargesdata->payment_method_details->type;
844 if (!empty(
$object->last_payment_error)) {
846 $objpayid =
$object->latest_charge;
847 $objpaydesc =
$object->description;
849 if (
$object->metadata->dol_type ==
'facture') {
850 $objinvoiceid =
$object->metadata->dol_id;
852 $objerrcode = empty(
$object->last_payment_error->code) ?
$object->last_payment_error->decline_code :
$object->last_payment_error->code;
853 $objerrmessage =
$object->last_payment_error->message;
855 $objpaymentmodetype =
$object->last_payment_error->payment_method->type;
858 dol_syslog(
"objpayid=".$objpayid.
" objpaymentmodetype=".$objpaymentmodetype.
" objerrcode=".$objerrcode);
859 dol_syslog(
"objpayid=".$objpayid.
" objpaymentmodetype=".$objpaymentmodetype.
" objerrcode=".$objerrcode, LOG_DEBUG, 0,
'_payment');
862 if ($objpaymentmodetype ==
'sepa_debit') {
865 require_once DOL_DOCUMENT_ROOT.
'/comm/action/class/actioncomm.class.php';
868 if ($objinvoiceid > 0) {
869 require_once DOL_DOCUMENT_ROOT.
'/compta/facture/class/facture.class.php';
871 $invoice->fetch($objinvoiceid);
873 $actioncomm->userownerid = 0;
874 $actioncomm->percentage = -1;
876 $actioncomm->type_code =
'AC_OTH_AUTO';
877 $actioncomm->code =
'AC_PAYMENT_STRIPE_IPN_SEPA_KO';
879 $actioncomm->datep = $now;
880 $actioncomm->datef = $now;
882 $actioncomm->socid = $invoice->socid;
883 $actioncomm->fk_project = $invoice->fk_project;
884 $actioncomm->elementid = $invoice->id;
885 $actioncomm->elementtype =
'invoice';
889 $actioncomm->note_private =
'Stripe Sepa payment error received by IPN service listening webhooks - ' .
dol_print_date($now,
'standard') .
' (TZ server) using servicestatus=' . $servicestatus . ($remoteipaddress ?
' remote ip ' . $remoteipaddress :
'').($ipaddress ?
' user ip ' . $ipaddress :
'').
' - Payment id '.$objpayid.
' after SEPA payment request '.$objpaydesc.
'<br>Error code is: '.$objerrcode.
'<br>Error message is: '.$objerrmessage;
890 $actioncomm->label =
'Payment error (SEPA Stripe)';
892 $result = $actioncomm->create($user);
895 dol_syslog($actioncomm->error, LOG_ERR, 0,
'_payment');
910 http_response_code(500);
914} elseif ($event->type ==
'checkout.session.completed') {
916} elseif ($event->type ==
'payment_method.attached') {
921 require_once DOL_DOCUMENT_ROOT.
'/societe/class/companypaymentmode.class.php';
922 require_once DOL_DOCUMENT_ROOT.
'/societe/class/societeaccount.class.php';
927 $idthirdparty = $societeaccount->getThirdPartyID(
$db->escape($event->data->object->customer),
'stripe', $servicestatus);
928 if ($idthirdparty > 0) {
931 $companypaymentmode->stripe_card_ref = $event->data->object->id;
932 $companypaymentmode->fk_soc = $idthirdparty;
933 $companypaymentmode->bank =
null;
934 $companypaymentmode->label =
'';
935 $companypaymentmode->number = $event->data->object->id;
936 $companypaymentmode->last_four = $event->data->object->card->last4;
937 $companypaymentmode->card_type = $event->data->object->card->branding;
939 $companypaymentmode->owner_name = $event->data->object->billing_details->name;
940 $companypaymentmode->proprio = $companypaymentmode->owner_name;
942 $companypaymentmode->exp_date_month = (int) $event->data->object->card->exp_month;
943 $companypaymentmode->exp_date_year = (int) $event->data->object->card->exp_year;
944 $companypaymentmode->cvn =
null;
945 $companypaymentmode->datec = $event->data->object->created;
946 $companypaymentmode->default_rib = 0;
947 $companypaymentmode->type = $event->data->object->type;
948 $companypaymentmode->country_code = $event->data->object->card->country;
949 $companypaymentmode->status = $servicestatus;
955 $result = $companypaymentmode->create($user);
963 http_response_code(500);
968} elseif ($event->type ==
'payment_method.updated') {
973 require_once DOL_DOCUMENT_ROOT.
'/societe/class/companypaymentmode.class.php';
975 $companypaymentmode->fetch(0,
'', 0,
'',
" AND stripe_card_ref = '".
$db->escape($event->data->object->id).
"'");
976 if ($companypaymentmode->id > 0) {
978 $companypaymentmode->bank =
null;
979 $companypaymentmode->label =
'';
980 $companypaymentmode->number =
$db->escape($event->data->object->id);
981 $companypaymentmode->last_four =
$db->escape($event->data->object->card->last4);
982 $companypaymentmode->proprio =
$db->escape($event->data->object->billing_details->name);
983 $companypaymentmode->owner_name =
$db->escape($event->data->object->billing_details->name);
984 $companypaymentmode->exp_date_month = (int) $event->data->object->card->exp_month;
985 $companypaymentmode->exp_date_year = (int) $event->data->object->card->exp_year;
986 $companypaymentmode->cvn =
null;
987 $companypaymentmode->datec = (int) $event->data->object->created;
988 $companypaymentmode->default_rib = 0;
989 $companypaymentmode->type =
$db->escape($event->data->object->type);
990 $companypaymentmode->country_code =
$db->escape($event->data->object->card->country);
991 $companypaymentmode->status = $servicestatus;
995 $result = $companypaymentmode->update($user);
1005 http_response_code(500);
1009} elseif ($event->type ==
'payment_method.detached') {
1012 $sql =
"DELETE FROM ".MAIN_DB_PREFIX.
"societe_rib WHERE number = '".
$db->escape($event->data->object->id).
"' and status = ".((int) $servicestatus);
1015} elseif ($event->type ==
'charge.succeeded') {
1017} elseif ($event->type ==
'charge.failed') {
1019} elseif (($event->type ==
'source.chargeable') && ($event->data->object->type ==
'three_d_secure') && ($event->data->object->three_d_secure->authenticated ==
true)) {
1021} elseif ($event->type ==
'charge.dispute.closed') {
1025} elseif ($event->type ==
'charge.dispute.funds_withdrawn') {
1030 global $stripearrayofkeysbyenv;
1033 $object = $event->data->object;
1034 $TRANSACTIONID =
$object->payment_intent;
1035 $ipaddress =
$object->metadata->ipaddress;
1038 $currencyCodeType = strtoupper(
$object->currency);
1039 $paymentmethodstripeid =
$object->payment_method;
1040 $customer_id =
$object->customer;
1042 $amountdisputestripe =
$object->amount;
1043 $amountdispute = $stripe->convertAmount($amountdisputestripe, $currencyCodeType, 1);
1044 $statusdispute =
$object->status;
1047 if (isset($stripearrayofkeysbyenv[$servicestatus][
'publishable_key'])) {
1048 $pkey = $stripearrayofkeysbyenv[$servicestatus][
'publishable_key'];
1050 $LONGTRANSACTIONID = $TRANSACTIONID.
':'.$customer_id.
'@'.$pkey;
1053 $balance_transactions_array =
$object->balance_transactions;
1055 if (!empty($balance_transactions_array) && is_array($balance_transactions_array)) {
1056 foreach ($balance_transactions_array as $tmpval) {
1057 if (isset($tmpval[
'fee'])) {
1058 $feesstripe += (int) $tmpval[
'fee'];
1062 $fees = $stripe->convertAmount($feesstripe, $currencyCodeType, 1);
1065 $paymentTypeCode =
"";
1066 $paymentTypeCodeInDolibarr =
"";
1067 $payment_amount = 0;
1068 $payment_amountInDolibarr = 0;
1070 dol_syslog(
"Try to find the payment in database for the payment_intent id = ".$TRANSACTIONID);
1071 dol_syslog(
"Try to find the payment in database for the payment_intent id = ".$TRANSACTIONID, LOG_DEBUG, 0,
'_payment');
1073 $sql =
"SELECT pi.rowid, pi.fk_facture, pi.fk_prelevement_bons, pi.amount, pi.type, pi.traite";
1074 $sql .=
" FROM ".MAIN_DB_PREFIX.
"prelevement_demande as pi";
1076 $sql .=
" WHERE (pi.ext_payment_id = '".$db->escape($LONGTRANSACTIONID).
"' OR pi.ext_payment_id = '".
$db->escape($TRANSACTIONID).
"')";
1077 $sql .=
" AND pi.ext_payment_site = '".$db->escape($service).
"'";
1079 $result =
$db->query($sql);
1081 $obj =
$db->fetch_object($result);
1083 if ($obj->type ==
'ban') {
1085 $pdid = $obj->rowid;
1086 $invoice_id = $obj->fk_facture;
1087 $directdebitorcreditransfer_id = $obj->fk_prelevement_bons;
1088 $payment_amountInDolibarr = $obj->amount;
1089 $paymentTypeCodeInDolibarr = $obj->type;
1091 dol_syslog(
"Found the payment intent for ban in database (pdid = ".$pdid.
" directdebitorcreditransfer_id=".$directdebitorcreditransfer_id.
")");
1092 dol_syslog(
"Found the payment intent for ban in database (pdid = ".$pdid.
" directdebitorcreditransfer_id=".$directdebitorcreditransfer_id.
")", LOG_DEBUG, 0,
'_payment');
1094 if ($obj->type ==
'card' || empty($obj->type)) {
1096 $pdid = $obj->rowid;
1097 $invoice_id = $obj->fk_facture;
1098 $directdebitorcreditransfer_id = 0;
1099 $payment_amountInDolibarr = $obj->amount;
1100 $paymentTypeCodeInDolibarr = empty($obj->type) ?
'card' : $obj->type;
1102 dol_syslog(
"Found the payment intent for card in database (pdid = ".$pdid.
" directdebitorcreditransfer_id=".$directdebitorcreditransfer_id.
")");
1103 dol_syslog(
"Found the payment intent for card in database (pdid = ".$pdid.
" directdebitorcreditransfer_id=".$directdebitorcreditransfer_id.
")", LOG_DEBUG, 0,
'_payment');
1106 dol_syslog(
"Payment intent ".$TRANSACTIONID.
" not found into database, so ignored.");
1107 dol_syslog(
"Payment intent ".$TRANSACTIONID.
" not found into database, so ignored.", LOG_DEBUG, 0,
'_payment');
1108 http_response_code(200);
1109 print
"Payment intent ".$TRANSACTIONID.
" not found into database, so ignored.";
1113 http_response_code(500);
1114 print
$db->lasterror();
1119 dol_syslog(
"objinvoiceid=".$invoice_id, LOG_DEBUG, 0,
'_payment');
1121 $tmpinvoice->fetch($invoice_id);
1122 $tmpinvoice->fetch_thirdparty();
1124 dol_syslog(
"The payment disputed has the amount ".$amountdispute.
", fees of ".$fees.
" and the invoice has ".$payment_amountInDolibarr);
1125 dol_syslog(
"The payment disputed has the amount ".$amountdispute.
", fees of ".$fees.
" and the invoice has ".$payment_amountInDolibarr, LOG_DEBUG, 0,
'_payment');
1139 if ($statusdispute ==
'needs_response') {
1148 $errormsg = $tmpinvoice->error.implode(
', ', $tmpinvoice->errors);
1179 $errormsg = $tmpinvoice->error.implode(
', ', $tmpinvoice->errors);
1186 dol_syslog(
"The dispute_status of invoice ".$tmpinvoice->ref.
" has been modified to 1");
1187 dol_syslog(
"The dispute_status of invoice ".$tmpinvoice->ref.
" has been modified to 1", LOG_DEBUG, 0,
'_payment');
1189 http_response_code(200);
1190 print
"Payment dispute received for ".$TRANSACTIONID.
". We have changed the status of dispute_status to 1 for invoice ".$tmpinvoice->ref;
1195 dol_syslog(
"Technicalerror ".
$db->lasterror().
" - ".$errormsg, LOG_ERR);
1196 dol_syslog(
"Technicalerror ".
$db->lasterror().
" - ".$errormsg, LOG_ERR, 0,
'_payment');
1198 http_response_code(500);
1199 print
$db->lasterror();
1205 $accountfrom->fetch(
getDolGlobalInt(
'STRIPE_BANK_ACCOUNT_FOR_PAYMENTS'));
1211 $amounts[$tmpinvoice->id] = -1 * $payment_amountInDolibarr;
1213 $paiement->datepaye =
dol_now();
1214 $paiement->amounts = $amounts;
1220 $paiement->num_payment =
$object->id;
1222 $paiement->note_private =
'Stripe fund withdrawn message received by IPN service listening webhooks - ' .
dol_print_date($now,
'standard') .
' (TZ server) using servicestatus=' . $servicestatus . ($remoteipaddress ?
' remote ip ' . $remoteipaddress :
'').($ipaddress ?
' user ip ' . $ipaddress :
'');
1223 $paiement->note_private .=
' - Fund withdrawn by bank with id='.$object->id.
'. Reason: '.$reason.
'. A fee of '.$fees.
' may have been charged by Stripe.';
1225 $paiement->fk_account = $accountfrom->id;
1227 $paiement->ext_payment_id =
$object->payment_intent;
1228 $paiement->ext_payment_site = $service;
1232 $alreadytransferedinaccounting = $tmpinvoice->getVentilExportCompta();
1234 dol_syslog(
"The invoice has alreadytransferedinaccounting=".$alreadytransferedinaccounting);
1235 dol_syslog(
"The invoice has alreadytransferedinaccounting=".$alreadytransferedinaccounting, LOG_DEBUG, 0,
'_payment');
1250 $errormsg = $tmpinvoice->error.implode(
', ', $tmpinvoice->errors);
1259 $errormsg = $tmpinvoice->error.implode(
', ', $tmpinvoice->errors);
1264 dol_syslog(
"The dispute_status of invoice ".$tmpinvoice->ref.
" has been modified to 1");
1265 dol_syslog(
"The dispute_status of invoice ".$tmpinvoice->ref.
" has been modified to 1", LOG_DEBUG, 0,
'_payment');
1270 $withdrawn_payment_already_exists =
true;
1271 $sql =
"SELECT p.rowid, p.ref";
1272 $sql .=
" FROM ".MAIN_DB_PREFIX.
"paiement as p";
1273 $sql .=
" WHERE p.ext_payment_id = '".$db->escape($paiement->ext_payment_id).
"'";
1274 $sql .=
" AND p.ext_payment_site = '".$db->escape($service).
"'";
1276 $tmpresql =
$db->query($sql);
1278 $obj =
$db->fetch_object($tmpresql);
1280 $withdrawn_payment_already_exists =
false;
1281 dol_syslog(
"No withdraw payment already exists", LOG_DEBUG);
1283 dol_syslog(
"A withdraw payment already exists", LOG_DEBUG);
1287 if (!$error && !$alreadytransferedinaccounting && !$withdrawn_payment_already_exists) {
1288 if ($paiement->fk_account > 0) {
1292 dol_syslog(
"We try to record the payment", LOG_DEBUG, 0,
'_payment');
1294 $paiement_id = $paiement->create($user, 0, $tmpinvoice->thirdparty);
1295 if ($paiement_id < 0) {
1296 $errormsg = $paiement->error.implode(
', ', $paiement->errors);
1299 $banklineid = $paiement->addPaymentToBank($user,
'payment',
'IPN Stripe dispute funds withdrawn', $paiement->fk_account,
'',
'', 1,
'',
'');
1300 if ($banklineid < 0) {
1301 $errormsg = $paiement->error.implode(
', ', $paiement->errors);
1306 dol_syslog(
"No bank account defined to record payment so no payment recorded");
1307 dol_syslog(
"No bank account defined to record payment so no payment recorded", LOG_DEBUG, 0,
'_payment');
1321 dol_syslog(
"Invoice status updated and/or Revert payment created", LOG_WARNING);
1322 dol_syslog(
"Invoice status updated and/or Revert payment created", LOG_WARNING, 0,
'_payment');
1326 dol_syslog(
"Error - Return HTTP 500 - ".$errormsg, LOG_ERR);
1327 dol_syslog(
"Error - Return HTTP 500 - ".$errormsg, LOG_ERR, 0,
'_payment');
1329 http_response_code(500);
if(! $sortfield) if(! $sortorder) $object
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 agenda events (actions)
Class to manage withdrawal receipts.
Class to send emails (with attachments or not) Usage: $mailfile = new CMailFile($subject,...
Class for CompanyPaymentMode.
Class to manage invoices.
const STATUS_VALIDATED
Validated (need to be paid)
const STATUS_CLOSED
Classified paid.
Class to manage payments of customer invoices.
Class for SocieteAccount.
Stripe class @TODO No reason to extend CommonObject.
Class to manage translations.
Class to manage Dolibarr users.
dol_now($mode='gmt')
Return date for now.
dol_getIdFromCode($db, $key, $tablename, $fieldkey='code', $fieldid='id', $entityfilter=0, $filters='', $useCache=true)
Return an id or code from a code or id.
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
dolChmod($filepath, $newmask='')
Change mod of a file.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
dolGetFirstLastname($firstname, $lastname, $nameorder=-1)
Return firstname and lastname in correct order.
getDolCurrency()
Return the main currency ('EUR', 'USD', ...)
complete_substitutions_array(&$substitutionarray, $outputlangs, $object=null, $parameters=null, $callfunc="completesubstitutionarray")
Complete the $substitutionarray with more entries coming from external module that had set the "subst...
make_substitutions($text, $substitutionarray, $outputlangs=null, $converttextinhtmlifnecessary=0)
Make substitution into a text string, replacing keys with vals from $substitutionarray (oldval=>newva...
if(!function_exists( 'utf8_encode')) if(!function_exists('utf8_decode')) if(!function_exists( 'str_starts_with')) if(!function_exists('str_ends_with')) if(!function_exists( 'str_contains')) formatLogObject($data)
Return a string serialized to be output on log with dol_syslog() An option allow to output log in one...
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs=null, $encodetooutput=false, $decorate=0)
Output date in a string format according to outputlangs (or langs if not defined).
getUserRemoteIP($trusted=0)
Return the real IP of remote user.
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
isModEnabled($module)
Is Dolibarr module enabled.
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.
print $langs trans('Date')." left Ref Label right Qty right Price right TotalHT right TotalTTC right right right right right right right right right centpercent right TotalHT right n right VAT right n right TotalVAT right n No sujeto a RE IRPF right TotalLT1 right n right TotalLT2 right n right TotalTTC right n takeposcustomercurrency takeposcustomercurrency takeposcustomercurrency takeposcustomercurrency right TotalTTC takeposcustomercurrency right takeposcustomercurrency n right Paid right PaymentTypeShortLIQ right SELECT p pos_change as p datep as date
httponly_accessforbidden($message='1', $http_response_code=403, $stringalreadysanitized=0)
Show a message to say access is forbidden and stop program.