From 5405d92c8c77ff31e0a79500657c66b8ec4a0c31 Mon Sep 17 00:00:00 2001
From: "Matthew Wire (MJW Consulting)" <mjw@mjwconsult.co.uk>
Date: Thu, 18 Oct 2018 12:59:01 +0100
Subject: [PATCH] Delay IPN processing so we don't conflict with browser

---
 CRM/Core/Payment/StripeIPN.php | 29 +++++++++++++++++++++++++++++
 1 file changed, 29 insertions(+)

diff --git a/CRM/Core/Payment/StripeIPN.php b/CRM/Core/Payment/StripeIPN.php
index bbc170ec..24633704 100644
--- a/CRM/Core/Payment/StripeIPN.php
+++ b/CRM/Core/Payment/StripeIPN.php
@@ -192,6 +192,31 @@ class CRM_Core_Payment_StripeIPN extends CRM_Core_Payment_BaseIPN {
     return $value;
   }
 
+  /**
+   * Get a lock so we don't process browser return & ipn return at the same time.
+   *
+   * Paralell processing notably results in 2 receipts.
+   *
+   * Currently mysql 5.7.5+ will process a cross-session lock. If we can't do that
+   * then we should be tardy on the processing of the ipn response.
+   *
+   * @return bool
+   */
+  protected function getLock() {
+    $mysqlVersion = CRM_Core_DAO::singleValueQuery('SELECT VERSION()');
+    if (stripos($mysqlVersion, 'mariadb') === FALSE
+      && version_compare($mysqlVersion, '5.7.5', '>=')
+    ) {
+      $lock = Civi::lockManager()->acquire('data.contribute.contribution.' . $this->transaction_id);
+      return $lock->isAcquired();
+    }
+    if (empty(CRM_Core_Session::singleton()->getLoggedInContactID())) {
+      // So far the best way of telling the difference is the session.
+      sleep(30);
+    }
+    return TRUE;
+  }
+
   /**
    * @return bool
    * @throws \CRM_Core_Exception
@@ -449,6 +474,10 @@ class CRM_Core_Payment_StripeIPN extends CRM_Core_Payment_BaseIPN {
    * @throws \CiviCRM_API3_Exception
    */
   public function setInfo() {
+    if (!$this->getLock()) {
+      return;
+    }
+
     $this->test_mode = $this->retrieve('test_mode', 'Integer');
 
     $abort = FALSE;
-- 
GitLab