Razorpay for WooCommerce - Version 1.4.0

Version Description

  • Added Support for WooCommerce 3.x (https://github.com/razorpay/razorpay-woocommerce/pull/35)
  • Fixes around discount coupon handling (Order Amount mismatch)
  • Updates Razorpay SDK
  • Improves Javascript Caching (https://github.com/razorpay/razorpay-woocommerce/pull/39)
  • Adds support for mobile browsers (https://github.com/razorpay/razorpay-woocommerce/pull/37):
    • Chrome on iOS
    • Facebook Browser
    • Internet Explorer Mobile
    • AOSP Browser
    • Opera Mini
    • Google Search App
    • Any other apps using webviews
  • Adds support for refunding payments from within WooCommerce
Download this release

Release Info

Developer razorpay
Plugin Icon 128x128 Razorpay for WooCommerce
Version 1.4.0
Comparing to
See all releases

Code changes from version 1.3.2 to 1.4.0

Files changed (3) hide show
  1. razorpay-payments.php +341 -171
  2. readme.txt +54 -3
  3. script.js +51 -0
razorpay-payments.php CHANGED
@@ -3,12 +3,17 @@
3
  Plugin Name: WooCommerce Razorpay Payments
4
  Plugin URI: https://razorpay.com
5
  Description: Razorpay Payment Gateway Integration for WooCommerce
6
- Version: 1.3.2
7
  Author: Razorpay
8
  Author URI: https://razorpay.com
9
  */
10
 
 
 
 
 
11
  use Razorpay\Api\Api;
 
12
 
13
  require_once __DIR__.'/razorpay-sdk/Razorpay.php';
14
 
@@ -21,10 +26,9 @@ function woocommerce_razorpay_init()
21
 
22
  class WC_Razorpay extends WC_Payment_Gateway
23
  {
24
- const BASE_URL = 'https://api.razorpay.com/';
25
- const API_VERSION = 'v1';
26
  // This one stores the WooCommerce Order Id
27
  const SESSION_KEY = 'razorpay_wc_order_id';
 
28
 
29
  public function __construct()
30
  {
@@ -40,8 +44,13 @@ function woocommerce_razorpay_init()
40
  $this->key_secret = $this->settings['key_secret'];
41
  $this->payment_action = $this->settings['payment_action'];
42
 
43
- $this->msg['message'] = "";
44
- $this->msg['class'] = "";
 
 
 
 
 
45
 
46
  add_action('init', array(&$this, 'check_razorpay_response'));
47
  add_action('woocommerce_api_' . strtolower(get_class($this)), array($this, 'check_razorpay_response'));
@@ -140,19 +149,21 @@ function woocommerce_razorpay_init()
140
  }
141
 
142
  /**
143
- * Generate razorpay button link
144
- **/
145
- public function generate_razorpay_form($orderId)
 
 
 
 
 
146
  {
147
  global $woocommerce;
148
- $order = new WC_Order($orderId);
149
-
150
- $redirect_url = get_site_url() . '/?wc-api=' . get_class($this);
151
- $productinfo = "Order $orderId";
152
- $api = new Api($this->key_id, $this->key_secret);
153
 
154
  $sessionKey = $this->getSessionKey($orderId);
155
 
 
 
156
  try
157
  {
158
  $razorpayOrderId = $woocommerce->session->get($sessionKey);
@@ -162,37 +173,115 @@ function woocommerce_razorpay_init()
162
  if (($razorpayOrderId === null) or
163
  (($razorpayOrderId and ($this->verifyOrderAmount($razorpayOrderId, $orderId)) === false)))
164
  {
165
- $razorpayOrderId = $this->createRazorpayOrderId(
166
- $orderId, $sessionKey);
 
 
 
167
  }
168
  }
 
 
169
  catch (Exception $e)
170
  {
171
- echo "RAZORPAY ERROR: Api could not be reached";
172
  }
173
 
174
- $razorpay_args = array(
175
- 'key' => $this->key_id,
176
- 'name' => get_bloginfo('name'),
177
- 'amount' => $order->order_total*100,
178
- 'currency' => get_woocommerce_currency(),
179
- 'description' => $productinfo,
180
- 'prefill' => array(
181
- 'name' => $order->billing_first_name." ".$order->billing_last_name,
182
- 'email' => $order->billing_email,
183
- 'contact' => $order->billing_phone
184
- ),
185
- 'notes' => array(
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
186
  'woocommerce_order_id' => $orderId
187
  ),
188
- 'order_id' => $razorpayOrderId
 
189
  );
190
 
191
- $json = json_encode($razorpay_args);
192
 
193
- $html = $this->generate_order_form($redirect_url,$json,$orderId);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
194
 
195
- return $html;
 
 
 
 
 
 
 
 
 
 
 
 
 
196
  }
197
 
198
  protected function createRazorpayOrderId($orderId, $sessionKey)
@@ -202,7 +291,7 @@ function woocommerce_razorpay_init()
202
 
203
  $api = new Api($this->key_id, $this->key_secret);
204
 
205
- $data = $this->get_order_creation_data($orderId);
206
  $razorpay_order = $api->order->create($data);
207
 
208
  $razorpayOrderId = $razorpay_order['id'];
@@ -216,13 +305,13 @@ function woocommerce_razorpay_init()
216
  {
217
  $order = new WC_Order($orderId);
218
 
219
- $api = new Api($this->key_id, $this->key_secret);
220
 
221
  $razorpayOrder = $api->order->fetch($razorpayOrderId);
222
 
223
  $razorpayOrderArgs = array(
224
  'id' => $razorpayOrderId,
225
- 'amount' => (int) $order->order_total*100,
226
  'currency' => get_woocommerce_currency(),
227
  'receipt' => (string) $orderId,
228
  );
@@ -240,9 +329,9 @@ function woocommerce_razorpay_init()
240
  return true;
241
  }
242
 
243
- function get_order_creation_data($order_id)
244
  {
245
- $order = new WC_Order($order_id);
246
 
247
  if (!isset($this->payment_action))
248
  {
@@ -250,38 +339,45 @@ function woocommerce_razorpay_init()
250
  }
251
 
252
  $data = array(
253
- 'receipt' => $order_id,
254
- 'amount' => (int) ($order->order_total * 100),
255
- 'currency' => get_woocommerce_currency(),
 
256
  );
257
 
258
- switch($this->payment_action)
259
- {
260
- case 'authorize':
261
- $data['payment_capture'] = 0;
262
- break;
263
-
264
- case 'capture':
265
- default:
266
- $data['payment_capture'] = 1;
267
- break;
268
- }
269
  return $data;
270
  }
271
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
272
  /**
273
  * Generates the order form
274
  **/
275
- function generate_order_form($redirect_url, $json)
276
  {
277
- $html = <<<EOT
278
- <script src="https://checkout.razorpay.com/v1/checkout.js"></script>
279
- <script>
280
- var data = $json;
281
- </script>
282
- <form name='razorpayform' action="$redirect_url" method="POST">
283
  <input type="hidden" name="razorpay_payment_id" id="razorpay_payment_id">
284
  <input type="hidden" name="razorpay_signature" id="razorpay_signature" >
 
 
285
  </form>
286
  <p id="msg-razorpay-success" class="woocommerce-info woocommerce-message" style="display:none">
287
  Please wait while we are processing your payment.
@@ -290,54 +386,71 @@ Please wait while we are processing your payment.
290
  <button id="btn-razorpay">Pay Now</button>
291
  <button id="btn-razorpay-cancel" onclick="document.razorpayform.submit()">Cancel</button>
292
  </p>
293
- <script>
294
- (function(){
295
- var setDisabled = function(id, state) {
296
- if (typeof state === 'undefined') {
297
- state = true;
298
- }
299
- var elem = document.getElementById(id);
300
- if (state === false) {
301
- elem.removeAttribute('disabled');
302
- }
303
- else {
304
- elem.setAttribute('disabled', state);
305
- }
306
- };
307
- // Payment was closed without handler getting called
308
- data.modal = {
309
- ondismiss: function() {
310
- setDisabled('btn-razorpay', false);
311
- }
312
- };
313
- data.handler = function(payment){
314
- setDisabled('btn-razorpay-cancel');
315
- var successMsg = document.getElementById('msg-razorpay-success');
316
- successMsg.style.display = "block";
317
- document.getElementById('razorpay_payment_id').value = payment.razorpay_payment_id;
318
- document.getElementById('razorpay_signature').value = payment.razorpay_signature;
319
- document.razorpayform.submit();
320
- };
321
- var razorpayCheckout = new Razorpay(data);
322
- // global method
323
- function openCheckout() {
324
- // Disable the pay button
325
- setDisabled('btn-razorpay');
326
- razorpayCheckout.open();
327
- }
328
- function addEvent(element, evnt, funct){
329
- if (element.attachEvent)
330
- return element.attachEvent('on'+evnt, funct);
331
- else
332
- return element.addEventListener(evnt, funct, false);
333
- }
334
- // Attach event listener
335
- addEvent(document.getElementById('btn-razorpay'), 'click', openCheckout);
336
- openCheckout();
337
- })();
338
- </script>
339
  EOT;
340
- return $html;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
341
  }
342
 
343
  /**
@@ -348,115 +461,172 @@ EOT;
348
  global $woocommerce;
349
  $order = new WC_Order($order_id);
350
  $woocommerce->session->set(self::SESSION_KEY, $order_id);
 
 
 
351
  if (version_compare(WOOCOMMERCE_VERSION, '2.1', '>='))
352
  {
353
  return array(
354
  'result' => 'success',
355
- 'redirect' => add_query_arg('key', $order->order_key, $order->get_checkout_payment_url(true))
356
  );
357
  }
358
  else if (version_compare(WOOCOMMERCE_VERSION, '2.0.0', '>='))
359
  {
360
  return array(
361
  'result' => 'success',
362
- 'redirect' => add_query_arg('order', $order->id,
363
- add_query_arg('key', $order->order_key, $order->get_checkout_payment_url(true)))
364
  );
365
  }
366
  else
367
  {
368
  return array(
369
  'result' => 'success',
370
- 'redirect' => add_query_arg('order', $order->id,
371
- add_query_arg('key', $order->order_key, get_permalink(get_option('woocommerce_pay_page_id'))))
372
  );
373
  }
374
  }
375
 
 
 
 
 
 
376
  /**
377
  * Check for valid razorpay server callback
378
  **/
379
  function check_razorpay_response()
380
  {
381
  global $woocommerce;
382
- $order_id = $woocommerce->session->get(self::SESSION_KEY);
383
 
384
- if ($order_id and !empty($_POST['razorpay_payment_id']))
 
 
 
 
 
 
385
  {
386
- $razorpay_payment_id = $_POST['razorpay_payment_id'];
387
- $order = new WC_Order($order_id);
388
- $key_id = $this->key_id;
389
- $key_secret = $this->key_secret;
390
- $amount = $order->order_total*100;
391
- $success = false;
392
  $error = "";
393
- $api = new Api($key_id, $key_secret);
394
- $payment = $api->payment->fetch($razorpay_payment_id);
395
 
396
  try
397
  {
398
- if ($this->payment_action === 'authorize' && $payment['amount'] === $amount)
399
- {
400
- $success = true;
401
- }
402
-
403
- else
404
- {
405
- $sessionKey = $this->getSessionKey($order_id);
406
- $razorpay_order_id = $woocommerce->session->get($sessionKey);
407
- $razorpay_signature = $_POST['razorpay_signature'];
408
-
409
- $signature = hash_hmac('sha256', $razorpay_order_id . '|' . $razorpay_payment_id, $key_secret);
410
- if (hash_equals($signature , $razorpay_signature))
411
- {
412
- $success = true;
413
- }
414
- else
415
- {
416
- $success = false;
417
- $error = "PAYMENT_ERROR: Payment failed";
418
- }
419
- }
420
  }
421
- catch (Exception $e)
422
  {
423
- $success = false;
424
- $error = 'WOOCOMMERCE_ERROR: Request to Razorpay Failed';
425
  }
426
- if ($success === true)
427
- {
428
- $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: $order_id";
429
- $this->msg['class'] = 'success';
430
- $order->payment_complete();
431
- $order->add_order_note("Razorpay payment successful <br/>Razorpay Id: $razorpay_payment_id");
432
- $order->add_order_note($this->msg['message']);
433
- $woocommerce->cart->empty_cart();
434
- }
435
- else
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
436
  {
437
- $this->msg['class'] = 'error';
438
- $this->msg['message'] = 'Thank you for shopping with us. However, the payment failed.';
439
- $order->add_order_note("Transaction Declined: $error<br/>");
440
- $order->add_order_note("Payment Failed. Please check Razorpay Dashboard. <br/> Razorpay Id: $razorpay_payment_id");
441
- $order->update_status('failed');
442
  }
443
  }
444
- // We don't have a proper order id
445
  else
446
  {
447
- if ($order_id !== null)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
448
  {
449
- $order = new WC_Order($order_id);
450
- $order->update_status('failed');
451
- $order->add_order_note('Customer cancelled the payment');
452
  }
453
- $this->msg['class'] = 'error';
454
- $this->msg['message'] = "An error occured while processing this payment";
 
455
  }
456
- $this->add_notice($this->msg['message'], $this->msg['class']);
457
- $redirect_url = $this->get_return_url($order);
458
- wp_redirect( $redirect_url );
459
- exit;
 
 
 
 
460
  }
461
 
462
  /**
3
  Plugin Name: WooCommerce Razorpay Payments
4
  Plugin URI: https://razorpay.com
5
  Description: Razorpay Payment Gateway Integration for WooCommerce
6
+ Version: 1.4.0
7
  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
 
26
 
27
  class WC_Razorpay extends WC_Payment_Gateway
28
  {
 
 
29
  // This one stores the WooCommerce Order Id
30
  const SESSION_KEY = 'razorpay_wc_order_id';
31
+ const RAZORPAY_PAYMENT_ID = 'razorpay_payment_id';
32
 
33
  public function __construct()
34
  {
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',
50
+ );
51
+
52
+ $this->msg['message'] = '';
53
+ $this->msg['class'] = '';
54
 
55
  add_action('init', array(&$this, 'check_razorpay_response'));
56
  add_action('woocommerce_api_' . strtolower(get_class($this)), array($this, 'check_razorpay_response'));
149
  }
150
 
151
  /**
152
+ * Given a order Id, find the associated
153
+ * Razorpay Order from the session and verify
154
+ * that is is still correct. If not found
155
+ * (or incorrect), create a new Razorpay Order
156
+ * @param string $orderId Order Id
157
+ * @return mixed Razorpay Order Id or null
158
+ */
159
+ protected function createOrGetRazorpayOrderId($orderId)
160
  {
161
  global $woocommerce;
 
 
 
 
 
162
 
163
  $sessionKey = $this->getSessionKey($orderId);
164
 
165
+ $create = false;
166
+
167
  try
168
  {
169
  $razorpayOrderId = $woocommerce->session->get($sessionKey);
173
  if (($razorpayOrderId === null) or
174
  (($razorpayOrderId and ($this->verifyOrderAmount($razorpayOrderId, $orderId)) === false)))
175
  {
176
+ $create = true;
177
+ }
178
+ else
179
+ {
180
+ return $razorpayOrderId;
181
  }
182
  }
183
+ // Order doesn't exist or verification failed
184
+ // So try creating one
185
  catch (Exception $e)
186
  {
187
+ $create = true;
188
  }
189
 
190
+ if ($create)
191
+ {
192
+ try
193
+ {
194
+ return $this->createRazorpayOrderId(
195
+ $orderId, $sessionKey);
196
+ }
197
+ catch(Exception $e)
198
+ {
199
+ // Order creation failed
200
+ return null;
201
+ }
202
+ }
203
+ }
204
+
205
+ /**
206
+ * Generate razorpay button link
207
+ **/
208
+ public function generate_razorpay_form($orderId)
209
+ {
210
+ global $woocommerce;
211
+ $order = new WC_Order($orderId);
212
+
213
+ $redirectUrl = get_site_url() . '/?wc-api=' . get_class($this);
214
+
215
+ $razorpayOrderId = $this->createOrGetRazorpayOrderId($orderId);
216
+
217
+ if ($razorpayOrderId === null)
218
+ {
219
+ return 'RAZORPAY ERROR: Api could not be reached';
220
+ }
221
+
222
+ $checkoutArgs = $this->getCheckoutArguments($order, $razorpayOrderId);
223
+
224
+ $html = $this->generateOrderForm($redirectUrl, $checkoutArgs);
225
+
226
+ return $html;
227
+ }
228
+
229
+ /**
230
+ * Returns array of checkout params
231
+ */
232
+ protected function getCheckoutArguments($order, $razorpayOrderId)
233
+ {
234
+ $callbackUrl = get_site_url() . '/?wc-api=' . get_class($this);
235
+
236
+ $orderId = $this->getOrderId($order);
237
+
238
+ $productinfo = "Order $orderId";
239
+
240
+ $args = array(
241
+ 'key' => $this->key_id,
242
+ 'name' => get_bloginfo('name'),
243
+ 'currency' => get_woocommerce_currency(),
244
+ 'description' => $productinfo,
245
+ 'notes' => array(
246
  'woocommerce_order_id' => $orderId
247
  ),
248
+ 'order_id' => $razorpayOrderId,
249
+ 'callback_url' => $callbackUrl,
250
  );
251
 
252
+ $args['amount'] = $this->getOrderAmountAsInteger($order);
253
 
254
+ if (version_compare(WOOCOMMERCE_VERSION, '2.7.0', '>='))
255
+ {
256
+ $args['prefill'] = array(
257
+ 'name' => $order->get_billing_first_name() . ' ' . $order->get_billing_last_name(),
258
+ 'email' => $order->get_billing_email(),
259
+ 'contact' => $order->get_billing_phone(),
260
+ );
261
+ }
262
+ else
263
+ {
264
+ $args['prefill'] = array(
265
+ 'name' => $order->billing_first_name . ' ' . $order->billing_last_name,
266
+ 'email' => $order->billing_email,
267
+ 'contact' => $order->billing_phone,
268
+ );
269
+ }
270
 
271
+ return $args;
272
+ }
273
+
274
+ /**
275
+ * Returns the order amount, rounded as integer
276
+ */
277
+ protected function getOrderAmountAsInteger($order)
278
+ {
279
+ if (version_compare(WOOCOMMERCE_VERSION, '3.0.0', '>='))
280
+ {
281
+ return (int) round($order->get_total() * 100);
282
+ }
283
+
284
+ return (int) round($order->order_total * 100);
285
  }
286
 
287
  protected function createRazorpayOrderId($orderId, $sessionKey)
291
 
292
  $api = new Api($this->key_id, $this->key_secret);
293
 
294
+ $data = $this->getOrderCreationData($orderId);
295
  $razorpay_order = $api->order->create($data);
296
 
297
  $razorpayOrderId = $razorpay_order['id'];
305
  {
306
  $order = new WC_Order($orderId);
307
 
308
+ $api = $this->getRazorpayApiInstance();
309
 
310
  $razorpayOrder = $api->order->fetch($razorpayOrderId);
311
 
312
  $razorpayOrderArgs = array(
313
  'id' => $razorpayOrderId,
314
+ 'amount' => $this->getOrderAmountAsInteger($order),
315
  'currency' => get_woocommerce_currency(),
316
  'receipt' => (string) $orderId,
317
  );
329
  return true;
330
  }
331
 
332
+ function getOrderCreationData($orderId)
333
  {
334
+ $order = new WC_Order($orderId);
335
 
336
  if (!isset($this->payment_action))
337
  {
339
  }
340
 
341
  $data = array(
342
+ 'receipt' => $orderId,
343
+ 'amount' => (int) round($order->get_total() * 100),
344
+ 'currency' => get_woocommerce_currency(),
345
+ 'payment_capture' => ($this->payment_action === 'authorize') ? 0 : 1
346
  );
347
 
 
 
 
 
 
 
 
 
 
 
 
348
  return $data;
349
  }
350
 
351
+ private function enqueueCheckoutScripts($data)
352
+ {
353
+ wp_register_script('razorpay_checkout',
354
+ 'https://checkout.razorpay.com/v1/checkout.js',
355
+ null, null);
356
+
357
+ wp_register_script('razorpay_wc_script', plugin_dir_url(__FILE__) . 'script.js',
358
+ array('razorpay_checkout'));
359
+
360
+ wp_localize_script('razorpay_wc_script',
361
+ 'razorpay_wc_checkout_vars',
362
+ $data
363
+ );
364
+
365
+ wp_enqueue_script('razorpay_wc_script');
366
+ }
367
+
368
  /**
369
  * Generates the order form
370
  **/
371
+ function generateOrderForm($redirectUrl, $data)
372
  {
373
+ $this->enqueueCheckoutScripts($data);
374
+
375
+ return <<<EOT
376
+ <form name='razorpayform' action="$redirectUrl" method="POST">
 
 
377
  <input type="hidden" name="razorpay_payment_id" id="razorpay_payment_id">
378
  <input type="hidden" name="razorpay_signature" id="razorpay_signature" >
379
+ <!-- This distinguishes all our various wordpress plugins -->
380
+ <input type="hidden" name="razorpay_wc_form_submit" value="1">
381
  </form>
382
  <p id="msg-razorpay-success" class="woocommerce-info woocommerce-message" style="display:none">
383
  Please wait while we are processing your payment.
386
  <button id="btn-razorpay">Pay Now</button>
387
  <button id="btn-razorpay-cancel" onclick="document.razorpayform.submit()">Cancel</button>
388
  </p>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
389
  EOT;
390
+ }
391
+
392
+ /**
393
+ * Gets the Order Key from the Order
394
+ * for all WC versions that we suport
395
+ */
396
+ protected function getOrderKey($order)
397
+ {
398
+ $orderKey = null;
399
+
400
+ if (version_compare(WOOCOMMERCE_VERSION, '3.0.0', '>='))
401
+ {
402
+ return $order->get_order_key();
403
+ }
404
+
405
+ return $order->order_key;
406
+ }
407
+
408
+ protected function getOrderId($order)
409
+ {
410
+ if (version_compare(WOOCOMMERCE_VERSION, '2.7.0', '>='))
411
+ {
412
+ return $order->get_id();
413
+ }
414
+
415
+ return $order->id;
416
+ }
417
+
418
+ public function process_refund($orderId, $amount = null, $reason = '')
419
+ {
420
+ $order = new WC_Order($orderId);
421
+
422
+ if (! $order or ! $order->get_transaction_id())
423
+ {
424
+ return new WP_Error('error', __('Refund failed: No transaction ID', 'woocommerce'));
425
+ }
426
+
427
+ $client = $this->getRazorpayApiInstance();
428
+
429
+ $paymentId = $order->get_transaction_id();
430
+
431
+ $data = array(
432
+ 'amount' => (int) round($amount * 100),
433
+ 'notes' => array(
434
+ 'reason' => $reason,
435
+ 'order_id' => $orderId
436
+ )
437
+ );
438
+
439
+ try
440
+ {
441
+ $refund = $client->payment
442
+ ->fetch($paymentId)
443
+ ->refund($data);
444
+
445
+ $order->add_order_note(__( 'Refund Id: ' . $refund->id, 'woocommerce' ));
446
+
447
+ return true;
448
+ }
449
+ catch(Exception $e)
450
+ {
451
+ return new WP_Error('error', __($e->getMessage(), 'woocommerce'));
452
+ }
453
+
454
  }
455
 
456
  /**
461
  global $woocommerce;
462
  $order = new WC_Order($order_id);
463
  $woocommerce->session->set(self::SESSION_KEY, $order_id);
464
+
465
+ $orderKey = $this->getOrderKey($order);
466
+
467
  if (version_compare(WOOCOMMERCE_VERSION, '2.1', '>='))
468
  {
469
  return array(
470
  'result' => 'success',
471
+ 'redirect' => add_query_arg('key', $orderKey, $order->get_checkout_payment_url(true))
472
  );
473
  }
474
  else if (version_compare(WOOCOMMERCE_VERSION, '2.0.0', '>='))
475
  {
476
  return array(
477
  'result' => 'success',
478
+ 'redirect' => add_query_arg('order', $order->get_id(),
479
+ add_query_arg('key', $orderKey, $order->get_checkout_payment_url(true)))
480
  );
481
  }
482
  else
483
  {
484
  return array(
485
  'result' => 'success',
486
+ 'redirect' => add_query_arg('order', $order->get_id(),
487
+ add_query_arg('key', $orderKey, get_permalink(get_option('woocommerce_pay_page_id'))))
488
  );
489
  }
490
  }
491
 
492
+ protected function getRazorpayApiInstance()
493
+ {
494
+ return new Api($this->key_id, $this->key_secret);
495
+ }
496
+
497
  /**
498
  * Check for valid razorpay server callback
499
  **/
500
  function check_razorpay_response()
501
  {
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]))
511
  {
 
 
 
 
 
 
512
  $error = "";
513
+ $success = false;
 
514
 
515
  try
516
  {
517
+ $this->verifySignature($orderId);
518
+ $success = true;
519
+ $razorpayPaymentId = sanitize_text_field($_POST[self::RAZORPAY_PAYMENT_ID]);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
520
  }
521
+ catch (Errors\SignatureVerificationError $e)
522
  {
523
+ $error = 'WOOCOMMERCE_ERROR: Payment to Razorpay Failed. ' . $e->getMessage();
 
524
  }
525
+ }
526
+ else
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->add_notice($this->msg['message'], $this->msg['class']);
537
+ $redirectUrl = $this->get_return_url($order);
538
+ wp_redirect($redirectUrl);
539
+ exit;
540
+ }
541
+
542
+ protected function verifySignature($orderId)
543
+ {
544
+ global $woocommerce;
545
+
546
+ $key_id = $this->key_id;
547
+ $key_secret = $this->key_secret;
548
+
549
+ $api = new Api($key_id, $key_secret);
550
+
551
+ $sessionKey = $this->getSessionKey($orderId);
552
+
553
+ $attributes = array(
554
+ 'razorpay_payment_id' => $_POST['razorpay_payment_id'],
555
+ 'razorpay_order_id' => $woocommerce->session->get($sessionKey),
556
+ 'razorpay_signature' => $_POST['razorpay_signature'],
557
+ );
558
+
559
+ $api->utility->verifyPaymentSignature($attributes);
560
+ }
561
+
562
+ protected function getErrorMessage($orderId)
563
+ {
564
+ // We don't have a proper order id
565
+ if ($orderId !== null)
566
+ {
567
+ $message = "An error occured while processing this payment";
568
+ }
569
+ if (isset($_POST['error']) === true)
570
+ {
571
+ $error = $_POST['error'];
572
+
573
+ $message = 'An error occured. Description : ' . $error['description'] . '. Code : ' . $error['code'];
574
+
575
+ if (isset($error['field']) === true)
576
  {
577
+ $message .= 'Field : ' . $error['field'];
 
 
 
 
578
  }
579
  }
 
580
  else
581
  {
582
+ $message = 'An error occured. Please contact administrator for assistance';
583
+ }
584
+
585
+ return $message;
586
+ }
587
+
588
+ /**
589
+ * Modifies existing order and handles success case
590
+ *
591
+ * @param $success, & $order
592
+ */
593
+ protected function updateOrder(& $order, $success, $errorMessage, $razorpayPaymentId)
594
+ {
595
+ global $woocommerce;
596
+
597
+ $orderId = $this->getOrderId($order);
598
+
599
+ if ($success === true)
600
+ {
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
+ $woocommerce->cart->empty_cart();
608
+ }
609
+ else
610
+ {
611
+ $this->msg['class'] = 'error';
612
+ $this->msg['message'] = 'Thank you for shopping with us. However, the payment failed.';
613
+
614
+ if ($razorpayPaymentId)
615
  {
616
+ $order->add_order_note("Payment Failed. Please check Razorpay Dashboard. <br/> Razorpay Id: $razorpayPaymentId");
 
 
617
  }
618
+
619
+ $order->add_order_note("Transaction Failed: $errorMessage<br/>");
620
+ $order->update_status('failed');
621
  }
622
+ }
623
+
624
+ protected function handleErrorCase(& $order)
625
+ {
626
+ $orderId = $this->getOrderId($order);
627
+
628
+ $this->msg['class'] = 'error';
629
+ $this->msg['message'] = $this->getErrorMessage($orderId);
630
  }
631
 
632
  /**
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.3.2
7
  License: GPLv2 or later
8
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
9
 
@@ -11,9 +11,9 @@ Allows you to use Razorpay payment gateway with the WooCommerce plugin.
11
 
12
  == Description ==
13
 
14
- This is the official Razorpay payment gateway plugin for WooCommerce. Allows you to accept credit cards, debit cards, netbanking with the WooCommerce plugin. It uses a seamles integration, allowing the customer to pay on your website without being redirected away from your woocommerce website.
15
 
16
- This is compatible with both 2.4 and 2.5 series of WooCommerce.
17
 
18
  == Installation ==
19
 
@@ -34,6 +34,57 @@ This is compatible with both 2.4 and 2.5 series of WooCommerce.
34
  3. Enable the Payment Method, name it Credit Card / Debit Card / Internet Banking (this will show up on the payment page your customer sees), add in your Key id and Key Secret.
35
  4. The Payment Action should be set to "Authorize and Capture". If you want to capture payments manually from the Dashboard after manual verification, set it to "Authorize".
36
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
37
  == Support ==
38
 
39
  Visit [razorpay.com](https://razorpay.com) for support requests or email us at <integrations@razorpay.com>.
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.0
7
  License: GPLv2 or later
8
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
9
 
11
 
12
  == Description ==
13
 
14
+ This is the official Razorpay payment gateway plugin for WooCommerce. Allows you to accept credit cards, debit cards, netbanking, wallet, and UPI payments with the WooCommerce plugin. It uses a seamles integration, allowing the customer to pay on your website without being redirected away. This allows for refunds, works across all browsers, and is compatible with the latest WooCommerce.
15
 
16
+ This is compatible with WooCommerce>=2.4, including the new 3.0 release.
17
 
18
  == Installation ==
19
 
34
  3. Enable the Payment Method, name it Credit Card / Debit Card / Internet Banking (this will show up on the payment page your customer sees), add in your Key id and Key Secret.
35
  4. The Payment Action should be set to "Authorize and Capture". If you want to capture payments manually from the Dashboard after manual verification, set it to "Authorize".
36
 
37
+ == Changelog ==
38
+
39
+ = 1.4.0 =
40
+ * Added Support for WooCommerce 3.x (https://github.com/razorpay/razorpay-woocommerce/pull/35)
41
+ * Fixes around discount coupon handling (Order Amount mismatch)
42
+ * Updates Razorpay SDK
43
+ * Improves Javascript Caching (https://github.com/razorpay/razorpay-woocommerce/pull/39)
44
+ * Adds support for mobile browsers (https://github.com/razorpay/razorpay-woocommerce/pull/37):
45
+ * Chrome on iOS
46
+ * Facebook Browser
47
+ * Internet Explorer Mobile
48
+ * AOSP Browser
49
+ * Opera Mini
50
+ * Google Search App
51
+ * Any other apps using webviews
52
+ * Adds support for refunding payments from within WooCommerce
53
+
54
+ = 1.3.2 =
55
+ * Fixes a Notice about WC_Shortcode_Checkout->output being deprecated
56
+ * PR: https://github.com/razorpay/razorpay-woocommerce/pull/28
57
+
58
+ = 1.3.1 =
59
+ * Improves Session management
60
+ * Diff: https://git.io/vHVBM
61
+
62
+ = 1.3.0 =
63
+ * Shifts to the official [Razorpay SDK](https://github.com/razorpay/razorpay-php)
64
+ * Shifts to the Razorpay Orders API. Allows for auto-capturing and improves success rates
65
+ * Wordpress Versions >=3.9.2 only are supported
66
+
67
+ = 1.2.11 =
68
+ * Fixes issues with Safari and Internet Explorer
69
+
70
+ = 1.2.10 =
71
+ * Improves error handling in case customer clicks on cancel.
72
+ * Orders are now marked as failed if customer clicks cancel
73
+ * Note is added to the order mentioning that the customer cancelled the order.
74
+
75
+ = 1.2.9 =
76
+ * Fixed error handling and capture call
77
+
78
+ = 1.2.8 =
79
+ * Disables buttons while payment is in progress
80
+ * Refactors error message display
81
+
82
+ = 1.2.7 =
83
+ * Redirects customer to order details page, as per WooCommerce guidelines.
84
+
85
+ = 1.2.6 =
86
+ * Adds manual capture option
87
+
88
  == Support ==
89
 
90
  Visit [razorpay.com](https://razorpay.com) for support requests or email us at <integrations@razorpay.com>.
script.js ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ (function() {
2
+ var data = razorpay_wc_checkout_vars;
3
+ var setDisabled = function(id, state) {
4
+ if (typeof state === 'undefined') {
5
+ state = true;
6
+ }
7
+ var elem = document.getElementById(id);
8
+ if (state === false) {
9
+ elem.removeAttribute('disabled');
10
+ } else {
11
+ elem.setAttribute('disabled', state);
12
+ }
13
+ };
14
+
15
+ // Payment was closed without handler getting called
16
+ data.modal = {
17
+ ondismiss: function() {
18
+ setDisabled('btn-razorpay', false);
19
+ },
20
+ };
21
+
22
+ data.handler = function(payment) {
23
+ setDisabled('btn-razorpay-cancel');
24
+ var successMsg = document.getElementById('msg-razorpay-success');
25
+ successMsg.style.display = 'block';
26
+ document.getElementById('razorpay_payment_id').value =
27
+ payment.razorpay_payment_id;
28
+ document.getElementById('razorpay_signature').value =
29
+ payment.razorpay_signature;
30
+ document.razorpayform.submit();
31
+ };
32
+
33
+ var razorpayCheckout = new Razorpay(data);
34
+
35
+ // global method
36
+ function openCheckout() {
37
+ // Disable the pay button
38
+ setDisabled('btn-razorpay');
39
+ razorpayCheckout.open();
40
+ }
41
+
42
+ function addEvent(element, evnt, funct) {
43
+ if (element.attachEvent) return element.attachEvent('on' + evnt, funct);
44
+ else return element.addEventListener(evnt, funct, false);
45
+ }
46
+ // Attach event listener
47
+ window.onload = function() {
48
+ addEvent(document.getElementById('btn-razorpay'), 'click', openCheckout);
49
+ openCheckout();
50
+ };
51
+ })();