Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions razorpay/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,14 @@ class Client:
'base_url': URL.BASE_URL
}

def __init__(self, session=None, auth=None, **options):
def __init__(self, session=None, auth=None, public_auth=None, **options):
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this doesn't make sense, auth already contains the public key, should directly use from there

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At first, I thought the integration team would create only one client, so I added a field to separate the auth. Removed this now, integration team will create two different client (one for public auth for activity related API and other for private auth for Order related APIs)

"""
Initialize a Client object with session,
optional auth handler, and options
"""
self.session = session or requests.Session()
self.auth = auth
self.public_auth = public_auth
file_dir = os.path.dirname(__file__)
self.cert_path = file_dir + '/ca-bundle.crt'

Expand Down Expand Up @@ -115,9 +116,20 @@ def request(self, method, path, **options):
"""
options = self._update_user_agent_header(options)

# Determine authentication type
use_public_auth = options.pop('use_public_auth', False)
auth_to_use = self.public_auth if use_public_auth and self.public_auth else self.auth

# Inject device mode header if provided
device_mode = options.pop('device_mode', None)
if device_mode is not None:
if 'headers' not in options:
options['headers'] = {}
options['headers']['X-Razorpay-Device-Mode'] = device_mode

url = "{}{}".format(self.base_url, path)

response = getattr(self.session, method)(url, auth=self.auth,
response = getattr(self.session, method)(url, auth=auth_to_use,
verify=self.cert_path,
**options)
if ((response.status_code >= HTTP_STATUS_CODE.OK) and
Expand Down
3 changes: 3 additions & 0 deletions razorpay/constants/device.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
class DeviceMode:
WIRED = "wired"
WIRELESS = "wireless"
2 changes: 2 additions & 0 deletions razorpay/constants/url.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,5 @@ class URL(object):
DOCUMENT= "/documents"
DISPUTE= "/disputes"

DEVICE_ACTIVITY_URL = "/devices/activity"

2 changes: 2 additions & 0 deletions razorpay/resources/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
from .webhook import Webhook
from .document import Document
from .dispute import Dispute
from .device_activity import DeviceActivity

__all__ = [
'Payment',
Expand Down Expand Up @@ -50,4 +51,5 @@
'Webhook',
'Document',
'Dispute',
'DeviceActivity',
]
55 changes: 55 additions & 0 deletions razorpay/resources/device_activity.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
from typing import Any, Dict, Optional

from .base import Resource
from ..constants.url import URL
from ..constants.device import DeviceMode
from ..errors import BadRequestError


class DeviceActivity(Resource):
def __init__(self, client=None):
super(DeviceActivity, self).__init__(client)
self.base_url = URL.V1 + URL.DEVICE_ACTIVITY_URL

def create(self, data: Dict[str, Any], mode: Optional[str] = None, **kwargs) -> Dict[str, Any]:
"""
Create a new device activity for POS gateway

Args:
data: Dictionary containing device activity data in the format expected by rzp-pos-gateway
mode: Device communication mode ("wired" or "wireless")

Returns:
DeviceActivity object
"""
device_mode = None
if mode is not None:
if mode not in (DeviceMode.WIRED, DeviceMode.WIRELESS):
raise BadRequestError("Invalid device mode. Allowed values are 'wired' and 'wireless'.")
device_mode = mode

url = self.base_url
return self.post_url(url, data, use_public_auth=True, device_mode=device_mode, **kwargs)

def get_status(self, activity_id: str, mode: Optional[str] = None, **kwargs) -> Dict[str, Any]:
"""
Get the status of a device activity

Args:
activity_id: Activity ID to fetch status for
mode: Device communication mode ("wired" or "wireless")

Returns:
DeviceActivity object with current status
"""
if not activity_id:
raise BadRequestError("Activity ID must be provided")

device_mode = None
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can be extracted as separate method

if mode is not None:
if mode not in (DeviceMode.WIRED, DeviceMode.WIRELESS):
raise BadRequestError("Invalid device mode. Allowed values are 'wired' and 'wireless'.")
device_mode = mode

url = f"{self.base_url}/{activity_id}"
return self.get_url(url, {}, use_public_auth=True, device_mode=device_mode, **kwargs)
1 change: 1 addition & 0 deletions tests/mocks/fake_device_activity.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"id": "act_123", "status": "created", "mode": "wired"}
1 change: 1 addition & 0 deletions tests/mocks/fake_device_activity_status.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"id": "act_123", "status": "in_progress", "mode": "wireless"}
36 changes: 36 additions & 0 deletions tests/test_client_device_activity.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import unittest
import responses
import json

from .helpers import mock_file, ClientTestCase
from razorpay.errors import BadRequestError
import razorpay


class TestClientDeviceActivity(ClientTestCase):

def setUp(self):
super(TestClientDeviceActivity, self).setUp()
self.device_activity_base_url = f"{self.base_url}/devices/activity"
self.public_client = razorpay.Client(auth=('key_id', 'key_secret'), public_auth=('public_key', ''))

@responses.activate
def test_create_device_activity(self):
result = mock_file('fake_device_activity')
url = self.device_activity_base_url
responses.add(responses.POST, url, status=200,
body=json.dumps(result), match_querystring=True)
self.assertEqual(self.public_client.device_activity.create({'foo': 'bar'}, mode='wired'), result)

@responses.activate
def test_get_status_device_activity(self):
activity_id = 'act_123'
result = mock_file('fake_device_activity_status')
url = f"{self.device_activity_base_url}/{activity_id}"
responses.add(responses.GET, url, status=200,
body=json.dumps(result), match_querystring=True)
self.assertEqual(self.public_client.device_activity.get_status(activity_id, mode='wireless'), result)

def test_invalid_mode_raises(self):
with self.assertRaises(BadRequestError):
self.public_client.device_activity.create({'foo': 'bar'}, mode='invalid')
4 changes: 2 additions & 2 deletions tests/test_multiple_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ class TestClientPayment(ClientTestCase):
def setUp(self):
super(TestClientPayment, self).setUp()
self.base_url = '{}/payments'.format(self.base_url)
self.secondary_base_url = '{}/payments'.format(self.secondary_url)
self.secondary_base_url = '{}/v1/payments'.format(self.secondary_url)

@responses.activate
def test_payment_primary_url(self):
Expand All @@ -20,7 +20,7 @@ def test_payment_primary_url(self):
body=json.dumps(result), match_querystring=True)
self.assertEqual(self.client.payment.all(), result)

@unittest.skip
@responses.activate
def test_payment_secondary_url(self):
result = mock_file('payment_collection')
url = self.secondary_base_url
Expand Down
Loading