Razorpay for WooCommerce - Version 1.6.0-beta

Version Description

  • Added support for subscriptions, please contact us at support@razorpay.com to enable it
Download this release

Release Info

Developer mayankamencherla
Plugin Icon 128x128 Razorpay for WooCommerce
Version 1.6.0-beta
Comparing to
See all releases

Code changes from version 1.5.3 to 1.6.0-beta

includes/Errors/ErrorCode.php CHANGED
@@ -9,12 +9,16 @@ use Razorpay\Api\Errors as ApiErrors;
9
  class ErrorCode extends ApiErrors\ErrorCode
10
  {
11
  const INVALID_CURRENCY_ERROR_CODE = 'INVALID_CURRENCY_ERROR';
12
- const INVALID_CURRENCY_ERROR_MESSAGE = 'The selected currency is invalid.';
13
-
14
  const WOOCS_MISSING_ERROR_CODE = 'WOOCS_MISSING_ERROR';
15
- const WOOCS_MISSING_ERROR_MESSAGE = 'The Woocommerce Currency Switcher plugin is missing.';
16
 
17
- const WOOCS_CURRENCY_MISSING_ERROR_CODE = 'WOOCS_CURRENCY_MISSING_ERROR';
18
- const WOOCS_CURRENCY_MISSING_ERROR_MESSAGE = 'The current currency and INR needs to be configured in Woocommerce Currency Switcher plugin';
 
19
 
 
 
 
 
 
20
  }
9
  class ErrorCode extends ApiErrors\ErrorCode
10
  {
11
  const INVALID_CURRENCY_ERROR_CODE = 'INVALID_CURRENCY_ERROR';
12
+ const WOOCS_CURRENCY_MISSING_ERROR_CODE = 'WOOCS_CURRENCY_MISSING_ERROR';
 
13
  const WOOCS_MISSING_ERROR_CODE = 'WOOCS_MISSING_ERROR';
 
14
 
15
+ const WOOCS_MISSING_ERROR_MESSAGE = 'The WooCommerce Currency Switcher plugin is missing.';
16
+ const INVALID_CURRENCY_ERROR_MESSAGE = 'The selected currency is invalid.';
17
+ const WOOCS_CURRENCY_MISSING_ERROR_MESSAGE = 'Woocommerce Currency Switcher plugin is not configured with INR correctly';
18
 
19
+ // Subscription related errors
20
+ const API_SUBSCRIPTION_CREATION_FAILED = 'Razorpay API subscription creation failed';
21
+ const API_SUBSCRIPTION_CANCELLATION_FAILED = 'Razorpay API subscription cancellation failed';
22
+ const API_PLAN_CREATION_FAILED = 'Razorpay API plan creation failed';
23
+ const API_CUSTOMER_CREATION_FAILED = 'Razorpay API customer creation failed';
24
  }
includes/razorpay-subscriptions.php ADDED
@@ -0,0 +1,334 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ require_once __DIR__.'/../razorpay-sdk/Razorpay.php';
4
+
5
+ use Razorpay\Api\Api;
6
+ use Razorpay\Api\Errors;
7
+ use Razorpay\Woocommerce\Errors as WooErrors;
8
+
9
+ class RZP_Subscriptions
10
+ {
11
+ protected $razorpay;
12
+
13
+ const RAZORPAY_PLAN_ID = 'razorpay_wc_plan_id';
14
+ const INR = 'INR';
15
+
16
+ public function __construct($keyId, $keySecret)
17
+ {
18
+ $this->api = new Api($keyId, $keySecret);
19
+
20
+ $this->razorpay = new WC_Razorpay();
21
+ }
22
+
23
+ public function createSubscription($orderId)
24
+ {
25
+ global $woocommerce;
26
+
27
+ $subscriptionData = $this->getSubscriptionCreateData($orderId);
28
+
29
+ try
30
+ {
31
+ $subscription = $this->api->subscription->create($subscriptionData);
32
+ }
33
+ catch (Exception $e)
34
+ {
35
+ $message = $e->getMessage();
36
+
37
+ throw new Errors\Error(
38
+ $message,
39
+ WooErrors\ErrorCode::API_SUBSCRIPTION_CREATION_FAILED,
40
+ 400
41
+ );
42
+ }
43
+
44
+ // Setting the subscription id as the session variable
45
+ $sessionKey = $this->getSubscriptionSessionKey($orderId);
46
+ $woocommerce->session->set($sessionKey, $subscription['id']);
47
+
48
+ return $subscription['id'];
49
+ }
50
+
51
+ public function cancelSubscription($subscriptionId)
52
+ {
53
+ try
54
+ {
55
+ $subscription = $this->api->subscription->cancel($subscriptionId);
56
+ }
57
+ catch (Exception $e)
58
+ {
59
+ $message = $e->getMessage();
60
+
61
+ throw new Errors\Error(
62
+ $message,
63
+ WooErrors\ErrorCode::API_SUBSCRIPTION_CANCELLATION_FAILED,
64
+ 400
65
+ );
66
+ }
67
+ }
68
+
69
+ protected function getSubscriptionCreateData($orderId)
70
+ {
71
+ $order = new WC_Order($orderId);
72
+
73
+ $product = $this->getProductFromOrder($order);
74
+
75
+ $planId = $this->getProductPlanId($product);
76
+
77
+ $customerId = $this->getCustomerId($order);
78
+
79
+ $length = (int) WC_Subscriptions_Product::get_length($product['product_id']);
80
+
81
+ $subscriptionData = array(
82
+ 'customer_id' => $customerId,
83
+ 'plan_id' => $planId,
84
+ 'quantity' => (int) $product['qty'],
85
+ 'total_count' => $length,
86
+ 'customer_notify' => 0,
87
+ 'notes' => array(
88
+ 'woocommerce_order_id' => $orderId,
89
+ 'woocommerce_product_id' => $product['product_id']
90
+ ),
91
+ );
92
+
93
+ $signUpFee = WC_Subscriptions_Product::get_sign_up_fee($product['product_id']);
94
+
95
+ if ($signUpFee)
96
+ {
97
+ $item = array(
98
+ 'amount' => (int) round($signUpFee * 100),
99
+ 'currency' => get_woocommerce_currency(),
100
+ 'name' => $product['name']
101
+ );
102
+
103
+ if ($item['currency'] !== self::INR)
104
+ {
105
+ $this->razorpay->handleCurrencyConversion($item);
106
+ }
107
+
108
+ $subscriptionData['addons'] = array(array('item' => $item));
109
+ }
110
+
111
+ return $subscriptionData;
112
+ }
113
+
114
+ protected function getProductPlanId($product)
115
+ {
116
+ $currency = get_woocommerce_currency();
117
+
118
+ $key = self::RAZORPAY_PLAN_ID . '_'. strtolower($currency);
119
+
120
+ $productId = $product['product_id'];
121
+
122
+ $metadata = get_post_meta($productId);
123
+
124
+ list($planId, $created) = $this->createOrGetPlanId($metadata, $product, $key);
125
+
126
+ //
127
+ // If new plan was created, we delete the old plan id
128
+ // If we created a new planId, we have to store it as post metadata
129
+ //
130
+ if ($created === true)
131
+ {
132
+ delete_post_meta($productId, $key);
133
+
134
+ add_post_meta($productId, $key, $planId, true);
135
+ }
136
+
137
+ return $planId;
138
+ }
139
+
140
+ /**
141
+ * Takes in product metadata and product
142
+ * Creates or gets created plan
143
+ *
144
+ * @param $metadata,
145
+ * @param $product
146
+ *
147
+ * @return string $planId
148
+ * @return bool $created
149
+ */
150
+ protected function createOrGetPlanId($metadata, $product, $key)
151
+ {
152
+ $planArgs = $this->getPlanArguments($product);
153
+
154
+ //
155
+ // If razorpay_plan_id is set in the metadata,
156
+ // we check if the amounts match and return the plan id
157
+ //
158
+ if (isset($metadata[$key]) === true)
159
+ {
160
+ $create = false;
161
+
162
+ $planId = $metadata[$key][0];
163
+
164
+ try
165
+ {
166
+ $plan = $this->api->plan->fetch($planId);
167
+ }
168
+ catch (Exception $e)
169
+ {
170
+ //
171
+ // If plan id fetch causes an error, we re-create the plan
172
+ //
173
+ $create = true;
174
+ }
175
+
176
+ if (($create === false) and
177
+ ($plan['item']['amount'] === $planArgs['item']['amount']))
178
+ {
179
+ return array($plan['id'], false);
180
+ }
181
+ }
182
+
183
+ //
184
+ // By default we create a new plan
185
+ // if metadata doesn't have plan id set
186
+ //
187
+ $planId = $this->createPlan($planArgs);
188
+
189
+ return array($planId, true);
190
+ }
191
+
192
+ protected function createPlan($planArgs)
193
+ {
194
+ try
195
+ {
196
+ $plan = $this->api->plan->create($planArgs);
197
+ }
198
+ catch (Exception $e)
199
+ {
200
+ $message = $e->getMessage();
201
+
202
+ throw new Errors\Error(
203
+ $message,
204
+ WooErrors\ErrorCode::API_PLAN_CREATION_FAILED,
205
+ 400
206
+ );
207
+ }
208
+
209
+ // Storing the plan id as product metadata, unique set to true
210
+ return $plan['id'];
211
+ }
212
+
213
+ protected function getPlanArguments($product)
214
+ {
215
+ $productId = $product['product_id'];
216
+
217
+ $period = WC_Subscriptions_Product::get_period($productId);
218
+ $interval = WC_Subscriptions_Product::get_interval($productId);
219
+ $recurringFee = WC_Subscriptions_Product::get_price($productId);
220
+
221
+ //
222
+ // Ad-Hoc code
223
+ //
224
+ if ($period === 'year')
225
+ {
226
+ $period = 'month';
227
+
228
+ $interval *= 12;
229
+ }
230
+
231
+ $planArgs = array(
232
+ 'period' => $this->getProductPeriod($period),
233
+ 'interval' => $interval
234
+ );
235
+
236
+ $item = array(
237
+ 'name' => $product['name'],
238
+ 'amount' => (int) round($recurringFee * 100),
239
+ 'currency' => get_woocommerce_currency(),
240
+ );
241
+
242
+ if ($item['currency'] !== self::INR)
243
+ {
244
+ $this->razorpay->handleCurrencyConversion($item);
245
+ }
246
+
247
+ $planArgs['item'] = $item;
248
+
249
+ return $planArgs;
250
+ }
251
+
252
+ public function getDisplayAmount($orderId)
253
+ {
254
+ $order = new WC_Order($orderId);
255
+
256
+ $product = $this->getProductFromOrder($order);
257
+
258
+ $productId = $product['product_id'];
259
+
260
+ $recurringFee = WC_Subscriptions_Product::get_price($productId);
261
+
262
+ $signUpFee = WC_Subscriptions_Product::get_sign_up_fee($productId);
263
+
264
+ return $recurringFee + $signUpFee;
265
+ }
266
+
267
+ protected function getProductPeriod($period)
268
+ {
269
+ $periodMap = array(
270
+ 'day' => 'daily',
271
+ 'week' => 'weekly',
272
+ 'month' => 'monthly',
273
+ 'year' => 'yearly'
274
+ );
275
+
276
+ return $periodMap[$period];
277
+ }
278
+
279
+ protected function getCustomerId($order)
280
+ {
281
+ $data = $this->razorpay->getCustomerInfo($order);
282
+
283
+ //
284
+ // This line of code tells api that if a customer is already created,
285
+ // return the created customer instead of throwing an exception
286
+ // https://docs.razorpay.com/v1/page/customers-api
287
+ //
288
+ $data['fail_existing'] = '0';
289
+
290
+ try
291
+ {
292
+ $customer = $this->api->customer->create($data);
293
+ }
294
+ catch (Exception $e)
295
+ {
296
+ $message = $e->getMessage();
297
+
298
+ throw new Errors\Error(
299
+ $message,
300
+ WooErrors\ErrorCode::API_CUSTOMER_CREATION_FAILED,
301
+ 400
302
+ );
303
+ }
304
+
305
+ return $customer['id'];
306
+ }
307
+
308
+ public function getProductFromOrder($order)
309
+ {
310
+ $products = $order->get_items();
311
+
312
+ //
313
+ // Technically, subscriptions work only if there's one array in the cart
314
+ //
315
+ if (sizeof($products) > 1)
316
+ {
317
+ throw new Exception('Currently Razorpay does not support more than'
318
+ . ' one product in the cart if one of the products'
319
+ . ' is a subscription.');
320
+ }
321
+
322
+ return array_values($products)[0];
323
+ }
324
+
325
+ protected function getSubscriptionSessionKey($orderId)
326
+ {
327
+ return 'razorpay_subscription_id' . $orderId;
328
+ }
329
+
330
+ protected function getRazorpayApiInstance()
331
+ {
332
+ return new Api($this->keyId, $this->keySecret);
333
+ }
334
+ }
includes/razorpay-webhook.php CHANGED
@@ -8,6 +8,8 @@ use Razorpay\Api\Errors;
8
 
9
  class RZP_Webhook
10
  {
 
 
11
  protected $razorpay;
12
  protected $api;
13
 
@@ -60,28 +62,45 @@ class RZP_Webhook
60
  write_log($log);
61
  return;
62
  }
63
- }
64
 
65
- switch ($data['event'])
66
- {
67
- case 'payment.authorized':
68
- return $this->paymentAuthorized($data);
69
 
70
- default:
71
- return;
 
 
 
 
 
 
 
 
72
  }
73
  }
74
  }
75
 
 
 
 
 
 
76
  protected function paymentAuthorized($data)
77
  {
78
- global $woocommerce;
79
-
80
  //
81
  // Order entity should be sent as part of the webhook payload
82
  //
83
  $orderId = $data['payload']['payment']['entity']['notes']['woocommerce_order_id'];
84
 
 
 
 
 
 
 
 
85
  $order = new WC_Order($orderId);
86
 
87
  if ($order->needs_payment() === false)
@@ -91,9 +110,24 @@ class RZP_Webhook
91
 
92
  $razorpayPaymentId = $data['payload']['payment']['entity']['id'];
93
 
94
- $payment = $this->api->payment->fetch($razorpayPaymentId);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
95
 
96
- $amount = $this->razorpay->getOrderAmountAsInteger($order);
97
 
98
  $success = false;
99
  $errorMessage = 'The payment has failed.';
@@ -110,10 +144,162 @@ class RZP_Webhook
110
  // If the merchant has enabled auto capture
111
  //
112
  $payment->capture(array('amount' => $amount));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
113
  }
114
 
115
- $this->razorpay->updateOrder($order, $success, $errorMessage, $razorpayPaymentId);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
116
 
117
  exit;
118
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
119
  }
8
 
9
  class RZP_Webhook
10
  {
11
+ const RAZORPAY_SUBSCRIPTION_ID = 'razorpay_subscription_id';
12
+
13
  protected $razorpay;
14
  protected $api;
15
 
62
  write_log($log);
63
  return;
64
  }
 
65
 
66
+ switch ($data['event'])
67
+ {
68
+ case 'payment.authorized':
69
+ return $this->paymentAuthorized($data);
70
 
71
+ case 'payment.failed':
72
+ return $this->paymentFailed($data);
73
+
74
+ // if it is subscription.charged
75
+ case 'subscription.charged':
76
+ return $this->subscriptionCharged($data);
77
+
78
+ default:
79
+ return;
80
+ }
81
  }
82
  }
83
  }
84
 
85
+ /**
86
+ * Handling the payment authorized webhook
87
+ *
88
+ * @param $data
89
+ */
90
  protected function paymentAuthorized($data)
91
  {
 
 
92
  //
93
  // Order entity should be sent as part of the webhook payload
94
  //
95
  $orderId = $data['payload']['payment']['entity']['notes']['woocommerce_order_id'];
96
 
97
+ $paymentId = $data['payload']['payment']['entity']['id'];
98
+
99
+ if (isset($data['payload']['payment']['entity']['subscription_id']) === true)
100
+ {
101
+ return $this->processSubscription($orderId, $paymentId);
102
+ }
103
+
104
  $order = new WC_Order($orderId);
105
 
106
  if ($order->needs_payment() === false)
110
 
111
  $razorpayPaymentId = $data['payload']['payment']['entity']['id'];
112
 
113
+ try
114
+ {
115
+ $payment = $this->api->payment->fetch($razorpayPaymentId);
116
+ }
117
+ catch (Exception $e)
118
+ {
119
+ $log = array(
120
+ 'message' => $e->getMessage(),
121
+ 'data' => $razorpayPaymentId,
122
+ 'event' => $data['event']
123
+ );
124
+
125
+ write_log($log);
126
+
127
+ exit;
128
+ }
129
 
130
+ $amount = $this->getOrderAmountAsInteger($order);
131
 
132
  $success = false;
133
  $errorMessage = 'The payment has failed.';
144
  // If the merchant has enabled auto capture
145
  //
146
  $payment->capture(array('amount' => $amount));
147
+
148
+ $success = true;
149
+ }
150
+
151
+ $this->razorpay->updateOrder($order, $success, $errorMessage, $razorpayPaymentId, true);
152
+
153
+ exit;
154
+ }
155
+
156
+ /**
157
+ * Currently we handle only subscription failures using this webhook
158
+ *
159
+ * @param $data
160
+ */
161
+ protected function paymentFailed($data)
162
+ {
163
+ //
164
+ // Order entity should be sent as part of the webhook payload
165
+ //
166
+ $orderId = $data['payload']['payment']['entity']['notes']['woocommerce_order_id'];
167
+
168
+ $paymentId = $data['payload']['payment']['entity']['id'];
169
+
170
+ if (isset($data['payload']['payment']['subscription_id']) === true)
171
+ {
172
+ $this->processSubscription($orderId, $paymentId, false);
173
  }
174
 
175
+ exit;
176
+ }
177
+
178
+ /**
179
+ * Handling the subscription charged webhook
180
+ *
181
+ * @param $data
182
+ */
183
+ protected function subscriptionCharged($data)
184
+ {
185
+ //
186
+ // Order entity should be sent as part of the webhook payload
187
+ //
188
+ $orderId = $data['payload']['subscription']['entity']['notes']['woocommerce_order_id'];
189
+
190
+ $this->processSubscription($orderId);
191
 
192
  exit;
193
  }
194
+
195
+ /**
196
+ * Helper method used to handle all subscription processing
197
+ *
198
+ * @param $orderId
199
+ * @param $paymentId
200
+ * @param $success
201
+ */
202
+ protected function processSubscription($orderId, $paymentId, $success = true)
203
+ {
204
+ //
205
+ // If success is false, automatically process subscription failure
206
+ //
207
+ if ($success === false)
208
+ {
209
+ return $this->processSubscriptionFailed($orderId);
210
+ }
211
+
212
+ $subscriptionId = get_post_meta($orderId, self::RAZORPAY_SUBSCRIPTION_ID)[0];
213
+
214
+ $api = $this->razorpay->getRazorpayApiInstance();
215
+
216
+ try
217
+ {
218
+ $subscription = $api->subscription->fetch($subscriptionId);
219
+ }
220
+ catch (Exception $e)
221
+ {
222
+ $message = $e->getMessage();
223
+ return 'RAZORPAY ERROR: Subscription fetch failed with the message \'' . $message . '\'';
224
+ }
225
+
226
+ $this->processSubscriptionSuccess($orderId, $subscription, $paymentId);
227
+
228
+ exit;
229
+ }
230
+
231
+ /**
232
+ * In the case of successful payment, we mark the subscription successful
233
+ *
234
+ * @param $wcSubscription
235
+ * @param $subscription
236
+ */
237
+ protected function processSubscriptionSuccess($orderId, $subscription, $paymentId)
238
+ {
239
+ //
240
+ // This method is used to process the subscription's recurring payment
241
+ //
242
+ $wcSubscription = wcs_get_subscriptions_for_order($orderId);
243
+
244
+ $wcSubscriptionId = array_keys($wcSubscription)[0];
245
+
246
+ //
247
+ // We will only process one subscription per order
248
+ //
249
+ $wcSubscription = array_values($wcSubscription)[0];
250
+
251
+ if (count($wcSubscription) > 1)
252
+ {
253
+ $log = array(
254
+ 'Error' => 'There are more than one subscription products in this order'
255
+ );
256
+
257
+ write_log($log);
258
+
259
+ exit;
260
+ }
261
+
262
+ $paymentCount = $wcSubscription->get_completed_payment_count();
263
+
264
+ //
265
+ // The subscription is completely paid for
266
+ //
267
+ if ($paymentCount === $subscription->total_count)
268
+ {
269
+ return;
270
+ }
271
+ else if ($paymentCount + 1 === $subscription->paid_count)
272
+ {
273
+ //
274
+ // If subscription has been paid for on razorpay's end, we need to mark the
275
+ // subscription payment to be successful on woocommerce's end
276
+ //
277
+ WC_Subscriptions_Manager::prepare_renewal($wcSubscriptionId);
278
+
279
+ $wcSubscription->payment_complete($paymentId);
280
+ }
281
+ }
282
+
283
+ /**
284
+ * In the case of payment failure, we mark the subscription as failed
285
+ *
286
+ * @param $orderId
287
+ */
288
+ protected function processSubscriptionFailed($orderId)
289
+ {
290
+ WC_Subscriptions_Manager::process_subscription_payment_failure_on_order($orderId);
291
+ }
292
+
293
+ /**
294
+ * Returns the order amount, rounded as integer
295
+ */
296
+ public function getOrderAmountAsInteger($order)
297
+ {
298
+ if (version_compare(WOOCOMMERCE_VERSION, '3.0.0', '>='))
299
+ {
300
+ return (int) round($order->get_total() * 100);
301
+ }
302
+
303
+ return (int) round($order->order_total * 100);
304
+ }
305
  }
razorpay-payments.php CHANGED
@@ -3,7 +3,8 @@
3
  Plugin Name: WooCommerce Razorpay Payments
4
  Plugin URI: https://razorpay.com
5
  Description: Razorpay Payment Gateway Integration for WooCommerce
6
- Version: 1.5.3
 
7
  Author: Razorpay
8
  Author URI: https://razorpay.com
9
  */
@@ -15,13 +16,13 @@ if ( ! defined( 'ABSPATH' ) )
15
 
16
  require_once __DIR__.'/includes/razorpay-webhook.php';
17
  require_once __DIR__.'/includes/Errors/ErrorCode.php';
 
 
18
 
19
  use Razorpay\Api\Api;
20
  use Razorpay\Api\Errors;
21
  use Razorpay\Woocommerce\Errors as WooErrors;
22
 
23
- require_once __DIR__.'/razorpay-sdk/Razorpay.php';
24
-
25
  add_action('plugins_loaded', 'woocommerce_razorpay_init', 0);
26
  add_action('admin_post_nopriv_rzp_wc_webhook', 'razorpay_webhook_init');
27
 
@@ -37,13 +38,14 @@ function woocommerce_razorpay_init()
37
  // This one stores the WooCommerce Order Id
38
  const SESSION_KEY = 'razorpay_wc_order_id';
39
  const RAZORPAY_PAYMENT_ID = 'razorpay_payment_id';
 
 
40
 
41
  const INR = 'INR';
42
  const CAPTURE = 'capture';
43
  const AUTHORIZE = 'authorize';
44
  const WC_ORDER_ID = 'woocommerce_order_id';
45
 
46
-
47
  public function __construct()
48
  {
49
  $this->id = 'razorpay';
@@ -80,11 +82,17 @@ function woocommerce_razorpay_init()
80
  $this->supports = array(
81
  'products',
82
  'refunds',
 
 
 
 
83
  );
84
 
85
  $this->msg['message'] = '';
86
  $this->msg['class'] = '';
87
 
 
 
88
  add_action('init', array(&$this, 'check_razorpay_response'));
89
  add_action('woocommerce_api_' . strtolower(get_class($this)), array($this, 'check_razorpay_response'));
90
 
@@ -104,6 +112,8 @@ function woocommerce_razorpay_init()
104
 
105
  function init_form_fields()
106
  {
 
 
107
  $this->form_fields = array(
108
  'enabled' => array(
109
  'title' => __('Enable/Disable', 'razorpay'),
@@ -146,7 +156,7 @@ function woocommerce_razorpay_init()
146
  'enable_webhook' => array(
147
  'title' => __('Enable Webhook', 'razorpay'),
148
  'type' => 'checkbox',
149
- '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>",
150
  'label' => __('Enable Razorpay Webhook <a href="https://dashboard.razorpay.com/#/app/webhooks">here</a> with the URL listed below.', 'razorpay'),
151
  'default' => 'no'
152
  ),
@@ -188,9 +198,14 @@ function woocommerce_razorpay_init()
188
  echo $this->generate_razorpay_form($order);
189
  }
190
 
191
- protected function getSessionKey($orderId)
192
  {
193
- return "razorpay_order_id.$orderId";
 
 
 
 
 
194
  }
195
 
196
  /**
@@ -205,7 +220,7 @@ function woocommerce_razorpay_init()
205
  {
206
  global $woocommerce;
207
 
208
- $sessionKey = $this->getSessionKey($orderId);
209
 
210
  $create = false;
211
 
@@ -257,20 +272,44 @@ function woocommerce_razorpay_init()
257
  **/
258
  public function generate_razorpay_form($orderId)
259
  {
260
- global $woocommerce;
261
  $order = new WC_Order($orderId);
262
 
263
- $redirectUrl = get_site_url() . '/?wc-api=' . get_class($this);
 
264
 
265
- $razorpayOrderId = $this->createOrGetRazorpayOrderId($orderId);
 
 
266
 
267
- if(is_a($razorpayOrderId, 'Exception'))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
268
  {
269
  $message = $razorpayOrderId->getMessage();
270
  return 'RAZORPAY ERROR: Order creation failed with the message \'' . $message . '\'';
271
  }
272
 
273
- $checkoutArgs = $this->getCheckoutArguments($order, $razorpayOrderId);
274
 
275
  $html = '<p>'.__('Thank you for your order, please click the button below to pay with Razorpay.', 'razorpay').'</p>';
276
  $html .= $this->generateOrderForm($redirectUrl, $checkoutArgs);
@@ -281,7 +320,7 @@ function woocommerce_razorpay_init()
281
  /**
282
  * Returns array of checkout params
283
  */
284
- protected function getCheckoutArguments($order, $razorpayOrderId)
285
  {
286
  $callbackUrl = get_site_url() . '/?wc-api=' . get_class($this);
287
 
@@ -292,60 +331,75 @@ function woocommerce_razorpay_init()
292
  $currency = null;
293
 
294
  $args = array(
295
- 'key' => $this->key_id,
296
- 'name' => get_bloginfo('name'),
297
- 'currency' => self::INR,
298
- 'description' => $productinfo,
299
- 'notes' => array (
300
- self::WC_ORDER_ID => $orderId
301
- ),
302
- 'order_id' => $razorpayOrderId,
303
- 'callback_url' => $callbackUrl
304
  );
305
 
306
-
307
-
308
- $args['amount'] = $this->getOrderAmountAsInteger($order);
309
-
310
  if (version_compare(WOOCOMMERCE_VERSION, '2.7.0', '>='))
311
  {
312
- $args['prefill'] = array(
313
- 'name' => $order->get_billing_first_name() . ' ' . $order->get_billing_last_name(),
314
- 'email' => $order->get_billing_email(),
315
- 'contact' => $order->get_billing_phone(),
316
- );
317
  $currency = $order->get_currency();
318
  }
319
  else
320
  {
321
- $args['prefill'] = array(
322
- 'name' => $order->billing_first_name . ' ' . $order->billing_last_name,
323
- 'email' => $order->billing_email,
324
- 'contact' => $order->billing_phone,
325
- );
326
  $currency = $order->get_order_currency();
327
  }
328
 
329
  if ($currency !== self::INR)
330
  {
331
  $args['display_currency'] = $currency;
332
- $args['display_amount'] = $order->get_total();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
333
  }
334
 
335
  return $args;
336
  }
337
 
338
- /**
339
- * Returns the order amount, rounded as integer
340
- */
341
- public function getOrderAmountAsInteger($order)
342
  {
343
- if (version_compare(WOOCOMMERCE_VERSION, '3.0.0', '>='))
344
  {
345
- return (int) round($order->get_total() * 100);
 
 
 
 
 
 
 
 
 
 
 
 
346
  }
347
 
348
- return (int) round($order->order_total * 100);
349
  }
350
 
351
  protected function createRazorpayOrderId($orderId, $sessionKey)
@@ -357,7 +411,15 @@ function woocommerce_razorpay_init()
357
 
358
  $data = $this->getOrderCreationData($orderId);
359
 
360
- $razorpayOrder = $api->order->create($data);
 
 
 
 
 
 
 
 
361
 
362
  $razorpayOrderId = $razorpayOrder['id'];
363
 
@@ -412,7 +474,15 @@ function woocommerce_razorpay_init()
412
 
413
  $api = $this->getRazorpayApiInstance();
414
 
415
- $razorpayOrder = $api->order->fetch($razorpayOrderId);
 
 
 
 
 
 
 
 
416
 
417
  $orderCreationData = $this->getOrderCreationData($orderId);
418
 
@@ -457,23 +527,26 @@ function woocommerce_razorpay_init()
457
 
458
  if ($data['currency'] !== self::INR)
459
  {
460
- if (class_exists('WOOCS'))
461
- {
462
- $this->convertCurrency($data);
463
- }
464
- else
465
- {
466
- throw new Errors\BadRequestError(
467
- WooErrors\ErrorCode::WOOCS_MISSING_ERROR_MESSAGE,
468
- WooErrors\ErrorCode::WOOCS_MISSING_ERROR_CODE,
469
- 400
470
- );
471
- }
472
  }
473
 
474
  return $data;
475
  }
476
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
477
  private function enqueueCheckoutScripts($data)
478
  {
479
  wp_register_script('razorpay_checkout',
@@ -682,20 +755,31 @@ EOT;
682
  {
683
  global $woocommerce;
684
 
685
- $key_id = $this->key_id;
686
- $key_secret = $this->key_secret;
687
-
688
- $api = new Api($key_id, $key_secret);
689
-
690
- $sessionKey = $this->getSessionKey($orderId);
691
 
692
  $attributes = array(
693
  self::RAZORPAY_PAYMENT_ID => $_POST['razorpay_payment_id'],
694
- 'razorpay_order_id' => $woocommerce->session->get($sessionKey),
695
  'razorpay_signature' => $_POST['razorpay_signature'],
696
  );
697
 
 
 
 
 
 
 
 
 
 
 
 
698
  $api->utility->verifyPaymentSignature($attributes);
 
 
 
 
 
 
699
  }
700
 
701
  protected function getErrorMessage($orderId)
@@ -733,7 +817,7 @@ EOT;
733
  *
734
  * @param $success, & $order
735
  */
736
- public function updateOrder(& $order, $success, $errorMessage, $razorpayPaymentId)
737
  {
738
  global $woocommerce;
739
 
@@ -756,7 +840,7 @@ EOT;
756
  else
757
  {
758
  $this->msg['class'] = 'error';
759
- $this->msg['message'] = 'Thank you for shopping with us. However, the payment failed.';
760
 
761
  if ($razorpayPaymentId)
762
  {
@@ -767,7 +851,10 @@ EOT;
767
  $order->update_status('failed');
768
  }
769
 
770
- $this->add_notice($this->msg['message'], $this->msg['class']);
 
 
 
771
  }
772
 
773
  protected function handleErrorCase(& $order)
@@ -778,6 +865,17 @@ EOT;
778
  $this->msg['message'] = $this->getErrorMessage($orderId);
779
  }
780
 
 
 
 
 
 
 
 
 
 
 
 
781
  /**
782
  * Add a woocommerce notification message
783
  *
3
  Plugin Name: WooCommerce Razorpay Payments
4
  Plugin URI: https://razorpay.com
5
  Description: Razorpay Payment Gateway Integration for WooCommerce
6
+ Version: 1.6.0-beta
7
+ Stable tag: 1.5.3
8
  Author: Razorpay
9
  Author URI: https://razorpay.com
10
  */
16
 
17
  require_once __DIR__.'/includes/razorpay-webhook.php';
18
  require_once __DIR__.'/includes/Errors/ErrorCode.php';
19
+ require_once __DIR__.'/razorpay-sdk/Razorpay.php';
20
+ require_once __DIR__.'/includes/razorpay-subscriptions.php';
21
 
22
  use Razorpay\Api\Api;
23
  use Razorpay\Api\Errors;
24
  use Razorpay\Woocommerce\Errors as WooErrors;
25
 
 
 
26
  add_action('plugins_loaded', 'woocommerce_razorpay_init', 0);
27
  add_action('admin_post_nopriv_rzp_wc_webhook', 'razorpay_webhook_init');
28
 
38
  // This one stores the WooCommerce Order Id
39
  const SESSION_KEY = 'razorpay_wc_order_id';
40
  const RAZORPAY_PAYMENT_ID = 'razorpay_payment_id';
41
+ const RAZORPAY_ORDER_ID = 'razorpay_order_id';
42
+ const RAZORPAY_SUBSCRIPTION_ID = 'razorpay_subscription_id';
43
 
44
  const INR = 'INR';
45
  const CAPTURE = 'capture';
46
  const AUTHORIZE = 'authorize';
47
  const WC_ORDER_ID = 'woocommerce_order_id';
48
 
 
49
  public function __construct()
50
  {
51
  $this->id = 'razorpay';
82
  $this->supports = array(
83
  'products',
84
  'refunds',
85
+ 'subscriptions',
86
+ 'subscription_reactivation',
87
+ 'subscription_suspension',
88
+ 'subscription_cancellation',
89
  );
90
 
91
  $this->msg['message'] = '';
92
  $this->msg['class'] = '';
93
 
94
+ add_action('woocommerce_subscription_status_cancelled', array(&$this, 'subscription_cancelled'));
95
+
96
  add_action('init', array(&$this, 'check_razorpay_response'));
97
  add_action('woocommerce_api_' . strtolower(get_class($this)), array($this, 'check_razorpay_response'));
98
 
112
 
113
  function init_form_fields()
114
  {
115
+ $webhookUrl = esc_url(admin_url('admin-post.php')) . '?action=rzp_wc_webhook';
116
+
117
  $this->form_fields = array(
118
  'enabled' => array(
119
  'title' => __('Enable/Disable', 'razorpay'),
156
  'enable_webhook' => array(
157
  'title' => __('Enable Webhook', 'razorpay'),
158
  'type' => 'checkbox',
159
+ 'description' => "<span>$webhookUrl</span><br/><br/>Instructions and guide to <a href='https://github.com/razorpay/razorpay-woocommerce/wiki/Razorpay-Woocommerce-Webhooks'>Razorpay webhooks</a>",
160
  'label' => __('Enable Razorpay Webhook <a href="https://dashboard.razorpay.com/#/app/webhooks">here</a> with the URL listed below.', 'razorpay'),
161
  'default' => 'no'
162
  ),
198
  echo $this->generate_razorpay_form($order);
199
  }
200
 
201
+ protected function getOrderSessionKey($orderId)
202
  {
203
+ return self::RAZORPAY_ORDER_ID . $orderId;
204
+ }
205
+
206
+ protected function getSubscriptionSessionKey($orderId)
207
+ {
208
+ return self::RAZORPAY_SUBSCRIPTION_ID . $orderId;
209
  }
210
 
211
  /**
220
  {
221
  global $woocommerce;
222
 
223
+ $sessionKey = $this->getOrderSessionKey($orderId);
224
 
225
  $create = false;
226
 
272
  **/
273
  public function generate_razorpay_form($orderId)
274
  {
 
275
  $order = new WC_Order($orderId);
276
 
277
+ $subscriptionId = null;
278
+ $razorpayOrderId = null;
279
 
280
+ if (wcs_order_contains_subscription($order) === true)
281
+ {
282
+ $this->subscriptions = new RZP_Subscriptions($this->key_id, $this->key_secret);
283
 
284
+ try
285
+ {
286
+ $subscriptionId = $this->subscriptions->createSubscription($orderId);
287
+ }
288
+ catch (Exception $e)
289
+ {
290
+ $message = $e->getMessage();
291
+ return 'RAZORPAY ERROR: Subscription creation failed with the following message \'' . $message . '\'';
292
+ }
293
+ }
294
+ else
295
+ {
296
+ $razorpayOrderId = $this->createOrGetRazorpayOrderId($orderId);
297
+ }
298
+
299
+ $redirectUrl = get_site_url() . '/?wc-api=' . get_class($this);
300
+
301
+ if (($razorpayOrderId === null) and
302
+ (wcs_order_contains_subscription($orderId) === false))
303
+ {
304
+ return 'RAZORPAY ERROR: Api could not be reached';
305
+ }
306
+ else if($razorpayOrderId instanceof Exception)
307
  {
308
  $message = $razorpayOrderId->getMessage();
309
  return 'RAZORPAY ERROR: Order creation failed with the message \'' . $message . '\'';
310
  }
311
 
312
+ $checkoutArgs = $this->getCheckoutArguments($order, $razorpayOrderId, $subscriptionId);
313
 
314
  $html = '<p>'.__('Thank you for your order, please click the button below to pay with Razorpay.', 'razorpay').'</p>';
315
  $html .= $this->generateOrderForm($redirectUrl, $checkoutArgs);
320
  /**
321
  * Returns array of checkout params
322
  */
323
+ protected function getCheckoutArguments($order, $razorpayOrderId, $subscriptionId)
324
  {
325
  $callbackUrl = get_site_url() . '/?wc-api=' . get_class($this);
326
 
331
  $currency = null;
332
 
333
  $args = array(
334
+ 'key' => $this->key_id,
335
+ 'name' => get_bloginfo('name'),
336
+ 'currency' => 'INR',
337
+ 'description' => $productinfo,
338
+ 'notes' => array(
339
+ 'woocommerce_order_id' => $orderId
340
+ ),
341
+ 'callback_url' => $callbackUrl,
342
+ 'prefill' => $this->getCustomerInfo($order)
343
  );
344
 
 
 
 
 
345
  if (version_compare(WOOCOMMERCE_VERSION, '2.7.0', '>='))
346
  {
 
 
 
 
 
347
  $currency = $order->get_currency();
348
  }
349
  else
350
  {
 
 
 
 
 
351
  $currency = $order->get_order_currency();
352
  }
353
 
354
  if ($currency !== self::INR)
355
  {
356
  $args['display_currency'] = $currency;
357
+ $args['display_amount'] = (int) round($order->get_total());
358
+ }
359
+
360
+ // order_id and subscription_id both cannot be set at the same time
361
+ if (empty($razorpayOrderId) === false)
362
+ {
363
+ $args['order_id'] = $razorpayOrderId;
364
+ }
365
+ else if (empty($subscriptionId) === false)
366
+ {
367
+ $args['recurring'] = 1;
368
+ $args['subscription_id'] = $subscriptionId;
369
+
370
+ if ($currency !== self::INR)
371
+ {
372
+ $args['display_amount'] = $this->subscriptions->getDisplayAmount($orderId);
373
+ }
374
+ }
375
+ else
376
+ {
377
+ throw new Exception('Both orderId and subscriptionId are null!');
378
  }
379
 
380
  return $args;
381
  }
382
 
383
+ public function getCustomerInfo($order)
 
 
 
384
  {
385
+ if (version_compare(WOOCOMMERCE_VERSION, '2.7.0', '>='))
386
  {
387
+ $args = array(
388
+ 'name' => $order->get_billing_first_name() . ' ' . $order->get_billing_last_name(),
389
+ 'email' => $order->get_billing_email(),
390
+ 'contact' => $order->get_billing_phone(),
391
+ );
392
+ }
393
+ else
394
+ {
395
+ $args = array(
396
+ 'name' => $order->billing_first_name . ' ' . $order->billing_last_name,
397
+ 'email' => $order->billing_email,
398
+ 'contact' => $order->billing_phone,
399
+ );
400
  }
401
 
402
+ return $args;
403
  }
404
 
405
  protected function createRazorpayOrderId($orderId, $sessionKey)
411
 
412
  $data = $this->getOrderCreationData($orderId);
413
 
414
+ try
415
+ {
416
+ $razorpayOrder = $api->order->create($data);
417
+ }
418
+ catch (Exception $e)
419
+ {
420
+ $message = $e->getMessage();
421
+ return 'RAZORPAY ERROR: Order creation failed with the message \'' . $message . '\'';
422
+ }
423
 
424
  $razorpayOrderId = $razorpayOrder['id'];
425
 
474
 
475
  $api = $this->getRazorpayApiInstance();
476
 
477
+ try
478
+ {
479
+ $razorpayOrder = $api->order->fetch($razorpayOrderId);
480
+ }
481
+ catch (Exception $e)
482
+ {
483
+ $message = $e->getMessage();
484
+ return 'RAZORPAY ERROR: Order fetch failed with the message \'' . $message . '\'';
485
+ }
486
 
487
  $orderCreationData = $this->getOrderCreationData($orderId);
488
 
527
 
528
  if ($data['currency'] !== self::INR)
529
  {
530
+ $this->handleCurrencyConversion($data);
 
 
 
 
 
 
 
 
 
 
 
531
  }
532
 
533
  return $data;
534
  }
535
 
536
+ public function handleCurrencyConversion(& $data)
537
+ {
538
+ if (class_exists('WOOCS') === false)
539
+ {
540
+ throw new Errors\BadRequestError(
541
+ WooErrors\ErrorCode::WOOCS_MISSING_ERROR_MESSAGE,
542
+ WooErrors\ErrorCode::WOOCS_MISSING_ERROR_CODE,
543
+ 400
544
+ );
545
+ }
546
+
547
+ $this->convertCurrency($data);
548
+ }
549
+
550
  private function enqueueCheckoutScripts($data)
551
  {
552
  wp_register_script('razorpay_checkout',
755
  {
756
  global $woocommerce;
757
 
758
+ $api = $this->getRazorpayApiInstance();
 
 
 
 
 
759
 
760
  $attributes = array(
761
  self::RAZORPAY_PAYMENT_ID => $_POST['razorpay_payment_id'],
 
762
  'razorpay_signature' => $_POST['razorpay_signature'],
763
  );
764
 
765
+ if (wcs_order_contains_subscription($orderId) === true)
766
+ {
767
+ $sessionKey = $this->getSubscriptionSessionKey($orderId);
768
+ $attributes[self::RAZORPAY_SUBSCRIPTION_ID] = $woocommerce->session->get($sessionKey);
769
+ }
770
+ else
771
+ {
772
+ $sessionKey = $this->getOrderSessionKey($orderId);
773
+ $attributes[self::RAZORPAY_ORDER_ID] = $woocommerce->session->get($sessionKey);
774
+ }
775
+
776
  $api->utility->verifyPaymentSignature($attributes);
777
+
778
+ // Once the signature passes, save the subscription id as order metadata
779
+ if (wcs_order_contains_subscription($orderId) === true)
780
+ {
781
+ add_post_meta($orderId, self::RAZORPAY_SUBSCRIPTION_ID, $attributes[self::RAZORPAY_SUBSCRIPTION_ID]);
782
+ }
783
  }
784
 
785
  protected function getErrorMessage($orderId)
817
  *
818
  * @param $success, & $order
819
  */
820
+ public function updateOrder(& $order, $success, $errorMessage, $razorpayPaymentId, $webhook = false)
821
  {
822
  global $woocommerce;
823
 
840
  else
841
  {
842
  $this->msg['class'] = 'error';
843
+ $this->msg['message'] = $errorMessage;
844
 
845
  if ($razorpayPaymentId)
846
  {
851
  $order->update_status('failed');
852
  }
853
 
854
+ if ($webhook === false)
855
+ {
856
+ $this->add_notice($this->msg['message'], $this->msg['class']);
857
+ }
858
  }
859
 
860
  protected function handleErrorCase(& $order)
865
  $this->msg['message'] = $this->getErrorMessage($orderId);
866
  }
867
 
868
+ public function subscription_cancelled($subscription)
869
+ {
870
+ $orderIds = array_keys($subscription->get_related_orders());
871
+
872
+ $parentOrderId = $orderIds[0];
873
+
874
+ $subscriptionId = get_post_meta($parentOrderId, self::RAZORPAY_SUBSCRIPTION_ID)[0];
875
+
876
+ $this->subscriptions->cancelSubscription($subscriptionId);
877
+ }
878
+
879
  /**
880
  * Add a woocommerce notification message
881
  *
razorpay-sdk/src/Entity.php CHANGED
@@ -99,7 +99,7 @@ class Entity extends Resource implements ArrayableInterface
99
  {
100
  $entity = new self;
101
 
102
- $entity->fill($data);
103
  }
104
 
105
  return $entity;
@@ -216,4 +216,4 @@ class Entity extends Resource implements ArrayableInterface
216
 
217
  return $array;
218
  }
219
- }
99
  {
100
  $entity = new self;
101
 
102
+ $entity->fill($data);
103
  }
104
 
105
  return $entity;
216
 
217
  return $array;
218
  }
219
+ }
razorpay-sdk/src/Plan.php ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Razorpay\Api;
4
+
5
+ class Plan extends Entity
6
+ {
7
+ public function create($attributes = array())
8
+ {
9
+ return parent::create($attributes);
10
+ }
11
+
12
+ public function fetch($id)
13
+ {
14
+ return parent::fetch($id);
15
+ }
16
+
17
+ public function all($options = array())
18
+ {
19
+ return parent::all($options);
20
+ }
21
+ }
razorpay-sdk/src/Request.php CHANGED
@@ -206,4 +206,4 @@ class Request
206
  $this->throwServerError($body, $httpStatusCode);
207
  }
208
  }
209
- }
206
  $this->throwServerError($body, $httpStatusCode);
207
  }
208
  }
209
+ }
razorpay-sdk/src/Subscription.php ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Razorpay\Api;
4
+
5
+ class Subscription extends Entity
6
+ {
7
+ public function create($attributes = array())
8
+ {
9
+ return parent::create($attributes);
10
+ }
11
+
12
+ public function fetch($id)
13
+ {
14
+ return parent::fetch($id);
15
+ }
16
+
17
+ public function all($options = array())
18
+ {
19
+ return parent::all($options);
20
+ }
21
+
22
+ public function cancel($subscriptionId)
23
+ {
24
+ $relativeUrl = $this->getEntityUrl() . $subscriptionId . '/cancel';
25
+
26
+ return $this->request('POST', $relativeUrl);
27
+ }
28
+ }
razorpay-sdk/src/Utility.php CHANGED
@@ -9,10 +9,25 @@ class Utility
9
  public function verifyPaymentSignature($attributes)
10
  {
11
  $expectedSignature = $attributes['razorpay_signature'];
12
- $orderId = $attributes['razorpay_order_id'];
13
  $paymentId = $attributes['razorpay_payment_id'];
14
 
15
- $payload = $orderId . '|' . $paymentId;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16
 
17
  return self::verifySignature($payload, $expectedSignature);
18
  }
9
  public function verifyPaymentSignature($attributes)
10
  {
11
  $expectedSignature = $attributes['razorpay_signature'];
 
12
  $paymentId = $attributes['razorpay_payment_id'];
13
 
14
+ if (isset($attributes['razorpay_order_id']) === true)
15
+ {
16
+ $orderId = $attributes['razorpay_order_id'];
17
+
18
+ $payload = $orderId . '|' . $paymentId;
19
+ }
20
+ else if (isset($attributes['razorpay_subscription_id']) === true)
21
+ {
22
+ $subscriptionId = $attributes['razorpay_subscription_id'];
23
+
24
+ $payload = $paymentId . '|' . $subscriptionId ;
25
+ }
26
+ else
27
+ {
28
+ throw new Error('Invalid parameters passed to verifyPaymentSignature:'
29
+ . 'At least razorpay_order_id or razorpay_subscription_id should be set.');
30
+ }
31
 
32
  return self::verifySignature($payload, $expectedSignature);
33
  }
readme.txt CHANGED
@@ -2,7 +2,7 @@
2
  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.5.3
7
  License: GPLv2 or later
8
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
@@ -13,7 +13,7 @@ Allows you to use Razorpay payment gateway with the WooCommerce plugin.
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
 
@@ -36,6 +36,9 @@ This is compatible with WooCommerce>=2.4, including the new 3.0 release.
36
 
37
  == Changelog ==
38
 
 
 
 
39
  = 1.5.3 =
40
  * Webhooks are now disabled by default ([#52](https://github.com/razorpay/razorpay-woocommerce/pull/52))
41
 
2
  Contributors: razorpay
3
  Tags: razorpay, payments, india, woocommerce, ecommerce
4
  Requires at least: 3.9.2
5
+ Tested up to: 4.8
6
  Stable tag: 1.5.3
7
  License: GPLv2 or later
8
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
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. It has been tested upto the 3.1.1 WooCommerce release.
17
 
18
  == Installation ==
19
 
36
 
37
  == Changelog ==
38
 
39
+ = 1.6.0-beta =
40
+ * Added support for subscriptions, please contact us at support@razorpay.com to enable it
41
+
42
  = 1.5.3 =
43
  * Webhooks are now disabled by default ([#52](https://github.com/razorpay/razorpay-woocommerce/pull/52))
44