Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
diff --git a/app/addons/paypal/controllers/common/payment_notification.post.php b/app/addons/paypal/controllers/common/payment_notification.post.php
index a5248fa..d4d9432 100644
--- a/app/addons/paypal/controllers/common/payment_notification.post.php
+++ b/app/addons/paypal/controllers/common/payment_notification.post.php
@@ -20,23 +20,15 @@ if (!defined('BOOTSTRAP')) { die('Access denied'); }
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
if ($mode == 'paypal_ipn') {
if (!empty($_REQUEST['custom'])) {
- unset($_REQUEST['dispatch']);
-
- $result = '';
- $_REQUEST['cmd'] = '_notify-validate';
- $data = array_merge(array('cmd' => '_notify-validate'), $_REQUEST);
- //the txn_type variable absent in case of refund
- if (isset($data['txn_type']) && in_array($data['txn_type'], array('cart', 'express_checkout', 'web_accept')) || !isset($data['txn_type'])) {
- $order_ids = fn_pp_get_ipn_order_ids($data);
- $mode = fn_pp_get_mode(reset($order_ids));
- $url = ($mode == 'test') ? 'https://www.sandbox.paypal.com/cgi-bin/webscr' : 'https://www.paypal.com/cgi-bin/webscr';
- $result = Http::post($url, $data);
- }
+
+ list($result, $order_ids, $data) = fn_pp_validate_ipn_payload($_REQUEST);
if ($result == 'VERIFIED') {
fn_define('ORDER_MANAGEMENT', true);
foreach($order_ids as $order_id) {
fn_process_paypal_ipn($order_id, $data);
+ // unlock order after processing IPN
+ fn_pp_set_orders_lock($order_id, false);
}
}
}
diff --git a/app/addons/paypal/func.php b/app/addons/paypal/func.php
index a5ea5b2..ca05037 100644
--- a/app/addons/paypal/func.php
+++ b/app/addons/paypal/func.php
@@ -1078,3 +1078,88 @@ function fn_paypal_user_init(&$auth, &$user_info, &$first_init)
}
}
}
+
+/**
+ * Gets list of order identifiers whose IPN is currently processing.
+ *
+ * @return array Order identifiers
+ */
+function fn_pp_get_locked_orders()
+{
+ $orders_ids = fn_get_storage_data('paypal_locked_orders');
+
+ if ($orders_ids) {
+ return explode(',', $orders_ids);
+ }
+
+ return array();
+}
+
+/**
+ * Marks or unmarks orders as processors of IPN.
+ *
+ * @param array $orders_ids Orders' identifiers
+ * @param bool $are_locked True IPN for the orders is currently processing, false if processing is finished
+ * @param array $locked_orders_ids Currently locked orders (leave empty to fetch from the DB)
+ * @return array
+ */
+function fn_pp_set_orders_lock($orders_ids = array(), $are_locked = true, $locked_orders_ids = array())
+{
+ $orders_ids = (array)$orders_ids;
+
+ if (!$locked_orders_ids) {
+ $locked_orders_ids = fn_pp_get_locked_orders();
+ }
+
+ if ($are_locked) {
+ $orders_ids = array_unique(array_merge($locked_orders_ids, $orders_ids));
+ } else {
+ $orders_ids = array_diff($locked_orders_ids, $orders_ids);
+ }
+
+ fn_set_storage_data('paypal_locked_orders', implode(',', $orders_ids), true);
+
+ return array_values($orders_ids);
+}
+
+/**
+ * Checks if IPN for the order is currently processing.
+ *
+ * @param int $order_id Order identifier
+ *
+ * @return bool True if IPN is processing, false otherwise
+ */
+function fn_pp_is_order_locked($order_id = 0)
+{
+ $locked_order_ids = fn_pp_get_locked_orders();
+
+ return in_array($order_id, $locked_order_ids);
+}
+
+/**
+ * Checks if IPN is sent by PayPal.
+ *
+ * @param array $data Payload
+ *
+ * @return array Validation result, orders processed in the IPN and payload for ::fn_process_paypal_ipn()
+ */
+function fn_pp_validate_ipn_payload($data)
+{
+ $result = '';
+ $order_ids = array();
+
+ unset($data['dispatch']);
+ $data['cmd'] = '_notify-validate';
+ $data = array_merge(array('cmd' => '_notify-validate'), $data);
+ //the txn_type variable absent in case of refund
+ if (isset($data['txn_type']) && in_array($data['txn_type'], array('cart', 'express_checkout', 'web_accept')) || !isset($data['txn_type'])) {
+ $order_ids = fn_pp_get_ipn_order_ids($data);
+ // lock orders while processing IPN
+ fn_pp_set_orders_lock($order_ids, true);
+ $mode = fn_pp_get_mode(reset($order_ids));
+ $url = ($mode == 'test') ? 'https://www.sandbox.paypal.com/cgi-bin/webscr' : 'https://www.paypal.com/cgi-bin/webscr';
+ $result = Http::post($url, $data);
+ }
+
+ return array($result, $order_ids, $data);
+}
\ No newline at end of file
diff --git a/app/addons/paypal/payments/paypal.php b/app/addons/paypal/payments/paypal.php
index 45664b4..dca962b 100644
--- a/app/addons/paypal/payments/paypal.php
+++ b/app/addons/paypal/payments/paypal.php
@@ -45,6 +45,22 @@ if (defined('PAYMENT_NOTIFICATION')) {
}
}
}
+
+ // wait for the IPN to be processed
+ $is_locked = fn_pp_is_order_locked($_REQUEST['order_id']);
+ $time_to_wait = 10; // time to wait for IPN to be processed, seconds
+ while ($is_locked && $time_to_wait) {
+ sleep(1);
+ $time_to_wait--;
+ $is_locked = fn_pp_is_order_locked($_REQUEST['order_id']);
+ }
+
+ // set order's status to Open and wait for the IPN to arrive
+ $order_info = fn_get_order_info($_REQUEST['order_id'], true);
+ if (fn_pp_get_order_status($order_info) == STATUS_INCOMPLETED_ORDER) {
+ fn_change_order_status($_REQUEST['order_id'], 'O', '');
+ }
+
fn_order_placement_routines('route', $_REQUEST['order_id'], false);
} elseif ($mode == 'cancel') {
@@ -142,20 +158,24 @@ if (defined('PAYMENT_NOTIFICATION')) {
list($products, $product_count) = fn_pp_standart_prepare_products($order_info, $paypal_currency);
$post_data = array_merge($post_data, $products);
- if ($order_info['status'] == STATUS_INCOMPLETED_ORDER) {
- fn_change_order_status($order_id, 'O', '', false);
- }
- if (fn_allowed_for('MULTIVENDOR')) {
- if ($order_info['status'] == STATUS_PARENT_ORDER) {
- $child_orders = db_get_hash_single_array("SELECT order_id, status FROM ?:orders WHERE parent_order_id = ?i", array('order_id', 'status'), $order_id);
+ // empty (or no) 'new_order_status' value means that order has to be set to 'open' status
+ if (empty($processor_data['processor_params']['new_order_status'])) {
+ if ($order_info['status'] == STATUS_INCOMPLETED_ORDER) {
+ fn_change_order_status($order_id, 'O', '', false);
+ }
+ if (fn_allowed_for('MULTIVENDOR')) {
+ if ($order_info['status'] == STATUS_PARENT_ORDER) {
+ $child_orders = db_get_hash_single_array("SELECT order_id, status FROM ?:orders WHERE parent_order_id = ?i", array('order_id', 'status'), $order_id);
- foreach ($child_orders as $order_id => $order_status) {
- if ($order_status == STATUS_INCOMPLETED_ORDER) {
- fn_change_order_status($order_id, 'O', '', false);
+ foreach ($child_orders as $order_id => $order_status) {
+ if ($order_status == STATUS_INCOMPLETED_ORDER) {
+ fn_change_order_status($order_id, 'O', '', false);
+ }
}
}
}
}
+
fn_pp_save_mode($order_info);
fn_create_payment_form($paypal_url, $post_data, 'PayPal server', false);
}
diff --git a/design/backend/templates/addons/paypal/views/payments/components/cc_processors/paypal.tpl b/design/backend/templates/addons/paypal/views/payments/components/cc_processors/paypal.tpl
index fe8c528..a3ff585 100644
--- a/design/backend/templates/addons/paypal/views/payments/components/cc_processors/paypal.tpl
+++ b/design/backend/templates/addons/paypal/views/payments/components/cc_processors/paypal.tpl
@@ -41,3 +41,13 @@
<input type="text" name="payment_data[processor_params][order_prefix]" id="order_prefix" value="{$processor_params.order_prefix}" >
</div>
</div>
+
+<div class="control-group">
+ <label class="control-label" for="elm_new_order_status">{__("addons.paypal.status_for_new_orders")}:</label>
+ <div class="controls">
+ <select name="payment_data[processor_params][new_order_status]" id="elm_new_order_status">
+ <option value="" {if $processor_params.new_order_status == ""}selected="selected"{/if}>{__("open")}</option>
+ <option value="{$smarty.const.STATUS_INCOMPLETED_ORDER}" {if $processor_params.new_order_status == "{$smarty.const.STATUS_INCOMPLETED_ORDER}"}selected="selected"{/if}>{__("incompleted")}</option>
+ </select>
+ </div>
+</div>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.