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 | Razorpay for WooCommerce |
Version | 1.4.0 |
Comparing to | |
See all releases |
Code changes from version 1.3.2 to 1.4.0
- razorpay-payments.php +341 -171
- readme.txt +54 -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.
|
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->
|
44 |
-
|
|
|
|
|
|
|
|
|
|
|
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 |
-
*
|
144 |
-
|
145 |
-
|
|
|
|
|
|
|
|
|
|
|
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 |
-
$
|
166 |
-
|
|
|
|
|
|
|
167 |
}
|
168 |
}
|
|
|
|
|
169 |
catch (Exception $e)
|
170 |
{
|
171 |
-
|
172 |
}
|
173 |
|
174 |
-
|
175 |
-
|
176 |
-
|
177 |
-
|
178 |
-
|
179 |
-
|
180 |
-
|
181 |
-
|
182 |
-
|
183 |
-
|
184 |
-
|
185 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
186 |
'woocommerce_order_id' => $orderId
|
187 |
),
|
188 |
-
'order_id'
|
|
|
189 |
);
|
190 |
|
191 |
-
$
|
192 |
|
193 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
194 |
|
195 |
-
return $
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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->
|
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 =
|
220 |
|
221 |
$razorpayOrder = $api->order->fetch($razorpayOrderId);
|
222 |
|
223 |
$razorpayOrderArgs = array(
|
224 |
'id' => $razorpayOrderId,
|
225 |
-
'amount' => (
|
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
|
244 |
{
|
245 |
-
$order = new WC_Order($
|
246 |
|
247 |
if (!isset($this->payment_action))
|
248 |
{
|
@@ -250,38 +339,45 @@ function woocommerce_razorpay_init()
|
|
250 |
}
|
251 |
|
252 |
$data = array(
|
253 |
-
'receipt'
|
254 |
-
'amount'
|
255 |
-
'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
|
276 |
{
|
277 |
-
$
|
278 |
-
|
279 |
-
|
280 |
-
|
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 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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', $
|
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->
|
363 |
-
add_query_arg('key', $
|
364 |
);
|
365 |
}
|
366 |
else
|
367 |
{
|
368 |
return array(
|
369 |
'result' => 'success',
|
370 |
-
'redirect' => add_query_arg('order', $order->
|
371 |
-
add_query_arg('key', $
|
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 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
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 |
-
$
|
394 |
-
$payment = $api->payment->fetch($razorpay_payment_id);
|
395 |
|
396 |
try
|
397 |
{
|
398 |
-
|
399 |
-
|
400 |
-
|
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 (
|
422 |
{
|
423 |
-
$
|
424 |
-
$error = 'WOOCOMMERCE_ERROR: Request to Razorpay Failed';
|
425 |
}
|
426 |
-
|
427 |
-
|
428 |
-
|
429 |
-
|
430 |
-
|
431 |
-
|
432 |
-
|
433 |
-
|
434 |
-
|
435 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
436 |
{
|
437 |
-
$
|
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 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
448 |
{
|
449 |
-
$order
|
450 |
-
$order->update_status('failed');
|
451 |
-
$order->add_order_note('Customer cancelled the payment');
|
452 |
}
|
453 |
-
|
454 |
-
$
|
|
|
455 |
}
|
456 |
-
|
457 |
-
|
458 |
-
|
459 |
-
|
|
|
|
|
|
|
|
|
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.
|
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
|
15 |
|
16 |
-
This is compatible with
|
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 |
+
})();
|