Version Description
- Added razorpay webhooks
Download this release
Release Info
Developer | mayankamencherla |
Plugin | Razorpay for WooCommerce |
Version | 1.4.3 |
Comparing to | |
See all releases |
Code changes from version 1.4.2 to 1.4.3
- .editorconfig +0 -13
- images/logo.jpg +0 -0
- includes/razorpay-webhook.php +113 -0
- razorpay-payments.php +76 -13
- razorpay-sdk/src/Utility.php +11 -4
- readme.txt +4 -1
.editorconfig
DELETED
@@ -1,13 +0,0 @@
|
|
1 |
-
; This file is for unifying the coding style for different editors and IDEs.
|
2 |
-
; More information at http://EditorConfig.org
|
3 |
-
|
4 |
-
root = true
|
5 |
-
; Use 2 spaces for indentation in all files
|
6 |
-
|
7 |
-
[*.php]
|
8 |
-
end_of_line = lf
|
9 |
-
charset = utf-8
|
10 |
-
trim_trailing_whitespace = true
|
11 |
-
indent_style = space
|
12 |
-
indent_size = 4
|
13 |
-
insert_final_newline = true
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
images/logo.jpg
DELETED
Binary file
|
includes/razorpay-webhook.php
ADDED
@@ -0,0 +1,113 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
require_once __DIR__.'/../razorpay-payments.php';
|
4 |
+
require_once __DIR__.'/../razorpay-sdk/Razorpay.php';
|
5 |
+
|
6 |
+
use Razorpay\Api\Api;
|
7 |
+
use Razorpay\Api\Errors;
|
8 |
+
|
9 |
+
class RZP_Webhook
|
10 |
+
{
|
11 |
+
protected $razorpay;
|
12 |
+
protected $api;
|
13 |
+
|
14 |
+
function __construct()
|
15 |
+
{
|
16 |
+
$this->razorpay = new WC_Razorpay();
|
17 |
+
|
18 |
+
$this->api = $this->razorpay->getRazorpayApiInstance();
|
19 |
+
}
|
20 |
+
|
21 |
+
public function process()
|
22 |
+
{
|
23 |
+
$post = file_get_contents('php://input');
|
24 |
+
|
25 |
+
$data = json_decode($post, true);
|
26 |
+
|
27 |
+
if (json_last_error() !== 0)
|
28 |
+
{
|
29 |
+
return;
|
30 |
+
}
|
31 |
+
|
32 |
+
if ($this->razorpay->enable_webhook === 'yes' && empty($data['event']) === false)
|
33 |
+
{
|
34 |
+
if ((isset($_SERVER['HTTP_X_RAZORPAY_SIGNATURE']) === true))
|
35 |
+
{
|
36 |
+
$razorpayWebhookSecret = $this->razorpay->webhook_secret;
|
37 |
+
|
38 |
+
//
|
39 |
+
// If the webhook secret isn't set on wordpress, return
|
40 |
+
//
|
41 |
+
if (empty($razorpayWebhookSecret) === true)
|
42 |
+
{
|
43 |
+
return;
|
44 |
+
}
|
45 |
+
|
46 |
+
try
|
47 |
+
{
|
48 |
+
$this->api->utility->verifyWebhookSignature($post,
|
49 |
+
$_SERVER['HTTP_X_RAZORPAY_SIGNATURE'],
|
50 |
+
$razorpayWebhookSecret);
|
51 |
+
}
|
52 |
+
catch (Errors\SignatureVerificationError $e)
|
53 |
+
{
|
54 |
+
write_log(['message' => $e->getMessage()]);
|
55 |
+
return;
|
56 |
+
}
|
57 |
+
}
|
58 |
+
|
59 |
+
switch ($data['event'])
|
60 |
+
{
|
61 |
+
case 'payment.authorized':
|
62 |
+
return $this->paymentAuthorized($data);
|
63 |
+
|
64 |
+
default:
|
65 |
+
return;
|
66 |
+
}
|
67 |
+
}
|
68 |
+
}
|
69 |
+
|
70 |
+
protected function paymentAuthorized($data)
|
71 |
+
{
|
72 |
+
global $woocommerce;
|
73 |
+
|
74 |
+
//
|
75 |
+
// Order entity should be sent as part of the webhook payload
|
76 |
+
//
|
77 |
+
$orderId = $data['payload']['payment']['entity']['notes']['woocommerce_order_id'];
|
78 |
+
|
79 |
+
$order = new WC_Order($orderId);
|
80 |
+
|
81 |
+
if ($order->needs_payment() === false)
|
82 |
+
{
|
83 |
+
return;
|
84 |
+
}
|
85 |
+
|
86 |
+
$razorpayPaymentId = $data['payload']['payment']['entity']['id'];
|
87 |
+
|
88 |
+
$payment = $this->api->payment->fetch($razorpayPaymentId);
|
89 |
+
|
90 |
+
$amount = $this->razorpay->getOrderAmountAsInteger($order);
|
91 |
+
|
92 |
+
$success = false;
|
93 |
+
$errorMessage = 'The payment has failed.';
|
94 |
+
|
95 |
+
if ($payment['status'] === 'captured')
|
96 |
+
{
|
97 |
+
$success = true;
|
98 |
+
}
|
99 |
+
else if (($payment['status'] === 'authorized') and
|
100 |
+
($this->razorpay->payment_action === 'capture'))
|
101 |
+
{
|
102 |
+
//
|
103 |
+
// If the payment is only authorized, we capture it
|
104 |
+
// If the merchant has enabled auto capture
|
105 |
+
//
|
106 |
+
$payment->capture(array('amount' => $amount));
|
107 |
+
}
|
108 |
+
|
109 |
+
$this->razorpay->updateOrder($order, $success, $errorMessage, $razorpayPaymentId);
|
110 |
+
|
111 |
+
exit;
|
112 |
+
}
|
113 |
+
}
|
razorpay-payments.php
CHANGED
@@ -8,21 +8,27 @@ Author: Razorpay
|
|
8 |
Author URI: https://razorpay.com
|
9 |
*/
|
10 |
|
11 |
-
if ( ! defined( 'ABSPATH' ) )
|
|
|
12 |
exit; // Exit if accessed directly
|
13 |
}
|
14 |
|
|
|
|
|
15 |
use Razorpay\Api\Api;
|
16 |
use Razorpay\Api\Errors;
|
17 |
|
18 |
require_once __DIR__.'/razorpay-sdk/Razorpay.php';
|
19 |
|
20 |
add_action('plugins_loaded', 'woocommerce_razorpay_init', 0);
|
|
|
21 |
|
22 |
function woocommerce_razorpay_init()
|
23 |
{
|
24 |
if (!class_exists('WC_Payment_Gateway'))
|
|
|
25 |
return;
|
|
|
26 |
|
27 |
class WC_Razorpay extends WC_Payment_Gateway
|
28 |
{
|
@@ -44,6 +50,24 @@ function woocommerce_razorpay_init()
|
|
44 |
$this->key_secret = $this->settings['key_secret'];
|
45 |
$this->payment_action = $this->settings['payment_action'];
|
46 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
47 |
$this->supports = array(
|
48 |
'products',
|
49 |
'refunds',
|
@@ -109,7 +133,20 @@ function woocommerce_razorpay_init()
|
|
109 |
'authorize' => 'Authorize',
|
110 |
'capture' => 'Authorize and Capture'
|
111 |
)
|
112 |
-
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
113 |
);
|
114 |
}
|
115 |
public function admin_options()
|
@@ -274,7 +311,7 @@ function woocommerce_razorpay_init()
|
|
274 |
/**
|
275 |
* Returns the order amount, rounded as integer
|
276 |
*/
|
277 |
-
|
278 |
{
|
279 |
if (version_compare(WOOCOMMERCE_VERSION, '3.0.0', '>='))
|
280 |
{
|
@@ -289,7 +326,7 @@ function woocommerce_razorpay_init()
|
|
289 |
// Calls the helper function to create order data
|
290 |
global $woocommerce;
|
291 |
|
292 |
-
$api =
|
293 |
|
294 |
$data = $this->getOrderCreationData($orderId);
|
295 |
$razorpay_order = $api->order->create($data);
|
@@ -439,8 +476,8 @@ EOT;
|
|
439 |
try
|
440 |
{
|
441 |
$refund = $client->payment
|
442 |
-
|
443 |
-
|
444 |
|
445 |
$order->add_order_note(__( 'Refund Id: ' . $refund->id, 'woocommerce' ));
|
446 |
|
@@ -453,6 +490,7 @@ EOT;
|
|
453 |
|
454 |
}
|
455 |
|
|
|
456 |
/**
|
457 |
* Process the payment and return the result
|
458 |
**/
|
@@ -489,7 +527,7 @@ EOT;
|
|
489 |
}
|
490 |
}
|
491 |
|
492 |
-
|
493 |
{
|
494 |
return new Api($this->key_id, $this->key_secret);
|
495 |
}
|
@@ -502,9 +540,17 @@ EOT;
|
|
502 |
global $woocommerce;
|
503 |
|
504 |
$orderId = $woocommerce->session->get(self::SESSION_KEY);
|
505 |
-
|
506 |
$order = new WC_Order($orderId);
|
507 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
508 |
$razorpayPaymentId = null;
|
509 |
|
510 |
if ($orderId and !empty($_POST[self::RAZORPAY_PAYMENT_ID]))
|
@@ -527,14 +573,18 @@ EOT;
|
|
527 |
{
|
528 |
$success = false;
|
529 |
$error = 'Customer cancelled the payment';
|
530 |
-
|
531 |
$this->handleErrorCase($order);
|
532 |
}
|
533 |
|
534 |
$this->updateOrder($order, $success, $error, $razorpayPaymentId);
|
535 |
|
536 |
-
$this->
|
|
|
|
|
|
|
|
|
537 |
$redirectUrl = $this->get_return_url($order);
|
|
|
538 |
wp_redirect($redirectUrl);
|
539 |
exit;
|
540 |
}
|
@@ -590,7 +640,7 @@ EOT;
|
|
590 |
*
|
591 |
* @param $success, & $order
|
592 |
*/
|
593 |
-
|
594 |
{
|
595 |
global $woocommerce;
|
596 |
|
@@ -601,10 +651,14 @@ EOT;
|
|
601 |
$this->msg['message'] = "Thank you for shopping with us. Your account has been charged and your transaction is successful. We will be processing your order soon. Order Id: $orderId";
|
602 |
$this->msg['class'] = 'success';
|
603 |
|
604 |
-
$order->payment_complete();
|
605 |
$order->add_order_note("Razorpay payment successful <br/>Razorpay Id: $razorpayPaymentId");
|
606 |
$order->add_order_note($this->msg['message']);
|
607 |
-
|
|
|
|
|
|
|
|
|
608 |
}
|
609 |
else
|
610 |
{
|
@@ -619,6 +673,8 @@ EOT;
|
|
619 |
$order->add_order_note("Transaction Failed: $errorMessage<br/>");
|
620 |
$order->update_status('failed');
|
621 |
}
|
|
|
|
|
622 |
}
|
623 |
|
624 |
protected function handleErrorCase(& $order)
|
@@ -671,3 +727,10 @@ EOT;
|
|
671 |
|
672 |
add_filter('woocommerce_payment_gateways', 'woocommerce_add_razorpay_gateway' );
|
673 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
8 |
Author URI: https://razorpay.com
|
9 |
*/
|
10 |
|
11 |
+
if ( ! defined( 'ABSPATH' ) )
|
12 |
+
{
|
13 |
exit; // Exit if accessed directly
|
14 |
}
|
15 |
|
16 |
+
require_once __DIR__.'/includes/razorpay-webhook.php';
|
17 |
+
|
18 |
use Razorpay\Api\Api;
|
19 |
use Razorpay\Api\Errors;
|
20 |
|
21 |
require_once __DIR__.'/razorpay-sdk/Razorpay.php';
|
22 |
|
23 |
add_action('plugins_loaded', 'woocommerce_razorpay_init', 0);
|
24 |
+
add_action('admin_post_nopriv_rzp_wc_webhook', 'razorpay_webhook_init');
|
25 |
|
26 |
function woocommerce_razorpay_init()
|
27 |
{
|
28 |
if (!class_exists('WC_Payment_Gateway'))
|
29 |
+
{
|
30 |
return;
|
31 |
+
}
|
32 |
|
33 |
class WC_Razorpay extends WC_Payment_Gateway
|
34 |
{
|
50 |
$this->key_secret = $this->settings['key_secret'];
|
51 |
$this->payment_action = $this->settings['payment_action'];
|
52 |
|
53 |
+
if (isset($this->settings['enable_webhook']) === true)
|
54 |
+
{
|
55 |
+
$this->enable_webhook = $this->settings['enable_webhook'];
|
56 |
+
}
|
57 |
+
else
|
58 |
+
{
|
59 |
+
$this->enable_webhook = 'yes';
|
60 |
+
}
|
61 |
+
|
62 |
+
if (isset($this->settings['webhook_secret']) === true)
|
63 |
+
{
|
64 |
+
$this->webhook_secret = $this->settings['webhook_secret'];
|
65 |
+
}
|
66 |
+
else
|
67 |
+
{
|
68 |
+
$this->webhook_secret = '';
|
69 |
+
}
|
70 |
+
|
71 |
$this->supports = array(
|
72 |
'products',
|
73 |
'refunds',
|
133 |
'authorize' => 'Authorize',
|
134 |
'capture' => 'Authorize and Capture'
|
135 |
)
|
136 |
+
),
|
137 |
+
'enable_webhook' => array(
|
138 |
+
'title' => __('Enable Webhook', 'razorpay'),
|
139 |
+
'type' => 'checkbox',
|
140 |
+
'description' => esc_url( admin_url('admin-post.php') ) . "?action=rzp_wc_webhook <br><br>Instructions and guide to <a href='https://github.com/razorpay/razorpay-woocommerce/wiki/Razorpay-Woocommerce-Webhooks'>Razorpay webhooks</a>",
|
141 |
+
'label' => __('Enable Razorpay Webhook <a href="https://dashboard.razorpay.com/#/app/webhooks">here</a> with the URL listed below.', 'razorpay'),
|
142 |
+
'default' => 'yes'
|
143 |
+
),
|
144 |
+
'webhook_secret' => array(
|
145 |
+
'title' => __('Webhook Secret', 'razorpay'),
|
146 |
+
'type' => 'text',
|
147 |
+
'description' => __('Webhook secret is used for webhook signature verification. This has to match the one added <a href="https://dashboard.razorpay.com/#/app/webhooks">here</a>', 'razorpay'),
|
148 |
+
'default' => ''
|
149 |
+
),
|
150 |
);
|
151 |
}
|
152 |
public function admin_options()
|
311 |
/**
|
312 |
* Returns the order amount, rounded as integer
|
313 |
*/
|
314 |
+
public function getOrderAmountAsInteger($order)
|
315 |
{
|
316 |
if (version_compare(WOOCOMMERCE_VERSION, '3.0.0', '>='))
|
317 |
{
|
326 |
// Calls the helper function to create order data
|
327 |
global $woocommerce;
|
328 |
|
329 |
+
$api = $this->getRazorpayApiInstance();
|
330 |
|
331 |
$data = $this->getOrderCreationData($orderId);
|
332 |
$razorpay_order = $api->order->create($data);
|
476 |
try
|
477 |
{
|
478 |
$refund = $client->payment
|
479 |
+
->fetch($paymentId)
|
480 |
+
->refund($data);
|
481 |
|
482 |
$order->add_order_note(__( 'Refund Id: ' . $refund->id, 'woocommerce' ));
|
483 |
|
490 |
|
491 |
}
|
492 |
|
493 |
+
|
494 |
/**
|
495 |
* Process the payment and return the result
|
496 |
**/
|
527 |
}
|
528 |
}
|
529 |
|
530 |
+
public function getRazorpayApiInstance()
|
531 |
{
|
532 |
return new Api($this->key_id, $this->key_secret);
|
533 |
}
|
540 |
global $woocommerce;
|
541 |
|
542 |
$orderId = $woocommerce->session->get(self::SESSION_KEY);
|
|
|
543 |
$order = new WC_Order($orderId);
|
544 |
|
545 |
+
//
|
546 |
+
// If the order has already been paid for
|
547 |
+
// redirect user to success page
|
548 |
+
//
|
549 |
+
if ($order->needs_payment() === false)
|
550 |
+
{
|
551 |
+
$this->redirectUser($order);
|
552 |
+
}
|
553 |
+
|
554 |
$razorpayPaymentId = null;
|
555 |
|
556 |
if ($orderId and !empty($_POST[self::RAZORPAY_PAYMENT_ID]))
|
573 |
{
|
574 |
$success = false;
|
575 |
$error = 'Customer cancelled the payment';
|
|
|
576 |
$this->handleErrorCase($order);
|
577 |
}
|
578 |
|
579 |
$this->updateOrder($order, $success, $error, $razorpayPaymentId);
|
580 |
|
581 |
+
$this->redirectUser($order);
|
582 |
+
}
|
583 |
+
|
584 |
+
protected function redirectUser($order)
|
585 |
+
{
|
586 |
$redirectUrl = $this->get_return_url($order);
|
587 |
+
|
588 |
wp_redirect($redirectUrl);
|
589 |
exit;
|
590 |
}
|
640 |
*
|
641 |
* @param $success, & $order
|
642 |
*/
|
643 |
+
public function updateOrder(& $order, $success, $errorMessage, $razorpayPaymentId)
|
644 |
{
|
645 |
global $woocommerce;
|
646 |
|
651 |
$this->msg['message'] = "Thank you for shopping with us. Your account has been charged and your transaction is successful. We will be processing your order soon. Order Id: $orderId";
|
652 |
$this->msg['class'] = 'success';
|
653 |
|
654 |
+
$order->payment_complete($razorpayPaymentId);
|
655 |
$order->add_order_note("Razorpay payment successful <br/>Razorpay Id: $razorpayPaymentId");
|
656 |
$order->add_order_note($this->msg['message']);
|
657 |
+
|
658 |
+
if (isset($woocommerce->cart) === true)
|
659 |
+
{
|
660 |
+
$woocommerce->cart->empty_cart();
|
661 |
+
}
|
662 |
}
|
663 |
else
|
664 |
{
|
673 |
$order->add_order_note("Transaction Failed: $errorMessage<br/>");
|
674 |
$order->update_status('failed');
|
675 |
}
|
676 |
+
|
677 |
+
$this->add_notice($this->msg['message'], $this->msg['class']);
|
678 |
}
|
679 |
|
680 |
protected function handleErrorCase(& $order)
|
727 |
|
728 |
add_filter('woocommerce_payment_gateways', 'woocommerce_add_razorpay_gateway' );
|
729 |
}
|
730 |
+
|
731 |
+
function razorpay_webhook_init()
|
732 |
+
{
|
733 |
+
$rzpWebhook = new RZP_Webhook();
|
734 |
+
|
735 |
+
$rzpWebhook->process();
|
736 |
+
}
|
razorpay-sdk/src/Utility.php
CHANGED
@@ -17,14 +17,21 @@ class Utility
|
|
17 |
return self::verifySignature($payload, $expectedSignature);
|
18 |
}
|
19 |
|
20 |
-
public function verifyWebhookSignature($payload, $expectedSignature)
|
21 |
{
|
22 |
-
return self::verifySignature($payload, $expectedSignature);
|
23 |
}
|
24 |
|
25 |
-
public function verifySignature($payload, $expectedSignature)
|
26 |
{
|
27 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
28 |
|
29 |
// Use lang's built-in hash_equals if exists to mitigate timing attacks
|
30 |
if (function_exists('hash_equals'))
|
17 |
return self::verifySignature($payload, $expectedSignature);
|
18 |
}
|
19 |
|
20 |
+
public function verifyWebhookSignature($payload, $expectedSignature, $webhookSecret)
|
21 |
{
|
22 |
+
return self::verifySignature($payload, $expectedSignature, $webhookSecret);
|
23 |
}
|
24 |
|
25 |
+
public function verifySignature($payload, $expectedSignature, $webhookSecret = '')
|
26 |
{
|
27 |
+
if (isset($webhookSecret) === true)
|
28 |
+
{
|
29 |
+
$actualSignature = hash_hmac(self::SHA256, $payload, $webhookSecret);
|
30 |
+
}
|
31 |
+
else
|
32 |
+
{
|
33 |
+
$actualSignature = hash_hmac(self::SHA256, $payload, Api::getSecret());
|
34 |
+
}
|
35 |
|
36 |
// Use lang's built-in hash_equals if exists to mitigate timing attacks
|
37 |
if (function_exists('hash_equals'))
|
readme.txt
CHANGED
@@ -3,7 +3,7 @@ Contributors: razorpay
|
|
3 |
Tags: razorpay, payments, india, woocommerce, ecommerce
|
4 |
Requires at least: 3.9.2
|
5 |
Tested up to: 4.7
|
6 |
-
Stable tag: 1.4.
|
7 |
License: GPLv2 or later
|
8 |
License URI: http://www.gnu.org/licenses/gpl-2.0.html
|
9 |
|
@@ -36,6 +36,9 @@ This is compatible with WooCommerce>=2.4, including the new 3.0 release.
|
|
36 |
|
37 |
== Changelog ==
|
38 |
|
|
|
|
|
|
|
39 |
= 1.4.2 =
|
40 |
* Added missing classes in the WordPress release (Utility.php was missing)
|
41 |
|
3 |
Tags: razorpay, payments, india, woocommerce, ecommerce
|
4 |
Requires at least: 3.9.2
|
5 |
Tested up to: 4.7
|
6 |
+
Stable tag: 1.4.3
|
7 |
License: GPLv2 or later
|
8 |
License URI: http://www.gnu.org/licenses/gpl-2.0.html
|
9 |
|
36 |
|
37 |
== Changelog ==
|
38 |
|
39 |
+
= 1.4.3 =
|
40 |
+
* Added razorpay webhooks
|
41 |
+
|
42 |
= 1.4.2 =
|
43 |
* Added missing classes in the WordPress release (Utility.php was missing)
|
44 |
|