diff --git a/documents/dispute.md b/documents/dispute.md
new file mode 100644
index 00000000..79b7c0e2
--- /dev/null
+++ b/documents/dispute.md
@@ -0,0 +1,286 @@
+## Document
+
+### Fetch All Disputes
+
+```py
+client.dispute.all()
+```
+
+**Response:**
+```json
+{
+ "entity": "collection",
+ "count": 1,
+ "items": [
+ {
+ "id": "disp_Esz7KAitoYM7PJ",
+ "entity": "dispute",
+ "payment_id": "pay_EsyWjHrfzb59eR",
+ "amount": 10000,
+ "currency": "INR",
+ "amount_deducted": 0,
+ "reason_code": "pre_arbitration",
+ "respond_by": 1590604200,
+ "status": "open",
+ "phase": "pre_arbitration",
+ "created_at": 1590059211,
+ "evidence": {
+ "amount": 10000,
+ "summary": null,
+ "shipping_proof": null,
+ "billing_proof": null,
+ "cancellation_proof": null,
+ "customer_communication": null,
+ "proof_of_service": null,
+ "explanation_letter": null,
+ "refund_confirmation": null,
+ "access_activity_log": null,
+ "refund_cancellation_policy": null,
+ "term_and_conditions": null,
+ "others": null,
+ "submitted_at": null
+ }
+ }
+ ]
+}
+```
+-------------------------------------------------------------------------------------------------------
+
+### Fetch a Dispute
+
+```py
+disputeId = "disp_0000000000000";
+
+client.dispute.fetch(disputeId);
+```
+
+**Parameters:**
+
+| Name | Type | Description |
+|-------|-----------|--------------------------------------------------|
+| disputeId* | string | The unique identifier of the dispute. |
+
+**Response:**
+```json
+{
+ "id": "disp_AHfqOvkldwsbqt",
+ "entity": "dispute",
+ "payment_id": "pay_EsyWjHrfzb59eR",
+ "amount": 10000,
+ "currency": "INR",
+ "amount_deducted": 0,
+ "reason_code": "pre_arbitration",
+ "respond_by": 1590604200,
+ "status": "open",
+ "phase": "pre_arbitration",
+ "created_at": 1590059211,
+ "evidence": {
+ "amount": 10000,
+ "summary": "goods delivered",
+ "shipping_proof": null,
+ "billing_proof": null,
+ "cancellation_proof": null,
+ "customer_communication": null,
+ "proof_of_service": null,
+ "explanation_letter": null,
+ "refund_confirmation": null,
+ "access_activity_log": null,
+ "refund_cancellation_policy": null,
+ "term_and_conditions": null,
+ "others": null,
+ "submitted_at": null
+ }
+}
+```
+-------------------------------------------------------------------------------------------------------
+
+### Fetch a Dispute
+
+```py
+disputeId = "disp_0000000000000";
+
+client.dispute.accept(disputeId);
+```
+
+**Parameters:**
+
+| Name | Type | Description |
+|-------|-----------|--------------------------------------------------|
+| disputeId* | string | The unique identifier of the dispute. |
+
+**Response:**
+```json
+{
+ "id": "disp_AHfqOvkldwsbqt",
+ "entity": "dispute",
+ "payment_id": "pay_EsyWjHrfzb59eR",
+ "amount": 10000,
+ "currency": "INR",
+ "amount_deducted": 10000,
+ "reason_code": "pre_arbitration",
+ "respond_by": 1590604200,
+ "status": "lost",
+ "phase": "pre_arbitration",
+ "created_at": 1590059211,
+ "evidence": {
+ "amount": 10000,
+ "summary": null,
+ "shipping_proof": null,
+ "billing_proof": null,
+ "cancellation_proof": null,
+ "customer_communication": null,
+ "proof_of_service": null,
+ "explanation_letter": null,
+ "refund_confirmation": null,
+ "access_activity_log": null,
+ "refund_cancellation_policy": null,
+ "term_and_conditions": null,
+ "others": null,
+ "submitted_at": null
+ }
+}
+```
+-------------------------------------------------------------------------------------------------------
+### Contest a Dispute
+
+```py
+# Use this API sample code for draft
+
+disputeId = "disp_0000000000000";
+
+client.dispute.contest(disputeId,{
+ "amount": 5000,
+ "summary": "goods delivered",
+ "shipping_proof": [
+ "doc_EFtmUsbwpXwBH9",
+ "doc_EFtmUsbwpXwBH8"
+ ],
+ "others": [
+ {
+ "type": "receipt_signed_by_customer",
+ "document_ids": [
+ "doc_EFtmUsbwpXwBH1",
+ "doc_EFtmUsbwpXwBH7"
+ ]
+ }
+ ],
+ "action": "draft"
+})
+```
+
+**Parameters:**
+
+| Name | Type | Description |
+|-------|-----------|--------------------------------------------------|
+| disputeId* | string | The unique identifier of the dispute. |
+| amount | integer | The amount being contested. If the contest amount is not mentioned, we will assume it to be a full dispute contest. |
+| summary | string | The explanation provided by you for contesting the dispute. It can have a maximum length of 1000 characters. |
+| shipping_proof | array | List of document ids which serves as proof that the product was shipped to the customer at their provided address. It should show their complete shipping address, if possible. |
+| others | array | All keys listed [here](https://razorpay.com/docs/api/disputes/contest) are supported |
+
+```py
+# Use this API sample code for submit
+
+client.dispute.contest(disputeId,{
+ "billing_proof": [
+ "doc_EFtmUsbwpXwBG9",
+ "doc_EFtmUsbwpXwBG8"
+ ],
+ "action": "submit"
+})
+```
+
+**Response:**
+```json
+// Draft
+{
+ "id": "disp_AHfqOvkldwsbqt",
+ "entity": "dispute",
+ "payment_id": "pay_EsyWjHrfzb59eR",
+ "amount": 10000,
+ "currency": "INR",
+ "amount_deducted": 0,
+ "reason_code": "chargeback",
+ "respond_by": 1590604200,
+ "status": "open",
+ "phase": "chargeback",
+ "created_at": 1590059211,
+ "evidence": {
+ "amount": 5000,
+ "summary": "goods delivered",
+ "shipping_proof": [
+ "doc_EFtmUsbwpXwBH9",
+ "doc_EFtmUsbwpXwBH8"
+ ],
+ "billing_proof": null,
+ "cancellation_proof": null,
+ "customer_communication": null,
+ "proof_of_service": null,
+ "explanation_letter": null,
+ "refund_confirmation": null,
+ "access_activity_log": null,
+ "refund_cancellation_policy": null,
+ "term_and_conditions": null,
+ "others": [
+ {
+ "type": "receipt_signed_by_customer",
+ "document_ids": [
+ "doc_EFtmUsbwpXwBH1",
+ "doc_EFtmUsbwpXwBH7"
+ ]
+ }
+ ],
+ "submitted_at": null
+ }
+}
+
+//Submit
+{
+ "id": "disp_AHfqOvkldwsbqt",
+ "entity": "dispute",
+ "payment_id": "pay_EsyWjHrfzb59eR",
+ "amount": 10000,
+ "currency": "INR",
+ "amount_deducted": 0,
+ "reason_code": "chargeback",
+ "respond_by": 1590604200,
+ "status": "under_review",
+ "phase": "chargeback",
+ "created_at": 1590059211,
+ "evidence": {
+ "amount": 5000,
+ "summary": "goods delivered",
+ "shipping_proof": [
+ "doc_EFtmUsbwpXwBH9",
+ "doc_EFtmUsbwpXwBH8"
+ ],
+ "billing_proof": [
+ "doc_EFtmUsbwpXwBG9",
+ "doc_EFtmUsbwpXwBG8"
+ ],
+ "cancellation_proof": null,
+ "customer_communication": null,
+ "proof_of_service": null,
+ "explanation_letter": null,
+ "refund_confirmation": null,
+ "access_activity_log": null,
+ "refund_cancellation_policy": null,
+ "term_and_conditions": null,
+ "others": [
+ {
+ "type": "receipt_signed_by_customer",
+ "document_ids": [
+ "doc_EFtmUsbwpXwBH1",
+ "doc_EFtmUsbwpXwBH7"
+ ]
+ }
+ ],
+ "submitted_at": 1590603200
+ }
+}
+```
+-------------------------------------------------------------------------------------------------------
+**PN: * indicates mandatory fields**
+
+
+**For reference click [here](https://razorpay.com/docs/api/documents)**
\ No newline at end of file
diff --git a/razorpay/__init__.py b/razorpay/__init__.py
index 92fcd45d..7f601b97 100644
--- a/razorpay/__init__.py
+++ b/razorpay/__init__.py
@@ -25,6 +25,7 @@
from .resources import Product
from .resources import Iin
from .resources import Webhook
+from .resources import Dispute
__all__ = [
'Payment',
@@ -53,5 +54,6 @@
'Stakeholder',
'Product',
'Iin',
- 'Webhook'
+ 'Webhook',
+ 'Dispute',
]
diff --git a/razorpay/constants/url.py b/razorpay/constants/url.py
index e9ae8dea..6e3811e6 100644
--- a/razorpay/constants/url.py
+++ b/razorpay/constants/url.py
@@ -26,3 +26,4 @@ class URL(object):
TOKEN = "/tokens"
IIN = "/iins"
WEBHOOK = "/webhooks"
+ DISPUTE= "/disputes"
diff --git a/razorpay/resources/__init__.py b/razorpay/resources/__init__.py
index 68917d25..27338296 100644
--- a/razorpay/resources/__init__.py
+++ b/razorpay/resources/__init__.py
@@ -21,6 +21,7 @@
from .product import Product
from .iin import Iin
from .webhook import Webhook
+from .dispute import Dispute
__all__ = [
'Payment',
@@ -45,5 +46,6 @@
'Stakeholder',
'Product',
'Iin',
- 'Webhook'
+ 'Webhook',
+ 'Dispute',
]
diff --git a/razorpay/resources/dispute.py b/razorpay/resources/dispute.py
new file mode 100644
index 00000000..64d251fb
--- /dev/null
+++ b/razorpay/resources/dispute.py
@@ -0,0 +1,46 @@
+from .base import Resource
+from ..constants.url import URL
+
+
+class Dispute(Resource):
+ def __init__(self, client=None):
+ super(Dispute, self).__init__(client)
+ self.base_url = URL.V1 + URL.DISPUTE
+
+ def fetch(self, dispute_id, data={}, **kwargs):
+ """
+ Fetch dispute for given Id
+
+ Returns:
+ dispute dict for given dispute Id
+ """
+ return super(Dispute, self).fetch(dispute_id, data, **kwargs)
+
+ def accept(self, dispute_id, data={}, **kwargs):
+ """
+ Accept a dispute
+
+ Returns:
+ Dictionary of disputes
+ """
+ url = f"{self.base_url}/{dispute_id}/accept"
+ return self.post_url(url, data, **kwargs)
+
+ def contest(self, dispute_id, data={}, **kwargs):
+ """
+ Contest a Dispute
+
+ Returns:
+ Dictionary of disputes
+ """
+ url = f"{self.base_url}/{dispute_id}/contest"
+ return self.patch_url(url, data, **kwargs)
+
+ def all(self, data={}, **kwargs):
+ """
+ Fetch all disputes
+
+ Returns:
+ Dictionary of disputes
+ """
+ return super(Dispute, self).all(data, **kwargs)
diff --git a/tests/mocks/dispute.json b/tests/mocks/dispute.json
new file mode 100644
index 00000000..92778f96
--- /dev/null
+++ b/tests/mocks/dispute.json
@@ -0,0 +1,15 @@
+{
+ "id": "disp_9GTZ2XXXXXXXXX",
+ "entity": "dispute",
+ "payment_id": "pay_9GMNcXXXXXXXXX",
+ "amount": 5000,
+ "currency": "INR",
+ "amount_deducted": 0,
+ "gateway_dispute_id": "test",
+ "reason_code": "goods_or_services_not_received_or_partially_received",
+ "respond_by": 1514658600,
+ "status": "under_review",
+ "phase": "chargeback",
+ "comments": null,
+ "created_at": 1513965738
+}
diff --git a/tests/mocks/dispute_accept.json b/tests/mocks/dispute_accept.json
new file mode 100644
index 00000000..dfc91e36
--- /dev/null
+++ b/tests/mocks/dispute_accept.json
@@ -0,0 +1,29 @@
+{
+ "id": "disp_AHfqOvkldwsbqt",
+ "entity": "dispute",
+ "payment_id": "pay_EsyWjHrfzb59eR",
+ "amount": 10000,
+ "currency": "INR",
+ "amount_deducted": 10000,
+ "reason_code": "pre_arbitration",
+ "respond_by": 1590604200,
+ "status": "lost",
+ "phase": "pre_arbitration",
+ "created_at": 1590059211,
+ "evidence": {
+ "amount": 10000,
+ "summary": null,
+ "shipping_proof": null,
+ "billing_proof": null,
+ "cancellation_proof": null,
+ "customer_communication": null,
+ "proof_of_service": null,
+ "explanation_letter": null,
+ "refund_confirmation": null,
+ "access_activity_log": null,
+ "refund_cancellation_policy": null,
+ "term_and_conditions": null,
+ "others": null,
+ "submitted_at": null
+ }
+ }
diff --git a/tests/mocks/dispute_collection.json b/tests/mocks/dispute_collection.json
new file mode 100644
index 00000000..791cd97e
--- /dev/null
+++ b/tests/mocks/dispute_collection.json
@@ -0,0 +1,67 @@
+{
+ "entity": "collection",
+ "count": 2,
+ "items": [
+ {
+ "id": "disp_Esz7KAitoYM7PJ",
+ "entity": "dispute",
+ "payment_id": "pay_EsyWjHrfzb59eR",
+ "amount": 10000,
+ "currency": "INR",
+ "amount_deducted": 0,
+ "reason_code": "pre_arbitration",
+ "respond_by": 1590604200,
+ "status": "open",
+ "phase": "pre_arbitration",
+ "created_at": 1590059211,
+ "evidence": {
+ "amount": 10000,
+ "summary": null,
+ "shipping_proof": null,
+ "billing_proof": null,
+ "cancellation_proof": null,
+ "customer_communication": null,
+ "proof_of_service": null,
+ "explanation_letter": null,
+ "refund_confirmation": null,
+ "access_activity_log": null,
+ "refund_cancellation_policy": null,
+ "term_and_conditions": null,
+ "others": null,
+ "submitted_at": null
+ }
+ },
+ {
+ "id": "disp_Esyvk3kZj0isXk",
+ "entity": "dispute",
+ "payment_id": "pay_EsyWjHrfzb59eR",
+ "amount": 5000,
+ "currency": "INR",
+ "amount_deducted": 0,
+ "reason_code": "warning_bulletin_or_exception_file",
+ "respond_by": 1590604200,
+ "status": "won",
+ "phase": "chargeback",
+ "created_at": 1590058554,
+ "evidence": {
+ "amount": 5000,
+ "summary": null,
+ "shipping_proof": [
+ "doc_EFtmUsbwpXwBH9",
+ "doc_EFtmUsbwpXwBH8"
+ ],
+ "billing_proof": null,
+ "cancellation_proof": null,
+ "customer_communication": null,
+ "proof_of_service": null,
+ "explanation_letter": null,
+ "refund_confirmation": null,
+ "access_activity_log": null,
+ "refund_cancellation_policy": null,
+ "term_and_conditions": null,
+ "others": null,
+ "submitted_at": 1590604100
+ }
+ }
+ ]
+ }
diff --git a/tests/mocks/dispute_contest.json b/tests/mocks/dispute_contest.json
new file mode 100644
index 00000000..6e2bf03a
--- /dev/null
+++ b/tests/mocks/dispute_contest.json
@@ -0,0 +1,40 @@
+{
+ "id": "disp_AHfqOvkldwsbqt",
+ "entity": "dispute",
+ "payment_id": "pay_EsyWjHrfzb59eR",
+ "amount": 10000,
+ "currency": "INR",
+ "amount_deducted": 0,
+ "reason_code": "chargeback",
+ "respond_by": 1590604200,
+ "status": "open",
+ "phase": "chargeback",
+ "created_at": 1590059211,
+ "evidence": {
+ "amount": 5000,
+ "summary": "goods delivered",
+ "shipping_proof": [
+ "doc_EFtmUsbwpXwBH9",
+ "doc_EFtmUsbwpXwBH8"
+ ],
+ "billing_proof": null,
+ "cancellation_proof": null,
+ "customer_communication": null,
+ "proof_of_service": null,
+ "explanation_letter": null,
+ "refund_confirmation": null,
+ "access_activity_log": null,
+ "refund_cancellation_policy": null,
+ "term_and_conditions": null,
+ "others": [
+ {
+ "type": "receipt_signed_by_customer",
+ "document_ids": [
+ "doc_EFtmUsbwpXwBH1",
+ "doc_EFtmUsbwpXwBH7"
+ ]
+ }
+ ],
+ "submitted_at": null
+ }
+ }
diff --git a/tests/test_client_dispute.py b/tests/test_client_dispute.py
new file mode 100644
index 00000000..bcf2a74c
--- /dev/null
+++ b/tests/test_client_dispute.py
@@ -0,0 +1,65 @@
+import responses
+import json
+
+from .helpers import mock_file, ClientTestCase
+
+
+class TestClientDispute(ClientTestCase):
+
+ def setUp(self):
+ super(TestClientDispute, self).setUp()
+ self.base_url = '{}/disputes'.format(self.base_url)
+
+ @responses.activate
+ def test_dispute_fetch_all(self):
+ result = mock_file('dispute_collection')
+ url = self.base_url
+ responses.add(responses.GET, url, status=200,
+ body=json.dumps(result), match_querystring=True)
+ self.assertEqual(self.client.dispute.all(), result)
+
+ @responses.activate
+ def test_fetch_dispute(self):
+ result = mock_file('dispute')
+ dispute_id = 'fake_dispute_id'
+ url = f"{self.base_url}/{dispute_id}"
+ responses.add(responses.GET, url, status=200, body=json.dumps(result),
+ match_querystring=True)
+ self.assertEqual(self.client.dispute.fetch(dispute_id), result)
+
+ @responses.activate
+ def test_dispute_accept(self):
+ result = mock_file('dispute_accept')
+ dispute_id = 'fake_dispute_id'
+ url = f"{self.base_url}/{dispute_id}/accept"
+ responses.add(responses.POST, url, status=200, body=json.dumps(result),
+ match_querystring=True)
+ self.assertEqual(self.client.dispute.accept(dispute_id), result)
+
+ @responses.activate
+ def test_dispute_contest(self):
+ request = {
+ "amount": 5000,
+ "summary": "goods delivered",
+ "shipping_proof": [
+ "doc_EFtmUsbwpXwBH9",
+ "doc_EFtmUsbwpXwBH8"
+ ],
+ "others": [
+ {
+ "type": "receipt_signed_by_customer",
+ "document_ids": [
+ "doc_EFtmUsbwpXwBH1",
+ "doc_EFtmUsbwpXwBH7"
+ ]
+ }
+ ],
+ "action": "draft"
+ }
+
+ result = mock_file('dispute_contest')
+ dispute_id = 'fake_dispute_id'
+ url = f"{self.base_url}/{dispute_id}/contest"
+ responses.add(responses.PATCH, url, status=200, body=json.dumps(result),
+ match_querystring=True)
+ self.assertEqual(self.client.dispute.contest(dispute_id, request), result)