From 6fa5fe2d3e0a6cfb7894f71d045fdb8e723db4c7 Mon Sep 17 00:00:00 2001 From: Ankit Das <89454448+ankitdas13@users.noreply.github.com> Date: Thu, 3 Aug 2023 13:48:11 +0530 Subject: [PATCH] feat: add partner's api's (#255) --- documents/account.md | 446 ++++++++++++++++++++++++ documents/card.md | 41 +++ documents/payment.md | 45 ++- documents/productConfiguration.md | 444 +++++++++++++++++++++++ documents/stakeholder.md | 338 ++++++++++++++++++ documents/token.md | 147 +++++++- documents/webhook.md | 224 ++++++++++++ razorpay/__init__.py | 10 + razorpay/client.py | 17 + razorpay/constants/url.py | 11 +- razorpay/resources/__init__.py | 12 +- razorpay/resources/account.py | 74 ++++ razorpay/resources/addon.py | 6 +- razorpay/resources/base.py | 3 + razorpay/resources/card.py | 17 +- razorpay/resources/customer.py | 10 +- razorpay/resources/fund_account.py | 6 +- razorpay/resources/iin.py | 19 + razorpay/resources/invoice.py | 18 +- razorpay/resources/item.py | 12 +- razorpay/resources/order.py | 12 +- razorpay/resources/payment.py | 48 +-- razorpay/resources/payment_link.py | 14 +- razorpay/resources/plan.py | 8 +- razorpay/resources/product.py | 49 +++ razorpay/resources/qrcode.py | 12 +- razorpay/resources/refund.py | 8 +- razorpay/resources/registration_link.py | 4 +- razorpay/resources/settlement.py | 8 +- razorpay/resources/stakeholder.py | 81 +++++ razorpay/resources/subscription.py | 12 +- razorpay/resources/token.py | 49 ++- razorpay/resources/transfer.py | 16 +- razorpay/resources/virtual_account.py | 18 +- razorpay/resources/webhook.py | 86 +++++ tests/helpers.py | 5 +- tests/mocks/fake_account.json | 78 +++++ tests/mocks/fake_iin.json | 26 ++ tests/mocks/fake_merchant_token.json | 32 ++ tests/mocks/fake_product.json | 139 ++++++++ tests/mocks/fake_reference_card.json | 1 + tests/mocks/fake_stakeholder.json | 29 ++ tests/mocks/fake_webhook.json | 22 ++ tests/mocks/init_account.json | 72 ++++ tests/mocks/init_stakeholder.json | 28 ++ tests/mocks/init_webhook.json | 13 + tests/mocks/stakeholder_collection.json | 35 ++ tests/mocks/webhook_collection.json | 29 ++ tests/test_client_account.py | 50 +++ tests/test_client_card.py | 15 + tests/test_client_iin.py | 20 ++ tests/test_client_product.py | 98 ++++++ tests/test_client_stakeholder.py | 85 +++++ tests/test_client_token.py | 59 ++++ tests/test_client_virtual_account.py | 5 +- tests/test_client_webhook.py | 76 ++++ tests/test_multiple_client.py | 3 +- 57 files changed, 3125 insertions(+), 120 deletions(-) create mode 100644 documents/account.md create mode 100644 documents/productConfiguration.md create mode 100644 documents/stakeholder.md create mode 100644 documents/webhook.md create mode 100644 razorpay/resources/account.py create mode 100644 razorpay/resources/iin.py create mode 100644 razorpay/resources/product.py create mode 100644 razorpay/resources/stakeholder.py create mode 100644 razorpay/resources/webhook.py create mode 100644 tests/mocks/fake_account.json create mode 100644 tests/mocks/fake_iin.json create mode 100644 tests/mocks/fake_merchant_token.json create mode 100644 tests/mocks/fake_product.json create mode 100644 tests/mocks/fake_reference_card.json create mode 100644 tests/mocks/fake_stakeholder.json create mode 100644 tests/mocks/fake_webhook.json create mode 100644 tests/mocks/init_account.json create mode 100644 tests/mocks/init_stakeholder.json create mode 100644 tests/mocks/init_webhook.json create mode 100644 tests/mocks/stakeholder_collection.json create mode 100644 tests/mocks/webhook_collection.json create mode 100644 tests/test_client_account.py create mode 100644 tests/test_client_iin.py create mode 100644 tests/test_client_product.py create mode 100644 tests/test_client_stakeholder.py create mode 100644 tests/test_client_webhook.py diff --git a/documents/account.md b/documents/account.md new file mode 100644 index 00000000..a2d83783 --- /dev/null +++ b/documents/account.md @@ -0,0 +1,446 @@ +## Account + +### Create an Account +```py +client.account.create({ + "email": "gauriagain.kumar@example.org", + "phone": "9000090000", + "legal_business_name": "Acme Corp", + "business_type": "partnership", + "customer_facing_business_name": "Example", + "profile": { + "category": "healthcare", + "subcategory": "clinic", + "description": "Healthcare E-commerce platform", + "addresses": { + "operation": { + "street1": "507, Koramangala 6th block", + "street2": "Kormanagala", + "city": "Bengaluru", + "state": "Karnataka", + "postal_code": 560047, + "country": "IN" + }, + "registered": { + "street1": "507, Koramangala 1st block", + "street2": "MG Road", + "city": "Bengaluru", + "state": "Karnataka", + "postal_code": 560034, + "country": "IN" + } + }, + "business_model": "Online Clothing ( men, women, ethnic, modern ) fashion and lifestyle, accessories, t-shirt, shirt, track pant, shoes." + }, + "legal_info": { + "pan": "AAACL1234C", + "gst": "18AABCU9603R1ZM" + }, + "brand": { + "color": "FFFFFF" + }, + "notes": { + "internal_ref_id": "123123" + }, + "contact_name": "Gaurav Kumar", + "contact_info": { + "chargeback": { + "email": "cb@example.org" + }, + "refund": { + "email": "cb@example.org" + }, + "support": { + "email": "support@example.org", + "phone": "9999999998", + "policy_url": "https://www.google.com" + } + }, + "apps": { + "websites": [ + "https://www.example.org" + ], + "android": [ + { + "url": "playstore.example.org", + "name": "Example" + } + ], + "ios": [ + { + "url": "appstore.example.org", + "name": "Example" + } + ] + } +}) +``` + +**Parameters:** + +| Name | Type | Description | +|---------------|-------------|---------------------------------------------| +| email* | string | The sub-merchant's business email address. | +| phone* | integer | The sub-merchant's business phone number. The minimum length is 8 characters and the maximum length is 15. | +| legal_business_name* | string | The name of the sub-merchant's business. For example, Acme Corp. The minimum length is 4 characters and the maximum length is 200. | +| customer_facing_business_name | string | The sub-merchant billing label as it appears on the Razorpay Dashboard. The minimum length is 1 character and the maximum length is 255. | +| business_type | string | The type of business operated by the sub-merchant.Possible value is `proprietorship`, `partnership`, `private_limited`, `public_limited`, `llp`, `ngo`, `trust`, `society`, `not_yet_registered`, `huf` | +| reference_id | string | Partner's external account reference id. The minimum length is 1 character and the maximum length is 512. | +| profile | object | All keys listed [here](https://razorpay.com/docs/api/partners/account-onboarding/#create-an-account) are supported | +| legal_info | object | All keys listed [here](hhttps://razorpay.com/docs/api/partners/account-onboarding/#create-an-account) are supported | +| brand | object | All keys listed [here](https://razorpay.com/docs/api/partners/account-onboarding/#create-an-account) are supported | +| notes | object | A key-value pair | +| contact_name* | string | The name of the contact. The minimum length is 4 and the maximum length is 255 characters. | +| contact_info | object | All keys listed [here](https://razorpay.com/docs/api/partners/account-onboarding/#create-an-account) are supported | +| apps | object | All keys listed [here](https://razorpay.com/docs/api/partners/account-onboarding/#create-an-account) are supported | + + +**Response:** +```json +{ + "id": "acc_GRWKk7qQsLnDjX", + "type": "standard", + "status": "created", + "email": "gauriagain.kumar@example.org", + "profile": { + "category": "healthcare", + "subcategory": "clinic", + "addresses": { + "registered": { + "street1": "507, Koramangala 1st block", + "street2": "MG Road", + "city": "Bengaluru", + "state": "KARNATAKA", + "postal_code": 560034, + "country": "IN" + }, + "operation": { + "street1": "507, Koramangala 6th block", + "street2": "Kormanagalo", + "city": "Bengaluru", + "state": "KARNATAKA", + "country": "IN", + "postal_code": 560047 + } + }, + "business_model": "Online Clothing ( men, women, ethnic, modern ) fashion and lifestyle, accessories, t-shirt, shirt, track pant, shoes." + }, + "notes": { + "internal_ref_id": "123123" + }, + "created_at": 1611136837, + "phone": "9000090000", + "business_type": "partnership", + "legal_business_name": "Acme Corp", + "customer_facing_business_name": "Example", + "legal_info": { + "pan": "AAACL1234C", + "gst": "18AABCU9603R1ZM" + }, + "apps": { + "websites": [ + "https://www.example.org" + ], + "android": [ + { + "url": "playstore.example.org", + "name": "Example" + } + ], + "ios": [ + { + "url": "appstore.example.org", + "name": "Example" + } + ] + }, + "brand": { + "color": "#FFFFFF" + }, + "contact_info": { + "chargeback": { + "email": "cb@example.org", + "phone": null, + "policy_url": null + }, + "refund": { + "email": "cb@example.org", + "phone": null, + "policy_url": null + }, + "support": { + "email": "support@example.org", + "phone": "9999999998", + "policy_url": "https://www.google.com" + } + } +} +``` + +------------------------------------------------------------------------------------------------------- + +### Edit Account + +```py +accountId = "acc_GP4lfNA0iIMn5B" + +client.account.edit(accountId,{ + "customer_facing_business_name": "ABCD Ltd" +}) +``` + +**Parameters:** + +| Name | Type | Description | +|---------------|-------------|---------------------------------------------| +| phone | integer | The sub-merchant's business phone number. The minimum length is 8 characters and the maximum length is 15. | +| legal_business_name | string | The name of the sub-merchant's business. For example, Acme Corp. The minimum length is 4 characters and the maximum length is 200. | +| customer_facing_business_name | string | The sub-merchant billing label as it appears on the Razorpay Dashboard. The minimum length is 1 character and the maximum length is 255. | +| profile | object | All keys listed [here](https://razorpay.com/docs/api/partners/account-onboarding/#update-an-account) are supported | +| legal_info | object | All keys listed [here](hhttps://razorpay.com/docs/api/partners/account-onboarding/#update-an-account) are supported | +| brand | object | All keys listed [here](https://razorpay.com/docs/api/partners/account-onboarding/#update-an-account) are supported | +| notes | object | A key-value pair | +| contact_name* | string | The name of the contact. The minimum length is 4 and the maximum length is 255 characters. | +| contact_info | object | All keys listed [here](https://razorpay.com/docs/api/partners/account-onboarding/#update-an-account) are supported | +| apps | object | All keys listed [here](https://razorpay.com/docs/api/partners/account-onboarding/#update-an-account) are supported | + +**Response:** +```json +{ + "id": "acc_GP4lfNA0iIMn5B", + "type": "standard", + "status": "created", + "email": "gauri@example.org", + "profile": { + "category": "healthcare", + "subcategory": "clinic", + "addresses": { + "registered": { + "street1": "507, Koramangala 1st block", + "street2": "MG Road-1", + "city": "Bengalore", + "state": "KARNATAKA", + "postal_code": "560034", + "country": "IN" + } + } + }, + "notes": [], + "created_at": 1610603081, + "phone": "9000090000", + "reference_id": "randomId", + "business_type": "partnership", + "legal_business_name": "Acme Corp", + "customer_facing_business_name": "ABCD Ltd" +} +``` +------------------------------------------------------------------------------------------------------- + +### Delete an account +```py +accountId = "acc_GP4lfNA0iIMn5B" + +client.account.delete(accountId) +``` + +**Parameters:** + +| Name | Type | Description | +|---------------|-------------|---------------------------------------------| +| accountId* | string | The unique identifier of a sub-merchant account that must be deleted. | + +**Response:** +```json +{ + "id": "acc_GXQAkO2MrvBYg4", + "type": "standard", + "status": "suspended", + "email": "gaurav.kumar@acme.org", + "profile": { + "category": "healthcare", + "subcategory": "clinic", + "addresses": { + "registered": { + "street1": "507, Koramangala 1st block", + "street2": "MG Road", + "city": "Bengaluru", + "state": "KARNATAKA", + "postal_code": "560034", + "country": "IN" + }, + "operation": { + "street1": "507, Koramangala 1st block", + "street2": "MG Road", + "city": "Bengaluru", + "state": "KARNATAKA", + "country": "IN", + "postal_code": "560034" + } + }, + "business_model": "Online Clothing ( men, women, ethnic, modern ) fashion and lifestyle, accessories, t-shirt, shirt, track pant, shoes." + }, + "notes": { + "internal_ref_id": "123123" + }, + "created_at": 1612425180, + "suspended_at": 1612425235, + "phone": "9000090000", + "reference_id": "account_COdeRandom", + "business_type": "partnership", + "legal_business_name": "Acme Corp Pvt Ltd", + "customer_facing_business_name": "Acme", + "legal_info": { + "pan": "AAACL1234C", + "gst": "18AABCU9603R1ZM" + }, + "apps": { + "websites": [ + "https://www.acme.org" + ], + "android": [ + { + "url": "playstore.acme.org", + "name": "Acme" + } + ], + "ios": [ + { + "url": "appstore.acme.org", + "name": "Acme" + } + ] + }, + "brand": { + "color": "#FFFFFF" + }, + "contact_name": "Gaurav Kumar", + "contact_info": { + "chargeback": { + "email": "cb@acme.org", + "phone": "9000090000", + "policy_url": "https://www.google.com" + }, + "refund": { + "email": "cb@acme.org", + "phone": "9898989898", + "policy_url": "https://www.google.com" + }, + "support": { + "email": "support@acme.org", + "phone": "9898989898", + "policy_url": "https://www.google.com" + } + } +} +``` + +------------------------------------------------------------------------------------------------------- + +### Fetch an account +```py +accountId = "acc_GP4lfNA0iIMn5B" + +client.account.fetch(accountId) +``` + +**Parameters:** + +| Name | Type | Description | +|-------------|-------------|---------------------------------------------| +| accountId* | string | The unique identifier of a sub-merchant account generated by Razorpay. | + +**Response:** +```json +{ + "id": "acc_GP4lfNA0iIMn5B", + "type": "standard", + "status": "created", + "email": "gauri@example.org", + "profile": { + "category": "healthcare", + "subcategory": "clinic", + "addresses": { + "registered": { + "street1": "507, Koramangala 1st block", + "street2": "MG Road-1", + "city": "Bengalore", + "state": "KARNATAKA", + "postal_code": "560034", + "country": "IN" + } + } + }, + "notes": [], + "created_at": 1610603081, + "phone": "9000090000", + "reference_id": "randomId", + "business_type": "partnership", + "legal_business_name": "Acme Corp", + "customer_facing_business_name": "Example Pvt. Ltd." +} +``` + +------------------------------------------------------------------------------------------------------- + +### Upload account documents +```py +accountId = "acc_M83Uw27KXuC7c8" + +file = open('/Users/your_name/Downloads/sample_uploaded.jpeg', 'rb') + +client.account.uploadAccountDoc(accountId, { + "file" : file, + "document_type" : "business_proof_url" +}) +``` + +**Parameters:** + +| Name | Type | Description | +|-------------|-------------|---------------------------------------------| +| accountId* | string | The unique identifier of a sub-merchant account generated by Razorpay. | +| file* | string | The URL generated once the business proof document is uploaded. | +| document_type* | string | The documents valid for the proof type to be shared. Possible values :
business_proof_of_identification: `shop_establishment_certificate`, `gst_certificate`, `msme_certificate`, `business_proof_url`, `business_pan_url`,

additional_documents : `form_12_a_url`, `form_80g_url`, `cancelled_cheque` | + +**Response:** +```json +{ + "business_proof_of_identification": [ + { + "type": "business_proof_url", + "url": "" + } + ] +} +``` +------------------------------------------------------------------------------------------------------- + +### Fetch account documents +```py +accountId = "acc_LryDIBIjBDbOWy" + +client.account.fetchAccountDoc(accountId) +``` + +**Parameters:** + +| Name | Type | Description | +|-------------|-------------|---------------------------------------------| +| accountId* | string | The unique identifier of a sub-merchant account generated by Razorpay. | + +**Response:** +```json +{ + "business_proof_of_identification": [ + { + "type": "business_proof_url", + "url": "" + } + ] +} +``` +------------------------------------------------------------------------------------------------------- +**PN: * indicates mandatory fields** +
+
+**For reference click [here](https://razorpay.com/docs/api/partners/account-onboarding/)** \ No newline at end of file diff --git a/documents/card.md b/documents/card.md index 1aad8183..15f2b79f 100644 --- a/documents/card.md +++ b/documents/card.md @@ -571,7 +571,48 @@ client.token.delete(customerId,tokenId) } ``` ------------------------------------------------------------------------------------------------------- +## Using Card Number/ Tokenised Card Number +```py +client.card.requestCardReference({"number":"4854980604708430"}) +``` +**Parameters:** + +| Name | Type | Description | +|-------------|---------|------------------------------------------------------------------------------| +| number* | string | The card number whose PAR or network reference id should be retrieved. | +| tokenised | string | Determines if the card is saved as a token. Possible value is `true` or `false` | + +**Response:** +```json +{ + "network": "Visa", + "payment_account_reference": "V0010013819231376539033235990", + "network_reference_id": null +} +``` +------------------------------------------------------------------------------------------------------- + +## Using Razporpay token + +```py +client.card.requestCardReference({"token":"token_4lsdksD31GaZ09"}) +``` +**Parameters:** + +| Name | Type | Description | +|-------------|---------|------------------------------------------------------------------------------| +| token* | string | The token whose PAR or network reference id should be retrieved.| + +**Response:** +```json +{ + "network": "Visa", + "payment_account_reference": "V0010013819231376539033235990", + "network_reference_id": null +} +``` +------------------------------------------------------------------------------------------------------- **PN: * indicates mandatory fields**

diff --git a/documents/payment.md b/documents/payment.md index c8e95003..63661f82 100644 --- a/documents/payment.md +++ b/documents/payment.md @@ -172,7 +172,7 @@ client.payment.fetch(paymentId) ### Fetch payments for an order ```py -client.order.payment(orderId) +client.order.payments(orderId) ``` **Parameters** @@ -717,7 +717,50 @@ Doc reference [doc](https://razorpay.com/docs/payments/payment-methods/cards/aut } ``` ------------------------------------------------------------------------------------------------------- +### Token IIN API +```py +tokenIin = "412345" + +client.iin.fetch(tokenIin) +``` + +**Parameters:** + +| Name | Type | Description | +|------------|--------|-----------------------------------| +| tokenIin* | string | The token IIN. | + +**Response:** +```json +{ + "iin": "412345", + "entity": "iin", + "network": "Visa", + "type": "credit", + "sub_type": "business", + "issuer_code": "HDFC", + "issuer_name": "HDFC Bank Ltd", + "international": false, + "is_tokenized": true, + "card_iin": "411111", + "emi":{ + "available": true + }, + "recurring": { + "available": true + }, + "authentication_types": [ + { + "type":"3ds" + }, + { + "type":"otp" + } + ] +} +``` +------------------------------------------------------------------------------------------------------- **PN: * indicates mandatory fields**

diff --git a/documents/productConfiguration.md b/documents/productConfiguration.md new file mode 100644 index 00000000..eb7a685a --- /dev/null +++ b/documents/productConfiguration.md @@ -0,0 +1,444 @@ +## Product Configuration + +### Request a Product Configuration +```py + +accountId = "acc_GP4lfNA0iIMn5B" + +client.product.requestProductConfiguration(accountId, { + "product_name" : "payment_gateway", + "tnc_accepted" : True, + "ip" : "233.233.233.234" +}) +``` + +**Parameters:** + +| Name | Type | Description | +|---------------|-------------|---------------------------------------------| +| product_name* | string | The product(s) to be configured. Possible value is `payment_gateway`, `payment_links` | +| tnc_accepted | boolean | Pass this parameter to accept terms and conditions. Send this parameter along with the ip parameter when the tnc is accepted. Possible values is `true` | +| ip | integer | The IP address of the merchant while accepting the terms and conditions. Send this parameter along with the `tnc_accepted` parameter when the `tnc` is accepted. | + +**Response:** +```json +{ + "requested_configuration": { + "payment_methods": [] + }, + "active_configuration": { + "payment_capture": { + "mode": "automatic", + "refund_speed": "normal", + "automatic_expiry_period": 7200 + }, + "settlements": { + "account_number": null, + "ifsc_code": null, + "beneficiary_name": null + }, + "checkout": { + "theme_color": "#FFFFFF", + "flash_checkout": true, + "logo": "https://example.com/your_logo" + }, + "refund": { + "default_refund_speed": "normal" + }, + "notifications": { + "whatsapp": true, + "sms": false, + "email": [ + "b963e252-1201-45b0-9c39-c53eceb0cfd6_load@gmail.com" + ] + }, + "payment_methods": { + "netbanking": { + "enabled": true, + "instrument": [ + { + "type": "retail", + "bank": [ + "hdfc", + "sbin", + "utib", + "icic", + "scbl", + "yesb" + ] + } + ] + }, + "wallet": { + "enabled": true, + "instrument": [ + "airtelmoney", + "freecharge", + "jiomoney", + "olamoney", + "payzapp", + "mobikwik" + ] + }, + "upi": { + "enabled": true, + "instrument": [ + "upi" + ] + } + } + }, + "requirements": [ + { + "field_reference": "individual_proof_of_address", + "resolution_url": "/accounts/acc_HQVlm3bnPmccC0/stakeholders/{stakeholderId}/documents", + "status": "required", + "reason_code": "document_missing" + }, + { + "field_reference": "individual_proof_of_identification", + "resolution_url": "/accounts/acc_HQVlm3bnPmccC0/stakeholders/{stakeholderId}/documents", + "status": "required", + "reason_code": "document_missing" + }, + { + "field_reference": "business_proof_of_identification", + "resolution_url": "/accounts/acc_HQVlm3bnPmccC0/documents", + "status": "required", + "reason_code": "document_missing" + }, + { + "field_reference": "settlements.beneficiary_name", + "resolution_url": "/accounts/acc_HQVlm3bnPmccC0/products/acc_prd_HEgNpywUFctQ9e", + "status": "required", + "reason_code": "field_missing" + }, + { + "field_reference": "settlements.account_number", + "resolution_url": "/accounts/acc_HQVlm3bnPmccC0/products/acc_prd_HEgNpywUFctQ9e", + "status": "required", + "reason_code": "field_missing" + }, + { + "field_reference": "settlements.ifsc_code", + "resolution_url": "/accounts/acc_HQVlm3bnPmccC0/products/acc_prd_HEgNpywUFctQ9e", + "status": "required", + "reason_code": "field_missing" + }, + { + "field_reference": "contact_name", + "resolution_url": "/accounts/acc_HQVlm3bnPmccC0", + "status": "required", + "reason_code": "field_missing" + }, + { + "field_reference": "name", + "resolution_url": "/accounts/acc_HQVlm3bnPmccC0/stakeholders", + "status": "required", + "reason_code": "field_missing" + }, + { + "field_reference": "customer_facing_business_name", + "resolution_url": "/accounts/acc_HQVlm3bnPmccC0", + "status": "required", + "reason_code": "field_missing" + }, + { + "field_reference": "kyc.pan", + "resolution_url": "/accounts/acc_HQVlm3bnPmccC0/stakeholders", + "status": "required", + "reason_code": "field_missing" + } + ], + "tnc":{ + "id": "tnc_IgohZaDBHRGjPv", + "accepted": true, + "accepted_at": 1641550798 + }, + "id": "acc_prd_HEgNpywUFctQ9e", + "account_id": "acc_HQVlm3bnPmccC0", + "product_name": "payment_gateway", + "activation_status": "needs_clarification", + "requested_at": 162547884 +} +``` + +------------------------------------------------------------------------------------------------------- + +### Edit a Product Configuration +```py +accountId = "acc_GP4lfNA0iIMn5B" +productId = "acc_prd_HEgNpywUFctQ9e" + +client.product.edit(accountId, productId, { + "notifications": { + "email": [ + "gaurav.kumar@example.com", + "acd@gmail.com" + ] + }, + "checkout": { + "theme_color": "#528FFF" + }, + "refund": { + "default_refund_speed": "optimum" + }, + "settlements": { + "account_number": "1234567890", + "ifsc_code": "HDFC0000317", + "beneficiary_name": "Gaurav Kumar" + }, + "tnc_accepted": True, + "ip": "233.233.233.234" +}) +``` + +**Parameters:** + +| Name | Type | Description | +|---------------|-------------|---------------------------------------------| +| notifications | object | All keys listed [here](https://razorpay.com/docs/api/partners/product-configuration/#update-a-product-configuration) are supported | +| checkout | object | All keys listed [here](https://razorpay.com/docs/api/partners/product-configuration/#update-a-product-configuration) are supported | +| refund | object | All keys listed [here](https://razorpay.com/docs/api/partners/product-configuration/#update-a-product-configuration) are supported | +| settlements | object | All keys listed [here](https://razorpay.com/docs/api/partners/product-configuration/#update-a-product-configuration) are supported | +| tnc_accepted | boolean | Pass this parameter to accept terms and conditions. Send this parameter along with the ip parameter when the tnc is accepted. Possible value is `true` | +| ip | string | The IP address of the merchant while accepting the terms and conditions. Send this parameter along with the tnc_accepted parameter when the `tnc` is accepted. | +| payment_methods | All keys listed [here](https://razorpay.com/docs/api/partners/product-configuration/#update-a-product-configuration) are supported | +| type | string | Possible value is `domestic` | +| issuer | string | The card issuer. Possible values for issuer are `amex`, `dicl`, `maestro`, `mastercard`, `rupay`, `visa`. | +| wallet | object | All keys listed [here](https://razorpay.com/docs/api/partners/product-configuration/#update-a-product-configuration) are supported | +| instrument(wallet) | string | The wallet issuer. Possible values are `airtelmoney`, `amazonpay`, `freecharge`, `jiomoney`, `mobiwik`, `mpesa`, `olamoney`, `paytm`, `payzapp`, `payumoney`, `phonepe`, `phonepeswitch`, `sbibuddy` | +| instrument(wallet) | string | The wallet issuer. Possible values are `airtelmoney`, `amazonpay`, `freecharge`, `jiomoney`, `mobiwik`, `mpesa`, `olamoney`, `paytm`, `payzapp`, `payumoney`, `phonepe`, `phonepeswitch`, `sbibuddy` | +| upi | object | All keys listed [here](https://razorpay.com/docs/api/partners/product-configuration/#update-a-product-configuration) are supported | +| instrument(upi) | string | The UPI service provider. Possible values are `google_pay`, `upi`| +| paylater | object | All keys listed [here](https://razorpay.com/docs/api/partners/product-configuration/#update-a-product-configuration) are supported | +| instrument(emi) | string | The Paylater service provider. Possible values are `epaylater`, `getsimpl`| +| emi | object | All keys listed [here](https://razorpay.com/docs/api/partners/product-configuration/#update-a-product-configuration) are supported | + +**Response:** +```json +{ + "id": "acc_GP4lfNA0iIMn5B", + "type": "standard", + "status": "created", + "email": "gauri@example.org", + "profile": { + "category": "healthcare", + "subcategory": "clinic", + "addresses": { + "registered": { + "street1": "507, Koramangala 1st block", + "street2": "MG Road-1", + "city": "Bengalore", + "state": "KARNATAKA", + "postal_code": "560034", + "country": "IN" + } + } + }, + "notes": [], + "created_at": 1610603081, + "phone": "9000090000", + "reference_id": "randomId", + "business_type": "partnership", + "legal_business_name": "Acme Corp", + "customer_facing_business_name": "ABCD Ltd" +} +``` +------------------------------------------------------------------------------------------------------- + +### Fetch a product configuration +```py +accountId = "acc_GP4lfNA0iIMn5B" + +productId = "acc_prd_HEgNpywUFctQ9e" + +client.product.fetch(accountId, productId) +``` + +**Parameters:** + +| Name | Type | Description | +|-------------|-------------|---------------------------------------------| +| accountId* | string | The unique identifier of a sub-merchant account generated by Razorpay. | +| productId* | string | The unique identifier of a product generated by Razorpay. | + +**Response:** +```json +{ + "requested_configuration": { + "payment_methods": [] + }, + "active_configuration": { + "payment_capture": { + "mode": "automatic", + "refund_speed": "normal", + "automatic_expiry_period": 7200 + }, + "settlements": { + "account_number": null, + "ifsc_code": null, + "beneficiary_name": null + }, + "checkout": { + "theme_color": "#FFFFFF", + "flash_checkout": true + }, + "refund": { + "default_refund_speed": "normal" + }, + "notifications": { + "whatsapp": true, + "sms": false, + "email": [ + "b963e252-1201-45b0-9c39-c53eceb0cfd6_load@gmail.com" + ] + }, + "payment_methods": { + "netbanking": { + "enabled": true, + "instrument": [ + { + "type": "retail", + "bank": [ + "hdfc", + "sbin", + "utib", + "icic", + "scbl", + "yesb" + ] + } + ] + }, + "wallet": { + "enabled": true, + "instrument": [ + "airtelmoney", + "freecharge", + "jiomoney", + "olamoney", + "payzapp", + "mobikwik" + ] + }, + "upi": { + "enabled": true, + "instrument": [ + "upi" + ] + } + } + }, + "requirements": [ + { + "field_reference": "individual_proof_of_address", + "resolution_url": "/accounts/acc_HQVlm3bnPmccC0/stakeholders/{stakeholderId}/documents", + "status": "required", + "reason_code": "document_missing" + }, + { + "field_reference": "individual_proof_of_identification", + "resolution_url": "/accounts/acc_HQVlm3bnPmccC0/stakeholders/{stakeholderId}/documents", + "status": "required", + "reason_code": "document_missing" + }, + { + "field_reference": "business_proof_of_identification", + "resolution_url": "/accounts/acc_HQVlm3bnPmccC0/documents", + "status": "required", + "reason_code": "document_missing" + }, + { + "field_reference": "settlements.beneficiary_name", + "resolution_url": "/accounts/acc_HQVlm3bnPmccC0/products/acc_prd_HEgNpywUFctQ9e", + "status": "required", + "reason_code": "field_missing" + }, + { + "field_reference": "settlements.account_number", + "resolution_url": "/accounts/acc_HQVlm3bnPmccC0/products/acc_prd_HEgNpywUFctQ9e", + "status": "required", + "reason_code": "field_missing" + }, + { + "field_reference": "settlements.ifsc_code", + "resolution_url": "/accounts/acc_HQVlm3bnPmccC0/products/acc_prd_HEgNpywUFctQ9e", + "status": "required", + "reason_code": "field_missing" + }, + { + "field_reference": "contact_name", + "resolution_url": "/accounts/acc_HQVlm3bnPmccC0", + "status": "required", + "reason_code": "field_missing" + }, + { + "field_reference": "name", + "resolution_url": "/accounts/acc_HQVlm3bnPmccC0/stakeholders", + "status": "required", + "reason_code": "field_missing" + }, + { + "field_reference": "customer_facing_business_name", + "resolution_url": "/accounts/acc_HQVlm3bnPmccC0", + "status": "required", + "reason_code": "field_missing" + }, + { + "field_reference": "kyc.pan", + "resolution_url": "/accounts/acc_HQVlm3bnPmccC0/stakeholders", + "status": "required", + "reason_code": "field_missing" + } + ], + "tnc":{ + "id": "tnc_IgohZaDBHRGjPv", + "accepted": true, + "accepted_at": 1641550798 + }, + "id": "acc_prd_HEgNpywUFctQ9e", + "account_id": "acc_HQVlm3bnPmccC0", + "product_name": "payment_gateway", + "activation_status": "needs_clarification", + "requested_at": 1625478849 +} +``` + +------------------------------------------------------------------------------------------------------- + +### Fetch Terms and Conditions for a Sub-Merchant +```py + +productName = "payments" + +client.product.fetchTnc(productName) +``` + +**Parameters:** + +| Name | Type | Description | +|-------------|-------------|---------------------------------------------| +| productName* | string | The product family for which the relevant product to be requested for the sub-merchant. Possible value is `payments` | + +**Response:** +```json +{ + "entity": "tnc_map", + "product_name": "payments", + "id": "tnc_map_HjOVhIdpVDZ0FB", + "tnc": { + "terms": "https://razorpay.com/terms", + "privacy": "https://razorpay.com/privacy", + "agreement": "https://razorpay.com/agreement" + }, + "last_published_at": 1640589653 +} +``` + +------------------------------------------------------------------------------------------------------- + +**PN: * indicates mandatory fields** +
+
+**For reference click [here](https://razorpay.com/docs/api/partners/product-configuration/)** \ No newline at end of file diff --git a/documents/stakeholder.md b/documents/stakeholder.md new file mode 100644 index 00000000..64052aa1 --- /dev/null +++ b/documents/stakeholder.md @@ -0,0 +1,338 @@ +## Stakeholders + +### Create an Stakeholder +```py + +accountId = "acc_GP4lfNA0iIMn5B" + +client.stakeholder.create(accountId, { + "percentage_ownership": 10, + "name": "Gaurav Kumar", + "email": "gaurav.kumar@example.com", + "relationship": { + "director": True, + "executive": False + }, + "phone": { + "primary": "7474747474", + "secondary": "7474747474" + }, + "addresses": { + "residential": { + "street": "506, Koramangala 1st block", + "city": "Bengaluru", + "state": "Karnataka", + "postal_code": "560034", + "country": "IN" + } + }, + "kyc": { + "pan": "AVOPB1111K" + }, + "notes": { + "random_key_by_partner": "random_value" + } +}) +``` + +**Parameters:** + +| Name | Type | Description | +|---------------|-------------|---------------------------------------------| +| email | string | The sub-merchant's business email address. | +| name* | string | The stakeholder's name as per the PAN card. The maximum length is 255 characters. | +| percentage_ownership | float | The stakeholder's ownership of the business in percentage. Only two decimal places are allowed. For example, `87.55`. The maximum length is 100 characters. | +| relationship | boolean | The stakeholder's relationship with the account’s business. | +| phone | object | All keys listed [here](https://razorpay.com/docs/api/partners/stakeholder/#create-a-stakeholder) are supported | +| addresses | object | All keys listed [here](https://razorpay.com/docs/api/partners/stakeholder/#create-a-stakeholder) are supported | +| kyc | object | All keys listed [here](https://razorpay.com/docs/api/partners/stakeholder/#create-a-stakeholder) are supported | +| notes | object | A key-value pair | + +**Response:** +```json +{ + "entity": "stakeholder", + "relationship": { + "director": true + }, + "phone": { + "primary": "7474747474", + "secondary": "7474747474" + }, + "notes": { + "random_key_by_partner": "random_value" + }, + "kyc": { + "pan": "AVOPB1111K" + }, + "id": "sth_GLGgm8fFCKc92m", + "name": "Gaurav Kumar", + "email": "gaurav.kumar@example.com", + "percentage_ownership": 10, + "addresses": { + "residential": { + "street": "506, Koramangala 1st block", + "city": "Bengaluru", + "state": "Karnataka", + "postal_code": "560034", + "country": "IN" + } + } +} +``` + +------------------------------------------------------------------------------------------------------- + +### Edit Stakeholder +```py +accountId = "acc_GP4lfNA0iIMn5B" +stakeholderId = "sth_GOQ4Eftlz62TSL" + +client.stakeholder.edit(accountId, stakeholderId, { + "percentage_ownership": 20, + "name": "Gauri Kumar", + "relationship": { + "director": False, + "executive": True + }, + "phone": { + "primary": "9898989898", + "secondary": "9898989898" + }, + "addresses": { + "residential": { + "street": "507, Koramangala 1st block", + "city": "Bangalore", + "state": "Karnataka", + "postal_code": "560035", + "country": "IN" + } + }, + "kyc": { + "pan": "AVOPB1111J" + }, + "notes": { + "random_key_by_partner": "random_value2" + } +}) +``` + +**Parameters:** + +| Name | Type | Description | +|---------------|-------------|---------------------------------------------| +| accountId* | string | The unique identifier of a sub-merchant account generated by Razorpay. | +| stakeholderId* | string | The unique identifier of the stakeholder whose details are to be fetched. | +| name | string | The stakeholder's name as per the PAN card. The maximum length is 255 characters. | +| percentage_ownership | float | The stakeholder's ownership of the business in percentage. Only two decimal places are allowed. For example, `87.55`. The maximum length is 100 characters. | +| relationship | boolean | The stakeholder's relationship with the account’s business. | +| phone | object | All keys listed [here](https://razorpay.com/docs/api/partners/stakeholder/#update-a-stakeholder) are supported | +| addresses | object | All keys listed [here](https://razorpay.com/docs/api/partners/stakeholder/#update-a-stakeholder) are supported | +| kyc | object | All keys listed [here](https://razorpay.com/docs/api/partners/stakeholder/#update-a-stakeholder) are supported | +| notes | object | A key-value pair | + +**Response:** +```json +{ + "id": "acc_GP4lfNA0iIMn5B", + "type": "standard", + "status": "created", + "email": "gauri@example.org", + "profile": { + "category": "healthcare", + "subcategory": "clinic", + "addresses": { + "registered": { + "street1": "507, Koramangala 1st block", + "street2": "MG Road-1", + "city": "Bengalore", + "state": "KARNATAKA", + "postal_code": "560034", + "country": "IN" + } + } + }, + "notes": [], + "created_at": 1610603081, + "phone": "9000090000", + "reference_id": "randomId", + "business_type": "partnership", + "legal_business_name": "Acme Corp", + "customer_facing_business_name": "ABCD Ltd" +} +``` +------------------------------------------------------------------------------------------------------- + +### Fetch all accounts +```py +accountId = "acc_GP4lfNA0iIMn5B" + +client.stakeholder.all(accountId) +``` + +**Parameters:** + +| Name | Type | Description | +|---------------|-------------|---------------------------------------------| +| accountId* | string | The unique identifier of a sub-merchant account generated by Razorpay. | + +**Response:** +```json +{ + "entity": "collection", + "items": [ + { + "id": "GZ13yPHLJof9IE", + "entity": "stakeholder", + "relationship": { + "director": true + }, + "phone": { + "primary": "9000090000", + "secondary": "9000090000" + }, + "notes": { + "random_key_by_partner": "random_value" + }, + "kyc": { + "pan": "AVOPB1111K" + }, + "name": "Gaurav Kumar", + "email": "gaurav.kumar@acme.org", + "percentage_ownership": 10, + "addresses": { + "residential": { + "street": "506, Koramangala 1st block", + "city": "Bengaluru", + "state": "Karnataka", + "postal_code": "560034", + "country": "in" + } + } + } + ], + "count": 1 +} +``` + +------------------------------------------------------------------------------------------------------- + +### Fetch an stakeholder +```py +accountId = "acc_GP4lfNA0iIMn5B" + +stakeholderId = "sth_GOQ4Eftlz62TSL" + +client.stakeholder.fetch(accountId, stakeholderId) +``` + +**Parameters:** + +| Name | Type | Description | +|-------------|-------------|---------------------------------------------| +| accountId* | string | The unique identifier of a sub-merchant account generated by Razorpay. | +| stakeholderId* | string | The unique identifier of the stakeholder whose details are to be fetched. | + +**Response:** +```json +{ + "entity": "stakeholder", + "relationship": { + "director": true + }, + "phone": { + "primary": "9000090000", + "secondary": "9000090000" + }, + "notes": { + "random_key_by_partner": "random_value2" + }, + "kyc": { + "pan": "AVOPB1111J" + }, + "id": "sth_GOQ4Eftlz62TSL", + "name": "Gauri Kumar", + "email": "gauri@example.com", + "percentage_ownership": 20, + "addresses": { + "residential": { + "street": "507, Koramangala 1st block", + "city": "Bangalore", + "state": "Karnataka", + "postal_code": "560035", + "country": "in" + } + } +} +``` + +------------------------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------------------------- + +### Upload stakeholders documents +```py +accountId = "acc_M83Uw27KXuC7c8" +stakeholderId = "sth_M83WuwmrCFa55g" + +file = open('/Users/your_name/Downloads/sample_uploaded.jpeg', 'rb') + +client.stakeholder.uploadStakeholderDoc(accoundId, stakeholderId, { + "file" : file, + "document_type" : "aadhar_front" +}) +``` + +**Parameters:** + +| Name | Type | Description | +|-------------|-------------|---------------------------------------------| +| accountId* | string | The unique identifier of a sub-merchant account generated by Razorpay. | +| stakeholderId* | string | The unique identifier of the stakeholder whose details are to be fetched. | +| file* | string | The URL generated once the business proof document is uploaded. | +| document_type* | string | The documents valid for the proof type to be shared. In case of individual_proof_of_address, both the front and back of a document proof must be uploaded. Possible values :
individual_proof_of_identification: `personal_pan`

individual_proof_of_address : `voter_id_back`, `voter_id_front`, `aadhar_front`, `aadhar_back`, `passport_front`, `passport_back` | + +**Response:** +```json +{ + "individual_proof_of_address": [ + { + "type": "aadhar_front", + "url": "https://rzp.io/i/bzDAbNg" + } + ] +} +``` +------------------------------------------------------------------------------------------------------- + +### Fetch stakeholders documents +```py + +accoundId = "acc_LryDIBIjBDbOWy" +stakeholderId = "sth_M0zjeiVOLRJRPW" + +client.stakeholder.fetchStakeholderDoc(accoundId, stakeholderId) +``` + +**Parameters:** + +| Name | Type | Description | +|-------------|-------------|---------------------------------------------| +| accountId* | string | The unique identifier of a sub-merchant account generated by Razorpay. | +| stakeholderId* | string | The unique identifier of the stakeholder whose details are to be fetched. | + +**Response:** +```json +{ + "business_proof_of_identification": [ + { + "type": "business_proof_url", + "url": "" + } + ] +} +``` +------------------------------------------------------------------------------------------------------- +**PN: * indicates mandatory fields** +
+
+**For reference click [here](https://razorpay.com/docs/api/partners/stakeholder)** \ No newline at end of file diff --git a/documents/token.md b/documents/token.md index 2e4e1704..349a6d87 100644 --- a/documents/token.md +++ b/documents/token.md @@ -198,7 +198,7 @@ client.token.delete(customerId, tokenId) ### Fetch VPA tokens of a customer id -```js +```py client.token.all(customerId) ``` @@ -253,6 +253,151 @@ client.token.all(customerId) ``` ------------------------------------------------------------------------------------------------------- +### Create a token + +```py + +client.token.create({ + "customer_id": "cust_1Aa00000000001", + "method": "card", + "card": { + "number": "4111111111111111", + "cvv": "123", + "expiry_month": "12", + "expiry_year": "21", + "name": "Gaurav Kumar" + }, + "authentication": { + "provider": "razorpay", + "provider_reference_id": "pay_123wkejnsakd", + "authentication_reference_number": "100222021120200000000742753928" + }, + "notes": [] +}) +``` + +**Parameters:** + +| Name | Type | Description | +|---------------|-------------|---------------------------------------------| +| customerId* | string | The id of the customer to be fetched | +| method* | string | The type of object that needs to be tokenised. Currently, `card` is the only supported value. | +| card* | object | All keys listed [here](https://razorpay.com/docs/partners/aggregators/partner-auth/token-sharing/#create-token-on-behalf-of-a-sub-merchant) are supported +| +| authentication | object | All keys listed [here](https://razorpay.com/docs/partners/aggregators/partner-auth/token-sharing/#create-token-on-behalf-of-a-sub-merchant) are supported | + +**Response:** +```json +{ + "id": "token_IJmat4GwYATMtx", + "entity": "token", + "method": "card", + "card": { + "last4": "1111", + "network": "Visa", + "type": "credit", + "issuer": "IDFB", + "international": false, + "emi": false, + "sub_type": "consumer" + }, + "customer": { + "id": "cust_1Aa00000000001", + "entity": "customer", + "name": "Bob", + "email": "bob@gmail.com", + "contact": "9000090000", + "gstin": null, + "notes": { + "notes_key_1": "Tea, Earl Grey, Hot", + "notes_key_2": "Tea, Earl Grey… decaf." + }, + "created_at": 1658390470 + }, + "expired_at": 1701368999, + "customer_id": "cust_1Aa00000000001", + "compliant_with_tokenisation_guidelines": true, + "status": "active", + "notes": [] +} +``` +------------------------------------------------------------------------------------------------------- + +### Fetch token +```py +client.token.fetch({"id": "token_4lsdksD31GaZ09"}) +``` + +**Parameters:** + +| Name | Type | Description | +|-------------|-------------|---------------------------------------------| +| id* | string | The unique identifier of a sub-merchant account generated by Razorpay. | + +**Response:** +```json +{ + "id": "token_4lsdksD31GaZ09", + "entity": "token", + "customer_id": "cust_1Aa00000000001", + "method": "card", + "card": { + "last4": "3335", + "network": "Visa", + "type": "debit", + "issuer": "HDFC", + "international": false, + "emi": true, + "sub_type": "consumer", + "token_iin": "453335" + }, + "compliant_with_tokenisation_guidelines": true, + "expired_at": 1748716199, + "status": "active", + "status_reason": null, + "notes": [] +} +``` +------------------------------------------------------------------------------------------------------- +### Delete a token +```py +client.token.delete({"id": "token_4lsdksD31GaZ09"}) +``` + +**Parameters:** + +| Name | Type | Description | +|-------------|-------------|---------------------------------------------| +| id* | string | The unique identifier of a sub-merchant account generated by Razorpay. | + +**Response:** +```json +[] +``` +------------------------------------------------------------------------------------------------------- + +### Process a Payment on another PA/PG with Token +```py +client.token.processPaymentOnAlternatePAorPG({"id":"spt_4lsdksD31GaZ09"}) +``` + +**Parameters:** + +| Name | Type | Description | +|-------------|-------------|---------------------------------------------| +| id* | string | The unique identifier of the token whose details are to be fetched. | + +**Response:** +```json +{ + "card": { + "number": "4016981500100002", + "expiry_month" : "12", + "expiry_year" : 2021 + } +} +``` +------------------------------------------------------------------------------------------------------- **PN: * indicates mandatory fields**

diff --git a/documents/webhook.md b/documents/webhook.md new file mode 100644 index 00000000..acb391a0 --- /dev/null +++ b/documents/webhook.md @@ -0,0 +1,224 @@ +## Webhook + +### Create a Webhook +```py +accountId = "acc_GP4lfNA0iIMn5B" + +client.webhook.create({ + "url": "https://google.com", + "alert_email": "gaurav.kumar@example.com", + "secret": "12345", + "events": [ + "payment.authorized", + "payment.failed", + "payment.captured", + "payment.dispute.created", + "refund.failed", + "refund.created" + ] +}, accountId) +``` + +**Parameters:** + +| Name | Type | Description | +|---------------|-------------|---------------------------------------------| +| accountId* | string | The unique identifier of a sub-merchant account generated by Razorpay. | +| url* | string | The URL where you receive the webhook payload when an event is triggered. The maximum length is 255 characters. | +| alert_email | string | This is the email address to which notifications must be sent in case of webhook failure. | +| secret | string | A secret for the webhook endpoint that is used to validate that the webhook is from Razorpay. | +| events | string | The required events from the list of Active Events. For example `payment.authorized`, `payment.captured`, `payment.failed`, `payment.dispute.created`, `refund.failed`, `refund.created` and so on. | + +**Response:** +```json +{ + "id": "JebiXkKGYwua5L", + "created_at": 1654605478, + "updated_at": 1654605478, + "service": "beta-api-live", + "owner_id": "JOGUdtKu3dB03d", + "owner_type": "merchant", + "context": [], + "disabled_at": 0, + "url": "https://google.com", + "alert_email": "gaurav.kumar@example.com", + "secret_exists": true, + "entity": "webhook", + "active": true, + "events": [ + "payment.authorized", + "payment.failed", + "payment.captured", + "payment.dispute.created", + "refund.failed", + "refund.created" + ] +} +``` + +------------------------------------------------------------------------------------------------------- + +### Edit Webhook +```py +webhookId = "HK890egfiItP3H" + +accountId = "acc_GP4lfNA0iIMn5B" + +client.webhook.edit(webhookId, accountId,{ + "url": "https://www.linkedin.com", + "events": [ + "refund.created" + ] +}) +``` + +**Parameters:** + +| Name | Type | Description | +|---------------|-------------|---------------------------------------------| +| accountId* | string | The unique identifier of a sub-merchant account generated by Razorpay. | +| webhookId* | string | The unique identifier of the webhook whose details are to be updated | +| url | string | The URL where you receive the webhook payload when an event is triggered. The maximum length is 255 characters. | +| events | string | The required events from the list of Active Events. For example `payment.authorized`, `payment.captured`, `payment.failed`, `payment.dispute.created`, `refund.failed`, `refund.created` and so on. | + +**Response:** +```json +{ + "id": "HK890egfiItP3H", + "created_at": 1623060358, + "updated_at": 1623067148, + "service": "beta-api-test", + "owner_id": "H3kYHQ635sBwXG", + "owner_type": "merchant", + "context": [], + "disabled_at": 0, + "url": "https://www.linkedin.com", + "alert_email": "gaurav.kumar@example.com", + "secret_exists": true, + "entity": "webhook", + "active": true, + "events": [ + "refund.created" + ] +} +``` +------------------------------------------------------------------------------------------------------- + +### Delete an account +```py +accountId = "acc_GP4lfNA0iIMn5B" + +webhookId = "HK890egfiItP3H" + +client.webhook.delete(webhookId, accountId) +``` + +**Parameters:** + +| Name | Type | Description | +|---------------|-------------|---------------------------------------------| +| accountId* | string | The unique identifier of a sub-merchant account that must be deleted. | +| webhookId* | string | The unique identifier of the webhook whose details are to be updated | + +**Response:** +```json +[] +``` + +------------------------------------------------------------------------------------------------------- + +### Fetch a webhook +```py +accountId = "acc_GP4lfNA0iIMn5B" + +webhookId = "HK890egfiItP3H" + +client.webhook.fetch(webhookId, accountId) +``` + +**Parameters:** + +| Name | Type | Description | +|-------------|-------------|---------------------------------------------| +| accountId* | string | The unique identifier of a sub-merchant account generated by Razorpay. | +| webhookId* | string | The unique identifier of the webhook whose details are to be updated | + +**Response:** +```json +{ + "id": "HK890egfiItP3H", + "created_at": 1623060358, + "updated_at": 1623060358, + "owner_id": "H3kYHQ635sBwXG", + "owner_type": "merchant", + "context": [], + "disabled_at": 0, + "url": "https://en1mwkqo5ioct.x.pipedream.net", + "alert_email": "gaurav.kumar@example.com", + "secret_exists": true, + "entity": "webhook", + "active": true, + "events": [ + "payment.authorized", + "payment.failed", + "payment.captured", + "payment.dispute.created", + "refund.failed", + "refund.created" + ] +} +``` + +------------------------------------------------------------------------------------------------------- + +### Fetch all Webhooks +```py +accountId = "acc_GP4lfNA0iIMn5B" + +client.webhook.all({ + "count": 3 +}, accountId) +``` + +**Parameters:** + +| Name | Type | Description | +|-------------|-------------|---------------------------------------------| +| accountId* | string | The unique identifier of a sub-merchant account generated by Razorpay. | +| from | integer | Timestamp, in seconds, from when the webhooks are to be fetched. | +| to | integer | Timestamp, in seconds, till when the webhooks are to be fetched. | +| count | integer | Number of webhooks to be fetched. The default value is `10` and the maximum value is `100`. This can be used for pagination, in combination with `skip`. | +| skip | integer | Number of records to be skipped while fetching the webhooks. This can be used for pagination, in combination with `count`. | + +**Response:** +```json +{ + "id": "HK890egfiItP3H", + "created_at": 1623060358, + "updated_at": 1623060358, + "owner_id": "H3kYHQ635sBwXG", + "owner_type": "merchant", + "context": [], + "disabled_at": 0, + "url": "https://en1mwkqo5ioct.x.pipedream.net", + "alert_email": "gaurav.kumar@example.com", + "secret_exists": true, + "entity": "webhook", + "active": true, + "events": [ + "payment.authorized", + "payment.failed", + "payment.captured", + "payment.dispute.created", + "refund.failed", + "refund.created" + ] +} +``` + +------------------------------------------------------------------------------------------------------- + +**PN: * indicates mandatory fields** +
+
+**For reference click [here](https://razorpay.com/docs/api/partners/webhooks)** \ No newline at end of file diff --git a/razorpay/__init__.py b/razorpay/__init__.py index 1c6a2c1b..92fcd45d 100644 --- a/razorpay/__init__.py +++ b/razorpay/__init__.py @@ -20,6 +20,11 @@ from .utility import Utility from .constants import ERROR_CODE from .constants import HTTP_STATUS_CODE +from .resources import Account +from .resources import Stakeholder +from .resources import Product +from .resources import Iin +from .resources import Webhook __all__ = [ 'Payment', @@ -44,4 +49,9 @@ 'Qrcode', 'HTTP_STATUS_CODE', 'ERROR_CODE', + 'Account', + 'Stakeholder', + 'Product', + 'Iin', + 'Webhook' ] diff --git a/razorpay/client.py b/razorpay/client.py index f835e139..ea6cf08d 100644 --- a/razorpay/client.py +++ b/razorpay/client.py @@ -176,6 +176,23 @@ def put(self, path, data, **options): data, options = self._update_request(data, options) return self.request('put', path, data=data, **options) + def file(self, path, data, **options): + fileDict = {} + fieldDict = {} + + if('file' not in data): + # if file is not exists in the dictionary + data['file'] = "" + + fileDict['file'] = data['file'] + + # Create a dict of form fields + for fields in data: + if(fields != 'file'): + fieldDict[str(fields)] = data[fields] + + return self.request('post', path, files=fileDict, data=fieldDict, **options) + def _update_request(self, data, options): """ Updates The resource data and header options diff --git a/razorpay/constants/url.py b/razorpay/constants/url.py index 3f2be33e..e9ae8dea 100644 --- a/razorpay/constants/url.py +++ b/razorpay/constants/url.py @@ -1,5 +1,7 @@ class URL(object): - BASE_URL = 'https://api.razorpay.com/v1' + BASE_URL = 'https://api.razorpay.com' + V1 = '/v1' + V2 = '/v2' ORDER_URL = "/orders" INVOICE_URL = "/invoices" PAYMENT_LINK_URL = "/payment_links" @@ -17,3 +19,10 @@ class URL(object): QRCODE_URL = "/payments/qr_codes" REGISTRATION_LINK_URL = "/subscription_registration" FUND_ACCOUNT_URL = "/fund_accounts" + ACCOUNT = "/accounts" + STAKEHOLDER = "/stakeholders" + PRODUCT = "/products" + TNC = "/tnc" + TOKEN = "/tokens" + IIN = "/iins" + WEBHOOK = "/webhooks" diff --git a/razorpay/resources/__init__.py b/razorpay/resources/__init__.py index 39fa1323..68917d25 100644 --- a/razorpay/resources/__init__.py +++ b/razorpay/resources/__init__.py @@ -16,6 +16,11 @@ from .settlement import Settlement from .item import Item from .fund_account import FundAccount +from .account import Account +from .stakeholder import Stakeholder +from .product import Product +from .iin import Iin +from .webhook import Webhook __all__ = [ 'Payment', @@ -35,5 +40,10 @@ 'Settlement', 'Item', 'QrCode', - 'FundAccount' + 'FundAccount', + 'Account', + 'Stakeholder', + 'Product', + 'Iin', + 'Webhook' ] diff --git a/razorpay/resources/account.py b/razorpay/resources/account.py new file mode 100644 index 00000000..d9b29211 --- /dev/null +++ b/razorpay/resources/account.py @@ -0,0 +1,74 @@ +from .base import Resource +from ..constants.url import URL + + +class Account(Resource): + def __init__(self, client=None): + super(Account, self).__init__(client) + self.base_url = URL.V2 + URL.ACCOUNT + + def create(self, data={}, **kwargs): + """ + Create account from given dict + + Returns: + Account Dict which was created + """ + url = self.base_url + return self.post_url(url, data, **kwargs) + + def fetch(self, account_id, data={}, **kwargs): + """ + Fetch account for given Id + + Args: + account_id : Id for which addon object has to be retrieved + + Returns: + account dict for given account_id + """ + return super(Account, self).fetch(account_id, data, **kwargs) + + def edit(self, account_id, data={}, **kwargs): + """ + Edit account information from given dict + + Returns: + Account Dict which was edited + """ + url = '{}/{}'.format(self.base_url, account_id) + + return self.patch_url(url, data, **kwargs) + + def delete(self, account_id, data={}, **kwargs): + """ + Delete account for given id + + Args: + account_id : Id for which account object has to be deleted + """ + url = '{}/{}'.format(self.base_url, account_id) + + return self.delete_url(url, data, **kwargs) + + def uploadAccountDoc(self, account_id, data={}, **kwargs): + """ + Upload Account Documents + + Returns: + Account Document dict which was created + """ + url = '{}/{}/{}'.format(self.base_url, account_id, "documents") + + return self.file_url(url, data, **kwargs) + + def fetchAccountDoc(self, account_id, data={}, **kwargs): + """ + Fetch Account Documents + + Returns: + Account Document dict for given account_id + """ + url = '{}/{}/{}'.format(self.base_url, account_id, "documents") + + return self.get_url(url, data, **kwargs) diff --git a/razorpay/resources/addon.py b/razorpay/resources/addon.py index a3953c94..06fc5dea 100644 --- a/razorpay/resources/addon.py +++ b/razorpay/resources/addon.py @@ -5,10 +5,10 @@ class Addon(Resource): def __init__(self, client=None): super(Addon, self).__init__(client) - self.base_url = URL.ADDON_URL + self.base_url = URL.V1 + URL.ADDON_URL def fetch(self, addon_id, data={}, **kwargs): - """" + """ Fetch addon for given Id Args: @@ -31,7 +31,7 @@ def delete(self, addon_id, data={}, **kwargs): return self.delete_url(url, data, **kwargs) def all(self, data={}, **kwargs): - """" + """ Fetch all Add-ons Returns: Dictionary of Add-ons diff --git a/razorpay/resources/base.py b/razorpay/resources/base.py index cbfd018d..72a9a565 100644 --- a/razorpay/resources/base.py +++ b/razorpay/resources/base.py @@ -28,3 +28,6 @@ def delete_url(self, url, data, **kwargs): def delete(self, id, data, **kwargs): url = "{}/{}/delete".format(self.base_url, id) return self.delete_url(url, data, **kwargs) + + def file_url(self, url, data, **kwargs): + return self.client.file(url, data, **kwargs) \ No newline at end of file diff --git a/razorpay/resources/card.py b/razorpay/resources/card.py index e6913afe..7bbb4b68 100644 --- a/razorpay/resources/card.py +++ b/razorpay/resources/card.py @@ -5,10 +5,10 @@ class Card(Resource): def __init__(self, client=None): super(Card, self).__init__(client) - self.base_url = URL.CARD_URL + self.base_url = URL.V1 + URL.CARD_URL def fetch(self, card_id, data={}, **kwargs): - """" + """ Fetch Card for given Id Args: @@ -18,3 +18,16 @@ def fetch(self, card_id, data={}, **kwargs): Card dict for given card Id """ return super(Card, self).fetch(card_id, data, **kwargs) + + def requestCardReference(self, data={}, **kwargs): + """ + Fetch card reference number for a specific card + + Args: + number : The card number whose PAR or network reference id should be retrieved. + + Returns: + Card dict for given card Id + """ + url = "{}/{}".format(self.base_url, "fingerprints") + return self.post_url(url, data, **kwargs) diff --git a/razorpay/resources/customer.py b/razorpay/resources/customer.py index d5ce5054..96628247 100644 --- a/razorpay/resources/customer.py +++ b/razorpay/resources/customer.py @@ -5,10 +5,10 @@ class Customer(Resource): def __init__(self, client=None): super(Customer, self).__init__(client) - self.base_url = URL.CUSTOMER_URL + self.base_url = URL.V1 + URL.CUSTOMER_URL def fetch(self, customer_id, data={}, **kwargs): - """" + """ Fetch Customer for given Id Args: @@ -20,7 +20,7 @@ def fetch(self, customer_id, data={}, **kwargs): return super(Customer, self).fetch(customer_id, data, **kwargs) def create(self, data={}, **kwargs): - """" + """ Create Customer from given dict Returns: @@ -30,7 +30,7 @@ def create(self, data={}, **kwargs): return self.post_url(url, data, **kwargs) def edit(self, customer_id, data={}, **kwargs): - """" + """ Edit Customer information from given dict Returns: @@ -41,7 +41,7 @@ def edit(self, customer_id, data={}, **kwargs): return self.put_url(url, data, **kwargs) def all(self, data={}, **kwargs): - """" + """ Fetch all customer Returns: diff --git a/razorpay/resources/fund_account.py b/razorpay/resources/fund_account.py index 98b02203..27463642 100644 --- a/razorpay/resources/fund_account.py +++ b/razorpay/resources/fund_account.py @@ -5,10 +5,10 @@ class FundAccount(Resource): def __init__(self, client=None): super(FundAccount, self).__init__(client) - self.base_url = URL.FUND_ACCOUNT_URL + self.base_url = URL.V1 + URL.FUND_ACCOUNT_URL def all(self, data={}, **kwargs): - """" + """ Fetch all Fund Account entities Returns: @@ -17,7 +17,7 @@ def all(self, data={}, **kwargs): return super(FundAccount, self).all(data, **kwargs) def create(self, data={}, **kwargs): - """" + """ Create a fund account Args: diff --git a/razorpay/resources/iin.py b/razorpay/resources/iin.py new file mode 100644 index 00000000..b3c87eda --- /dev/null +++ b/razorpay/resources/iin.py @@ -0,0 +1,19 @@ +from .base import Resource +from ..constants.url import URL + + +class Iin(Resource): + def __init__(self, client=None): + super(Iin, self).__init__(client) + self.base_url = URL.V1 + URL.IIN + + def fetch(self, token_iin, data={}, **kwargs): + """ + fetch card properties using token iin + + Returns: + Iin dict for given token iin + """ + + return super(Iin, self).fetch(token_iin, data, **kwargs) + diff --git a/razorpay/resources/invoice.py b/razorpay/resources/invoice.py index 8a25af1c..a5a37fcf 100644 --- a/razorpay/resources/invoice.py +++ b/razorpay/resources/invoice.py @@ -6,14 +6,14 @@ class Invoice(Resource): def __init__(self, client=None): super(Invoice, self).__init__(client) - self.base_url = URL.INVOICE_URL + self.base_url = URL.V1 + URL.INVOICE_URL def fetch_all(self, data={}, **kwargs): # pragma: no cover warnings.warn("Will be Deprecated in next release", DeprecationWarning) return self.all(data, **kwargs) def all(self, data={}, **kwargs): - """" + """ Fetch all Invoice entities Returns: @@ -22,7 +22,7 @@ def all(self, data={}, **kwargs): return super(Invoice, self).all(data, **kwargs) def fetch(self, invoice_id, data={}, **kwargs): - """" + """ Fetch Invoice for given Id Args: @@ -34,7 +34,7 @@ def fetch(self, invoice_id, data={}, **kwargs): return super(Invoice, self).fetch(invoice_id, data, **kwargs) def create(self, data={}, **kwargs): - """" + """ Create Invoice from given dict Args: @@ -47,7 +47,7 @@ def create(self, data={}, **kwargs): return self.post_url(url, data, **kwargs) def notify_by(self, invoice_id, medium, **kwargs): - """" + """ Send/Resend notifications to customer via email/sms Args: @@ -61,7 +61,7 @@ def notify_by(self, invoice_id, medium, **kwargs): return self.post_url(url, {}, **kwargs) def cancel(self, invoice_id, **kwargs): - """" + """ Cancel an unpaid Invoice with given ID via API It can only be called on an invoice that is not in the paid state. @@ -74,7 +74,7 @@ def cancel(self, invoice_id, **kwargs): return self.post_url(url, {}, **kwargs) def delete(self, invoice_id, **kwargs): - """" + """ Delete an invoice You can delete an invoice which is in the draft state. @@ -87,7 +87,7 @@ def delete(self, invoice_id, **kwargs): return self.delete_url(url, {}, **kwargs) def issue(self, invoice_id, **kwargs): - """" + """ Issues an invoice in draft state Args: @@ -99,7 +99,7 @@ def issue(self, invoice_id, **kwargs): return self.post_url(url, {}, **kwargs) def edit(self, invoice_id, data={}, **kwargs): - """" + """ Update an invoice In draft state all the attributes are allowed. diff --git a/razorpay/resources/item.py b/razorpay/resources/item.py index 2965f327..be00e872 100644 --- a/razorpay/resources/item.py +++ b/razorpay/resources/item.py @@ -5,10 +5,10 @@ class Item(Resource): def __init__(self, client=None): super(Item, self).__init__(client) - self.base_url = URL.ITEM_URL + self.base_url = URL.V1 + URL.ITEM_URL def create(self, data={}, **kwargs): - """" + """ Create item Returns: @@ -18,7 +18,7 @@ def create(self, data={}, **kwargs): return self.post_url(url, data, **kwargs) def fetch(self, item_id, data={}, **kwargs): - """" + """ Fetch an Item Args: @@ -30,7 +30,7 @@ def fetch(self, item_id, data={}, **kwargs): return super(Item, self).fetch(item_id, data, **kwargs) def all(self, data={}, **kwargs): - """" + """ Fetch all items Returns: @@ -39,7 +39,7 @@ def all(self, data={}, **kwargs): return super(Item, self).all(data, **kwargs) def edit(self, item_id, data={}, **kwargs): - """" + """ Update an Item Returns: @@ -50,7 +50,7 @@ def edit(self, item_id, data={}, **kwargs): return self.patch_url(url, data, **kwargs) def delete(self, item_id, **kwargs): - """" + """ Delete an Item Args: diff --git a/razorpay/resources/order.py b/razorpay/resources/order.py index fa323b50..fb601ccf 100644 --- a/razorpay/resources/order.py +++ b/razorpay/resources/order.py @@ -6,7 +6,7 @@ class Order(Resource): def __init__(self, client=None): super(Order, self).__init__(client) - self.base_url = URL.ORDER_URL + self.base_url = URL.V1 + URL.ORDER_URL def fetch_all(self, data={}, **kwargs): # pragma: no cover warnings.warn("Will be Deprecated in next release, use all", @@ -14,7 +14,7 @@ def fetch_all(self, data={}, **kwargs): # pragma: no cover return self.all(data, **kwargs) def all(self, data={}, **kwargs): - """" + """ Fetch all Order entities Returns: @@ -23,7 +23,7 @@ def all(self, data={}, **kwargs): return super(Order, self).all(data, **kwargs) def fetch(self, order_id, data={}, **kwargs): - """" + """ Fetch Order for given Id Args: @@ -40,7 +40,7 @@ def fetch_all_payments(self, order_id, data={}, **kwargs): # pragma: no cover return self.payments(order_id, data, **kwargs) def payments(self, order_id, data={}, **kwargs): - """" + """ Fetch Payment for Order Id Args: @@ -53,7 +53,7 @@ def payments(self, order_id, data={}, **kwargs): return self.get_url(url, data, **kwargs) def create(self, data={}, **kwargs): - """" + """ Create Order from given dict Args: @@ -71,7 +71,7 @@ def create(self, data={}, **kwargs): return self.post_url(url, data, **kwargs) def edit(self, order_id, data={}, **kwargs): - """" + """ Update order Args: diff --git a/razorpay/resources/payment.py b/razorpay/resources/payment.py index 4c2efe23..ee5e3130 100644 --- a/razorpay/resources/payment.py +++ b/razorpay/resources/payment.py @@ -6,7 +6,7 @@ class Payment(Resource): def __init__(self, client=None): super(Payment, self).__init__(client) - self.base_url = URL.PAYMENTS_URL + self.base_url = URL.V1 + URL.PAYMENTS_URL def fetch_all(self, data={}, **kwargs): # pragma: no cover warnings.warn("Will be Deprecated in next release, use all", @@ -14,7 +14,7 @@ def fetch_all(self, data={}, **kwargs): # pragma: no cover return self.all(data, **kwargs) def all(self, data={}, **kwargs): - """" + """ Fetch all Payment entities Returns: @@ -23,7 +23,7 @@ def all(self, data={}, **kwargs): return super(Payment, self).all(data, **kwargs) def fetch(self, payment_id, data={}, **kwargs): - """" + """ Fetch Payment for given Id Args: @@ -35,7 +35,7 @@ def fetch(self, payment_id, data={}, **kwargs): return super(Payment, self).fetch(payment_id, data, **kwargs) def capture(self, payment_id, amount, data={}, **kwargs): # nosemgrep : python.lang.correctness.common-mistakes.default-mutable-dict.default-mutable-dict - """" + """ Capture Payment for given Id Args: @@ -50,7 +50,7 @@ def capture(self, payment_id, amount, data={}, **kwargs): # nosemgrep : python.l return self.post_url(url, data, **kwargs) def refund(self, payment_id, amount, data={}, **kwargs): # pragma: no cover # nosemgrep : python.lang.correctness.common-mistakes.default-mutable-dict.default-mutable-dict - """" + """ Refund Payment for given Id Args: @@ -65,7 +65,7 @@ def refund(self, payment_id, amount, data={}, **kwargs): # pragma: no cover # n return self.post_url(url, data, **kwargs) def transfer(self, payment_id, data={}, **kwargs): - """" + """ Create Transfer for given Payment Id Args: @@ -78,7 +78,7 @@ def transfer(self, payment_id, data={}, **kwargs): return self.post_url(url, data, **kwargs) def transfers(self, payment_id, data={}, **kwargs): - """" + """ Fetches all transfer for given Payment Id Args: @@ -92,7 +92,7 @@ def transfers(self, payment_id, data={}, **kwargs): return self.get_url(url, data, **kwargs) def bank_transfer(self, payment_id, data={}, **kwargs): - """" + """ Bank Transfer Entity for given Payment Args: @@ -105,7 +105,7 @@ def bank_transfer(self, payment_id, data={}, **kwargs): return self.get_url(url, data, **kwargs) def upi_transfer(self, payment_id, data={}, **kwargs): - """" + """ UPI Transfer Entity for given Payment Args: @@ -118,7 +118,7 @@ def upi_transfer(self, payment_id, data={}, **kwargs): return self.get_url(url, data, **kwargs) def refund(self, payment_id, data={}, **kwargs): - """" + """ Create a normal refund Returns: @@ -128,7 +128,7 @@ def refund(self, payment_id, data={}, **kwargs): return self.post_url(url, data, **kwargs) def fetch_multiple_refund(self, payment_id, data={}, **kwargs): - """" + """ Fetch multiple refunds for a payment Returns: @@ -138,7 +138,7 @@ def fetch_multiple_refund(self, payment_id, data={}, **kwargs): return self.get_url(url, data, **kwargs) def fetch_refund_id(self, payment_id, refund_id, **kwargs): - """" + """ Fetch multiple refunds for a payment Returns: @@ -148,7 +148,7 @@ def fetch_refund_id(self, payment_id, refund_id, **kwargs): return self.get_url(url, {}, **kwargs) def edit(self, payment_id, data={}, **kwargs): - """" + """ Update the Payment Args: data : Dictionary having keys using which order have to be edited @@ -162,7 +162,7 @@ def edit(self, payment_id, data={}, **kwargs): return self.patch_url(url, data, **kwargs) def fetchCardDetails(self, payment_id, **kwargs): - """" + """ Fetch Card Details of a Payment Args: @@ -175,7 +175,7 @@ def fetchCardDetails(self, payment_id, **kwargs): return self.get_url(url, {}, **kwargs) def fetchDownTime(self, **kwargs): - """" + """ Fetch Card Details of a Payment Args: @@ -188,7 +188,7 @@ def fetchDownTime(self, **kwargs): return self.get_url(url, {}, **kwargs) def fetchDownTimeById(self, downtime_id, **kwargs): - """" + """ Fetch Payment Downtime Details by ID Args: @@ -201,7 +201,7 @@ def fetchDownTimeById(self, downtime_id, **kwargs): return self.get_url(url, {}, **kwargs) def createPaymentJson(self ,data={}, **kwargs): - """" + """ Create a Payment Args: @@ -216,7 +216,7 @@ def createPaymentJson(self ,data={}, **kwargs): return self.post_url(url, data, **kwargs) def createRecurring(self, data={}, **kwargs): - """" + """ Create Recurring Payments Return: Recurring Payments dict @@ -225,7 +225,7 @@ def createRecurring(self, data={}, **kwargs): return self.post_url(url, data, **kwargs) def createUpi(self, data={}, **kwargs): - """" + """ Initiate a payment Return: Payments dict @@ -234,7 +234,7 @@ def createUpi(self, data={}, **kwargs): return self.post_url(url, data, **kwargs) def validateVpa(self, data={}, **kwargs): - """" + """ Validate the VPA Return: Payments dict @@ -243,7 +243,7 @@ def validateVpa(self, data={}, **kwargs): return self.post_url(url, data, **kwargs) def fetchPaymentMethods(self, **kwargs): - """" + """ Fetch payment methods Return: Payments dict @@ -252,7 +252,7 @@ def fetchPaymentMethods(self, **kwargs): return self.get_url(url, {}, **kwargs) def otpGenerate(self, payment_id, data={}, **kwargs): - """" + """ Otp Generate Args: @@ -265,7 +265,7 @@ def otpGenerate(self, payment_id, data={}, **kwargs): return self.post_url(url, data, **kwargs) def otpSubmit(self, payment_id, data={}, **kwargs): - """" + """ Otp Submit Args: @@ -278,7 +278,7 @@ def otpSubmit(self, payment_id, data={}, **kwargs): return self.post_url(url, data, **kwargs) def otpResend(self, payment_id, data={}, **kwargs): - """" + """ Otp Resend Args: diff --git a/razorpay/resources/payment_link.py b/razorpay/resources/payment_link.py index 98d687fe..843786d6 100644 --- a/razorpay/resources/payment_link.py +++ b/razorpay/resources/payment_link.py @@ -6,14 +6,14 @@ class PaymentLink(Resource): def __init__(self, client=None): super(PaymentLink, self).__init__(client) - self.base_url = URL.PAYMENT_LINK_URL + self.base_url = URL.V1 + URL.PAYMENT_LINK_URL def fetch_all(self, data={}, **kwargs): # pragma: no cover warnings.warn("Will be Deprecated in next release", DeprecationWarning) return self.all(data, **kwargs) def all(self, data={}, **kwargs): - """" + """ Fetch all Payment link entities Returns: @@ -22,7 +22,7 @@ def all(self, data={}, **kwargs): return super(PaymentLink, self).all(data, **kwargs) def fetch(self, payment_link_id, data={}, **kwargs): - """" + """ Fetch Payment link for given Id Args: @@ -34,7 +34,7 @@ def fetch(self, payment_link_id, data={}, **kwargs): return super(PaymentLink, self).fetch(payment_link_id, data, **kwargs) def create(self, data={}, **kwargs): - """" + """ Create Payment link from given dict Args: @@ -47,7 +47,7 @@ def create(self, data={}, **kwargs): return self.post_url(url, data, **kwargs) def cancel(self, payment_link_id, **kwargs): - """" + """ Cancel an unpaid Payment link with given ID via API It can only be called on an Payment link that is not in the paid state. @@ -60,7 +60,7 @@ def cancel(self, payment_link_id, **kwargs): return self.post_url(url, {}, **kwargs) def edit(self, payment_link_id, data={}, **kwargs): - """" + """ Edit the Payment link Args: data : Dictionary having keys using which order have to be edited @@ -77,7 +77,7 @@ def edit(self, payment_link_id, data={}, **kwargs): return self.patch_url(url, data, **kwargs) def notifyBy(self, payment_link_id, medium, **kwargs): - """" + """ Send notification Args: diff --git a/razorpay/resources/plan.py b/razorpay/resources/plan.py index 3b8acca7..965024b1 100644 --- a/razorpay/resources/plan.py +++ b/razorpay/resources/plan.py @@ -5,10 +5,10 @@ class Plan(Resource): def __init__(self, client=None): super(Plan, self).__init__(client) - self.base_url = URL.PLAN_URL + self.base_url = URL.V1 + URL.PLAN_URL def create(self, data={}, **kwargs): - """" + """ Create Plan from given dict Args: @@ -21,7 +21,7 @@ def create(self, data={}, **kwargs): return self.post_url(url, data, **kwargs) def fetch(self, plan_id, data={}, **kwargs): - """" + """ Fetch Plan for given Id Args: @@ -33,7 +33,7 @@ def fetch(self, plan_id, data={}, **kwargs): return super(Plan, self).fetch(plan_id, data, **kwargs) def all(self, data={}, **kwargs): - """" + """ Fetch all plan entities Returns: diff --git a/razorpay/resources/product.py b/razorpay/resources/product.py new file mode 100644 index 00000000..6774f1d6 --- /dev/null +++ b/razorpay/resources/product.py @@ -0,0 +1,49 @@ +from .base import Resource +from ..constants.url import URL + + +class Product(Resource): + def __init__(self, client=None): + super(Product, self).__init__(client) + self.base_url = URL.V2 + URL.ACCOUNT + + def requestProductConfiguration(self, account_id, data={}, **kwargs): + """ + Request a Product Configuration from given dict + + Returns: + Product Configuration Dict which was created + """ + url = '{}/{}{}'.format(self.base_url, account_id, URL.PRODUCT) + + return self.post_url(url, data, **kwargs) + + def fetch(self, account_id, product_id, data={}, **kwargs): + """ + Fetch product for given accound and product id + + Returns: + account dict for given account_id + """ + url = '{}/{}{}/{}'.format(self.base_url, account_id, URL.PRODUCT, product_id) + return self.get_url(url, data, **kwargs) + + def edit(self, account_id, product_id, data={}, **kwargs): + """ + Edit account information from given dict + + Returns: + Account Dict which was edited + """ + url = '{}/{}{}/{}'.format(self.base_url, account_id, URL.PRODUCT, product_id) + return self.patch_url(url, data, **kwargs) + + def fetchTnc(self, product_name, data={}, **kwargs): + """ + Fetch Terms and Conditions for a Sub-Merchant + + Returns: + Tnc dict for given account_id + """ + url = '{}{}/{}{}'.format(URL.V2, URL.PRODUCT, product_name, URL.TNC ) + return self.get_url(url, data, **kwargs) \ No newline at end of file diff --git a/razorpay/resources/qrcode.py b/razorpay/resources/qrcode.py index 71150cf4..0a3704d0 100644 --- a/razorpay/resources/qrcode.py +++ b/razorpay/resources/qrcode.py @@ -5,10 +5,10 @@ class Qrcode(Resource): def __init__(self, client=None): super(Qrcode, self).__init__(client) - self.base_url = URL.QRCODE_URL + self.base_url = URL.V1 + URL.QRCODE_URL def fetch(self, qrcode_id, data={}, **kwargs): - """" + """ Fetch a Qr code Args: @@ -20,7 +20,7 @@ def fetch(self, qrcode_id, data={}, **kwargs): return super(Qrcode, self).fetch(qrcode_id, data, **kwargs) def create(self, data={}, **kwargs): - """" + """ Create a QR Code Returns: @@ -30,7 +30,7 @@ def create(self, data={}, **kwargs): return self.post_url(url, data, **kwargs) def all(self, data={}, **kwargs): - """" + """ Fetch All Qr Code Returns: @@ -39,7 +39,7 @@ def all(self, data={}, **kwargs): return super(Qrcode, self).all(data, **kwargs) def fetch_all_payments(self, qrcode_id, data={}, **kwargs): - """" + """ Fetch Payments for a QR Code Returns: @@ -49,7 +49,7 @@ def fetch_all_payments(self, qrcode_id, data={}, **kwargs): return self.get_url(url, data, **kwargs) def close(self, qrcode_id, **kwargs): - """" + """ Close a QR Code Returns: diff --git a/razorpay/resources/refund.py b/razorpay/resources/refund.py index 5b2ba1f1..92f5fc0f 100644 --- a/razorpay/resources/refund.py +++ b/razorpay/resources/refund.py @@ -6,7 +6,7 @@ class Refund(Resource): def __init__(self, client=None): super(Refund, self).__init__(client) - self.base_url = URL.REFUNDS_URL + self.base_url = URL.V1 + URL.REFUNDS_URL def fetch_all(self, data={}, **kwargs): # pragma: no cover warnings.warn("Will be Deprecated in next release, use all", @@ -21,7 +21,7 @@ def create(self, data={}, **kwargs): return self.post_url(url, data, **kwargs) def all(self, data={}, **kwargs): - """" + """ Fetch All Refund Returns: @@ -30,7 +30,7 @@ def all(self, data={}, **kwargs): return super(Refund, self).all(data, **kwargs) def fetch(self, refund_id, data={}, **kwargs): - """" + """ Refund object for given paymnet Id Args: @@ -42,7 +42,7 @@ def fetch(self, refund_id, data={}, **kwargs): return super(Refund, self).fetch(refund_id, data, **kwargs) def edit(self, refund_id, data={}, **kwargs): - """" + """ Update Refund Returns: diff --git a/razorpay/resources/registration_link.py b/razorpay/resources/registration_link.py index 9dc17166..7a17ba69 100644 --- a/razorpay/resources/registration_link.py +++ b/razorpay/resources/registration_link.py @@ -5,10 +5,10 @@ class RegistrationLink(Resource): def __init__(self, client=None): super(RegistrationLink, self).__init__(client) - self.base_url = URL.REGISTRATION_LINK_URL + self.base_url = URL.V1 + URL.REGISTRATION_LINK_URL def create(self, data={}, **kwargs): - """" + """ Create a Registration Link Args: customer : Details of the customer to whom the registration link will be sent. diff --git a/razorpay/resources/settlement.py b/razorpay/resources/settlement.py index 9b7f3ea1..2918463d 100644 --- a/razorpay/resources/settlement.py +++ b/razorpay/resources/settlement.py @@ -5,10 +5,10 @@ class Settlement(Resource): def __init__(self, client=None): super(Settlement, self).__init__(client) - self.base_url = URL.SETTLEMENT_URL + self.base_url = URL.V1 + URL.SETTLEMENT_URL def all(self, data={}, **kwargs): - """" + """ Fetch all Settlement entities Returns: @@ -17,7 +17,7 @@ def all(self, data={}, **kwargs): return super(Settlement, self).all(data, **kwargs) def fetch(self, settlement_id, data={}, **kwargs): - """" + """ Fetch Settlement data for given Id Args: @@ -29,7 +29,7 @@ def fetch(self, settlement_id, data={}, **kwargs): return super(Settlement, self).fetch(settlement_id, data, **kwargs) def report(self, data={}, **kwargs): - """" + """ Settlement report for a month Returns: diff --git a/razorpay/resources/stakeholder.py b/razorpay/resources/stakeholder.py new file mode 100644 index 00000000..ab63a00c --- /dev/null +++ b/razorpay/resources/stakeholder.py @@ -0,0 +1,81 @@ +from .base import Resource +from ..constants.url import URL + + +class Stakeholder(Resource): + def __init__(self, client=None): + super(Stakeholder, self).__init__(client) + self.base_url = URL.V2 + URL.ACCOUNT + + def create(self, account_id, data={}, **kwargs): + """ + Create stakeholder from given dict and account id + + Returns: + Stakeholder Dict which was created + """ + url = '{}/{}{}'.format(self.base_url, account_id, URL.STAKEHOLDER) + + return self.post_url(url, data, **kwargs) + + def fetch(self, account_id, stakeholder_id, data={}, **kwargs): + """ + Fetch stakeholder for given account & stakeholder id + + Args: + account_id : Id for which account object has to be retrieved + stakeholder_id : Id for which stakeholder object has to be retrieved + + Returns: + stakeholder dict for given account_id + """ + url = '{}/{}{}/{}'.format(self.base_url, account_id, URL.STAKEHOLDER, stakeholder_id) + + return self.get_url(url, data, **kwargs) + + def all(self, account_id, data={}, **kwargs): + """ + Fetch all stakeholder + + Args: + account_id : Id for which account object has to be retrieved + + Returns: + stakeholder dict for given account_id + """ + url = '{}/{}{}'.format(self.base_url, account_id, URL.STAKEHOLDER) + + return self.get_url(url, data, **kwargs) + + def edit(self, account_id, stakeholder_id, data={}, **kwargs): + """ + Edit stakeholder information from given dict + + Returns: + Stakeholder Dict which was edited + """ + url = '{}/{}{}/{}'.format(self.base_url, account_id, URL.STAKEHOLDER, stakeholder_id) + + return self.patch_url(url, data, **kwargs) + + def uploadStakeholderDoc(self, account_id, stakeholder_id, data={}, **kwargs): + """ + Upload Stakeholder Documents + + Returns: + Stakeholder Document dict which was created + """ + url = '{}/{}{}/{}/{}'.format(self.base_url, account_id, URL.STAKEHOLDER, stakeholder_id, "documents") + + return self.file_url(url, data, **kwargs) + + def fetchStakeholderDoc(self, account_id, stakeholder_id, data={}, **kwargs): + """ + Fetch Stakeholder Documents + + Returns: + Stakeholder Document dict for given account & stakeholder Id + """ + url = '{}/{}{}/{}/{}'.format(self.base_url, account_id, URL.STAKEHOLDER, stakeholder_id, "documents") + + return self.get_url(url, data, **kwargs) \ No newline at end of file diff --git a/razorpay/resources/subscription.py b/razorpay/resources/subscription.py index 037640f1..d313b963 100644 --- a/razorpay/resources/subscription.py +++ b/razorpay/resources/subscription.py @@ -5,10 +5,10 @@ class Subscription(Resource): def __init__(self, client=None): super(Subscription, self).__init__(client) - self.base_url = URL.SUBSCRIPTION_URL + self.base_url = URL.V1 + URL.SUBSCRIPTION_URL def all(self, data={}, **kwargs): - """" + """ Fetch all Subscription entities Returns: @@ -17,7 +17,7 @@ def all(self, data={}, **kwargs): return super(Subscription, self).all(data, **kwargs) def fetch(self, subscription_id, data={}, **kwargs): - """" + """ Fetch Subscription for given Id Args: @@ -29,7 +29,7 @@ def fetch(self, subscription_id, data={}, **kwargs): return super(Subscription, self).fetch(subscription_id, data, **kwargs) def create(self, data={}, **kwargs): - """" + """ Create Subscription from given dict Args: @@ -81,7 +81,7 @@ def createAddon(self, subscription_id, data={}, **kwargs): return self.post_url(url, data, **kwargs) def edit(self, subscription_id, data={}, **kwargs): - """" + """ Update particular subscription Args: @@ -93,7 +93,7 @@ def edit(self, subscription_id, data={}, **kwargs): return self.patch_url(url, data, **kwargs) def pending_update(self, subscription_id, **kwargs): - """" + """ Fetch Subscription for given Id Args: diff --git a/razorpay/resources/token.py b/razorpay/resources/token.py index 5273e25b..61bf9eab 100644 --- a/razorpay/resources/token.py +++ b/razorpay/resources/token.py @@ -5,10 +5,21 @@ class Token(Resource): def __init__(self, client=None): super(Token, self).__init__(client) - self.base_url = URL.CUSTOMER_URL + self.base_url = URL.V1 + URL.CUSTOMER_URL + + def create(self, data={}, **kwargs): + """ + Create token from given dict + + Returns: + token Dict which was created + """ + url = '{}{}'.format(URL.V1, URL.TOKEN) + + return self.post_url(url, data, **kwargs) def fetch(self, customer_id, token_id, data={}, **kwargs): - """" + """ Fetch Token for given Id and given customer Id Args: @@ -22,7 +33,7 @@ def fetch(self, customer_id, token_id, data={}, **kwargs): return self.get_url(url, data, **kwargs) def all(self, customer_id, data={}, **kwargs): - """" + """ Get all tokens for given customer Id Args: @@ -35,7 +46,7 @@ def all(self, customer_id, data={}, **kwargs): return self.get_url(url, data, **kwargs) def delete(self, customer_id, token_id, data={}, **kwargs): - """" + """ Delete Given Token For a Customer Args: @@ -46,3 +57,33 @@ def delete(self, customer_id, token_id, data={}, **kwargs): """ url = "{}/{}/tokens/{}".format(self.base_url, customer_id, token_id) return self.delete_url(url, data, **kwargs) + + def fetchToken(self, data={}, **kwargs): + """ + fetch Given Token For a Customer + + Returns: + Dict for fetch token + """ + url = '{}{}/{}'.format(URL.V1, URL.TOKEN, "fetch") + return self.post_url(url, data, **kwargs) + + def deleteToken(self, data={}, **kwargs): + """ + Delete Given Token + + Returns: + Dict for deleted token + """ + url = '{}{}/{}'.format(URL.V1, URL.TOKEN, "delete") + return self.post_url(url, data, **kwargs) + + def processPaymentOnAlternatePAorPG(self, data={}, **kwargs): + """ + Process a Payment on another PA/PG with Token Created on Razorpay + + Returns: + + """ + url = '{}{}/{}'.format(URL.V1, URL.TOKEN, "service_provider_tokens/token_transactional_data") + return self.post_url(url, data, **kwargs) diff --git a/razorpay/resources/transfer.py b/razorpay/resources/transfer.py index 914a2c52..7bf92a7e 100644 --- a/razorpay/resources/transfer.py +++ b/razorpay/resources/transfer.py @@ -6,7 +6,7 @@ class Transfer(Resource): def __init__(self, client=None): super(Transfer, self).__init__(client) - self.base_url = URL.TRANSFER_URL + self.base_url = URL.V1 + URL.TRANSFER_URL def fetch_all(self, data={}, **kwargs): # pragma: no cover warnings.warn("Will be Deprecated in next release, use all", @@ -14,14 +14,14 @@ def fetch_all(self, data={}, **kwargs): # pragma: no cover return self.all(data, **kwargs) def all(self, data={}, **kwargs): - """" + """ Fetch all Transfer entities Returns: Dictionary of Transfer data """ if 'payment_id' in data: - url = "/payments/{}/transfers".format(data['payment_id']) + url = URL.V1 + "/payments/{}/transfers".format(data['payment_id']) del data['payment_id'] return self.get_url(url, data, **kwargs) @@ -29,7 +29,7 @@ def all(self, data={}, **kwargs): return super(Transfer, self).all(data, **kwargs) def fetch(self, transfer_id, data={}, **kwargs): - """" + """ Fetch Transfer for given Id Args: @@ -41,7 +41,7 @@ def fetch(self, transfer_id, data={}, **kwargs): return super(Transfer, self).fetch(transfer_id, data, **kwargs) def create(self, data={}, **kwargs): - """" + """ Create Transfer from given dict Args: @@ -53,7 +53,7 @@ def create(self, data={}, **kwargs): return self.post_url(url, data, **kwargs) def edit(self, transfer_id, data={}, **kwargs): - """" + """ Edit Transfer from given id Args: @@ -66,7 +66,7 @@ def edit(self, transfer_id, data={}, **kwargs): return self.patch_url(url, data, **kwargs) def reverse(self, transfer_id, data={}, **kwargs): - """" + """ Reverse Transfer from given id Args: @@ -79,7 +79,7 @@ def reverse(self, transfer_id, data={}, **kwargs): return self.post_url(url, data, **kwargs) def reversals(self, transfer_id, data={}, **kwargs): - """" + """ Get all Reversal Transfer from given id Args: diff --git a/razorpay/resources/virtual_account.py b/razorpay/resources/virtual_account.py index eb5834d8..56ee7da1 100644 --- a/razorpay/resources/virtual_account.py +++ b/razorpay/resources/virtual_account.py @@ -6,10 +6,10 @@ class VirtualAccount(Resource): def __init__(self, client=None): super(VirtualAccount, self).__init__(client) - self.base_url = URL.VIRTUAL_ACCOUNT_URL + self.base_url = URL.V1 + URL.VIRTUAL_ACCOUNT_URL def all(self, data={}, **kwargs): - """" + """ Fetch all Virtual Account entities Returns: @@ -18,7 +18,7 @@ def all(self, data={}, **kwargs): return super(VirtualAccount, self).all(data, **kwargs) def fetch(self, virtual_account_id, data={}, **kwargs): - """" + """ Fetch Virtual Account for given Id Args: @@ -34,7 +34,7 @@ def fetch(self, virtual_account_id, data={}, **kwargs): **kwargs) def create(self, data={}, **kwargs): - """" + """ Create Virtual Account from given dict Args: @@ -47,7 +47,7 @@ def create(self, data={}, **kwargs): return self.post_url(url, data, **kwargs) def close(self, virtual_account_id, data={}, **kwargs): - """" + """ Close Virtual Account from given Id Args: @@ -58,7 +58,7 @@ def close(self, virtual_account_id, data={}, **kwargs): return self.post_url(url, data, **kwargs) def payments(self, virtual_account_id, data={}, **kwargs): - """" + """ Fetch Payment for Virtual Account Id Args: @@ -72,7 +72,7 @@ def payments(self, virtual_account_id, data={}, **kwargs): return self.get_url(url, data, **kwargs) def add_receiver(self, virtual_account_id, data={}, **kwargs): - """" + """ Add receiver to an existing virtual account Args: @@ -83,7 +83,7 @@ def add_receiver(self, virtual_account_id, data={}, **kwargs): return self.post_url(url, data, **kwargs) def add_allowed_player(self, virtual_account_id, data={}, **kwargs): - """" + """ Add an Allowed Payer Account Args: @@ -94,7 +94,7 @@ def add_allowed_player(self, virtual_account_id, data={}, **kwargs): return self.post_url(url, data, **kwargs) def delete_allowed_player(self, virtual_account_id, allowed_player_id, data={}, **kwargs): - """" + """ Delete an Allowed Payer Account Args: diff --git a/razorpay/resources/webhook.py b/razorpay/resources/webhook.py new file mode 100644 index 00000000..d0301d30 --- /dev/null +++ b/razorpay/resources/webhook.py @@ -0,0 +1,86 @@ +from .base import Resource +from ..constants.url import URL + + +class Webhook(Resource): + def __init__(self, client=None): + super(Webhook, self).__init__(client) + self.base_url = URL.V2 + URL.ACCOUNT + + def create(self, data={}, account_id=None, **kwargs): + """ + Create webhook from given dict + + Returns: + Webhook Dict which was created + """ + if account_id is None: + url = '{}{}'.format(URL.V1, URL.WEBHOOK) + else: + url = '{}/{}{}'.format(self.base_url, account_id, URL.WEBHOOK) + + return self.post_url(url, data, **kwargs) + + def fetch(self, webhook_id, account_id, data={}, **kwargs): + """ + Fetch webhook for given webhook id + + Args: + account_id : Id for which webhook object has to be retrieved + webhook_id : Id for which account object has to be retrieved + + Returns: + webhook dict for given webhook_id + """ + if(account_id): + url = '{}/{}{}/{}'.format(self.base_url, account_id, URL.WEBHOOK, webhook_id) + else: + url = '{}{}/{}'.format(URL.V1, URL.WEBHOOK, webhook_id) + + return self.get_url(url, data, **kwargs) + + def all(self, data={}, account_id=None, **kwargs): + """ + Fetch all webhooks + + Args: + account_id : Id for which webhook object has to be retrieved + + Returns: + webhook dict for given account_id + """ + if account_id is None: + url = '{}{}'.format(URL.V1, URL.WEBHOOK) + else: + url = '{}/{}{}'.format(self.base_url, account_id, URL.WEBHOOK) + + return self.get_url(url, data, **kwargs) + + def edit(self, webhook_id, account_id, data={}, **kwargs): + """ + Edit webhook from given dict + + Returns: + Webhook Dict which was edited + """ + if(account_id): + url = '{}/{}{}/{}'.format(self.base_url, account_id, URL.WEBHOOK, webhook_id) + return self.patch_url(url, data, **kwargs) + + else: + url = '{}{}/{}'.format(URL.V1, URL.WEBHOOK, webhook_id) + return self.put_url(url, data, **kwargs) + + def delete(self, webhook_id, account_id, data={}, **kwargs): + """ + delete webhook for given webhook id + + Args: + account_id : Id for which webhook object has to be retrieved + webhook_id : Id for which account object has to be retrieved + + Returns: + The response is always be an empty array like this - [] + """ + url = '{}/{}{}/{}'.format(self.base_url, account_id, URL.WEBHOOK, webhook_id) + return self.delete_url(url, data, **kwargs) \ No newline at end of file diff --git a/tests/helpers.py b/tests/helpers.py index ed051a92..b58aad80 100644 --- a/tests/helpers.py +++ b/tests/helpers.py @@ -16,7 +16,10 @@ def mock_file(filename): class ClientTestCase(unittest.TestCase): def setUp(self): self.base_url = 'https://api.razorpay.com/v1' - self.secondary_url = 'https://test-api.razorpay.com/v1' + self.base_url_v2 = 'https://api.razorpay.com/v2' + self.secondary_url = 'https://test-api.razorpay.com' + self.v1 = 'v1' + self.v2 = 'v2' self.payment_id = 'fake_payment_id' self.refund_id = 'fake_refund_id' self.card_id = 'fake_card_id' diff --git a/tests/mocks/fake_account.json b/tests/mocks/fake_account.json new file mode 100644 index 00000000..4ff26a74 --- /dev/null +++ b/tests/mocks/fake_account.json @@ -0,0 +1,78 @@ +{ + "id": "acc_GRWKk7qQsLnDjX", + "type": "standard", + "status": "created", + "email": "gauriagain.kumar@example.org", + "profile": { + "category": "healthcare", + "subcategory": "clinic", + "addresses": { + "registered": { + "street1": "507, Koramangala 1st block", + "street2": "MG Road", + "city": "Bengaluru", + "state": "KARNATAKA", + "postal_code": 560034, + "country": "IN" + }, + "operation": { + "street1": "507, Koramangala 6th block", + "street2": "Kormanagalo", + "city": "Bengaluru", + "state": "KARNATAKA", + "country": "IN", + "postal_code": 560047 + } + }, + "business_model": "Online Clothing ( men, women, ethnic, modern ) fashion and lifestyle, accessories, t-shirt, shirt, track pant, shoes." + }, + "notes": { + "internal_ref_id": "123123" + }, + "created_at": 1611136837, + "phone": "9000090000", + "business_type": "partnership", + "legal_business_name": "Acme Corp", + "customer_facing_business_name": "Example", + "legal_info": { + "pan": "AAACL1234C", + "gst": "18AABCU9603R1ZM" + }, + "apps": { + "websites": [ + "https://www.example.org" + ], + "android": [ + { + "url": "playstore.example.org", + "name": "Example" + } + ], + "ios": [ + { + "url": "appstore.example.org", + "name": "Example" + } + ] + }, + "brand": { + "color": "#FFFFFF" + }, + "contact_info": { + "chargeback": { + "email": "cb@example.org", + "phone": null, + "policy_url": null + }, + "refund": { + "email": "cb@example.org", + "phone": null, + "policy_url": null + }, + "support": { + "email": "support@example.org", + "phone": "9999999998", + "policy_url": "https://www.google.com" + } + } +} diff --git a/tests/mocks/fake_iin.json b/tests/mocks/fake_iin.json new file mode 100644 index 00000000..1f561c96 --- /dev/null +++ b/tests/mocks/fake_iin.json @@ -0,0 +1,26 @@ +{ + "iin": "412345", + "entity": "iin", + "network": "Visa", + "type": "credit", + "sub_type": "business", + "issuer_code": "HDFC", + "issuer_name": "HDFC Bank Ltd", + "international": false, + "is_tokenized": true, + "card_iin": "411111", + "emi": { + "available": true + }, + "recurring": { + "available": true + }, + "authentication_types": [ + { + "type": "3ds" + }, + { + "type": "otp" + } + ] +} diff --git a/tests/mocks/fake_merchant_token.json b/tests/mocks/fake_merchant_token.json new file mode 100644 index 00000000..1608d9b7 --- /dev/null +++ b/tests/mocks/fake_merchant_token.json @@ -0,0 +1,32 @@ +{ + "id": "token_IJmat4GwYATMtx", + "entity": "token", + "method": "card", + "card": { + "last4": "1111", + "network": "Visa", + "type": "credit", + "issuer": "IDFB", + "international": false, + "emi": false, + "sub_type": "consumer" + }, + "customer": { + "id": "cust_1Aa00000000001", + "entity": "customer", + "name": "Bob", + "email": "bob@gmail.com", + "contact": "9000090000", + "gstin": null, + "notes": { + "notes_key_1": "Tea, Earl Grey, Hot", + "notes_key_2": "Tea, Earl Grey… decaf." + }, + "created_at": 1658390470 + }, + "expired_at": 1701368999, + "customer_id": "cust_1Aa00000000001", + "compliant_with_tokenisation_guidelines": true, + "status": "active", + "notes": [] +} diff --git a/tests/mocks/fake_product.json b/tests/mocks/fake_product.json new file mode 100644 index 00000000..0be72add --- /dev/null +++ b/tests/mocks/fake_product.json @@ -0,0 +1,139 @@ +{ + "requested_configuration": { + "payment_methods": [] + }, + "active_configuration": { + "payment_capture": { + "mode": "automatic", + "refund_speed": "normal", + "automatic_expiry_period": 7200 + }, + "settlements": { + "account_number": null, + "ifsc_code": null, + "beneficiary_name": null + }, + "checkout": { + "theme_color": "#FFFFFF", + "flash_checkout": true, + "logo": "https://example.com/your_logo" + }, + "refund": { + "default_refund_speed": "normal" + }, + "notifications": { + "whatsapp": true, + "sms": false, + "email": [ + "b963e252-1201-45b0-9c39-c53eceb0cfd6_load@gmail.com" + ] + }, + "payment_methods": { + "netbanking": { + "enabled": true, + "instrument": [ + { + "type": "retail", + "bank": [ + "hdfc", + "sbin", + "utib", + "icic", + "scbl", + "yesb" + ] + } + ] + }, + "wallet": { + "enabled": true, + "instrument": [ + "airtelmoney", + "freecharge", + "jiomoney", + "olamoney", + "payzapp", + "mobikwik" + ] + }, + "upi": { + "enabled": true, + "instrument": [ + "upi" + ] + } + } + }, + "requirements": [ + { + "field_reference": "individual_proof_of_address", + "resolution_url": "/accounts/acc_HQVlm3bnPmccC0/stakeholders/{stakeholderId}/documents", + "status": "required", + "reason_code": "document_missing" + }, + { + "field_reference": "individual_proof_of_identification", + "resolution_url": "/accounts/acc_HQVlm3bnPmccC0/stakeholders/{stakeholderId}/documents", + "status": "required", + "reason_code": "document_missing" + }, + { + "field_reference": "business_proof_of_identification", + "resolution_url": "/accounts/acc_HQVlm3bnPmccC0/documents", + "status": "required", + "reason_code": "document_missing" + }, + { + "field_reference": "settlements.beneficiary_name", + "resolution_url": "/accounts/acc_HQVlm3bnPmccC0/products/acc_prd_HEgNpywUFctQ9e", + "status": "required", + "reason_code": "field_missing" + }, + { + "field_reference": "settlements.account_number", + "resolution_url": "/accounts/acc_HQVlm3bnPmccC0/products/acc_prd_HEgNpywUFctQ9e", + "status": "required", + "reason_code": "field_missing" + }, + { + "field_reference": "settlements.ifsc_code", + "resolution_url": "/accounts/acc_HQVlm3bnPmccC0/products/acc_prd_HEgNpywUFctQ9e", + "status": "required", + "reason_code": "field_missing" + }, + { + "field_reference": "contact_name", + "resolution_url": "/accounts/acc_HQVlm3bnPmccC0", + "status": "required", + "reason_code": "field_missing" + }, + { + "field_reference": "name", + "resolution_url": "/accounts/acc_HQVlm3bnPmccC0/stakeholders", + "status": "required", + "reason_code": "field_missing" + }, + { + "field_reference": "customer_facing_business_name", + "resolution_url": "/accounts/acc_HQVlm3bnPmccC0", + "status": "required", + "reason_code": "field_missing" + }, + { + "field_reference": "kyc.pan", + "resolution_url": "/accounts/acc_HQVlm3bnPmccC0/stakeholders", + "status": "required", + "reason_code": "field_missing" + } + ], + "tnc": { + "id": "tnc_IgohZaDBHRGjPv", + "accepted": true, + "accepted_at": 1641550798 + }, + "id": "acc_prd_HEgNpywUFctQ9e", + "account_id": "acc_HQVlm3bnPmccC0", + "product_name": "payment_gateway", + "activation_status": "needs_clarification", + "requested_at": 162547884 +} diff --git a/tests/mocks/fake_reference_card.json b/tests/mocks/fake_reference_card.json new file mode 100644 index 00000000..1c0ed3ec --- /dev/null +++ b/tests/mocks/fake_reference_card.json @@ -0,0 +1 @@ +mock_file('fake_card') \ No newline at end of file diff --git a/tests/mocks/fake_stakeholder.json b/tests/mocks/fake_stakeholder.json new file mode 100644 index 00000000..e5bb6cb8 --- /dev/null +++ b/tests/mocks/fake_stakeholder.json @@ -0,0 +1,29 @@ +{ + "entity": "stakeholder", + "relationship": { + "director": true + }, + "phone": { + "primary": "9000090000", + "secondary": "9000090000" + }, + "notes": { + "random_key_by_partner": "random_value" + }, + "kyc": { + "pan": "AVOPB1111K" + }, + "id": "sth_GLGgm8fFCKc92m", + "name": "Gaurav Kumar", + "email": "gaurav.kumar@example.com", + "percentage_ownership": 10, + "addresses": { + "residential": { + "street": "506, Koramangala 1st block", + "city": "Bengaluru", + "state": "Karnataka", + "postal_code": "560034", + "country": "IN" + } + } +} \ No newline at end of file diff --git a/tests/mocks/fake_webhook.json b/tests/mocks/fake_webhook.json new file mode 100644 index 00000000..49e09c78 --- /dev/null +++ b/tests/mocks/fake_webhook.json @@ -0,0 +1,22 @@ +{ + "id": "HK890egfiItP3H", + "created_at": 1623060358, + "updated_at": 1623060358, + "owner_id": "H3kYHQ635sBwXG", + "owner_type": "merchant", + "context": [], + "disabled_at": 0, + "url": "https://en1mwkqo5ioct.x.pipedream.net", + "alert_email": "gaurav.kumar@example.com", + "secret_exists": true, + "entity": "webhook", + "active": true, + "events": [ + "payment.authorized", + "payment.failed", + "payment.captured", + "payment.dispute.created", + "refund.failed", + "refund.created" + ] +} diff --git a/tests/mocks/init_account.json b/tests/mocks/init_account.json new file mode 100644 index 00000000..031b0533 --- /dev/null +++ b/tests/mocks/init_account.json @@ -0,0 +1,72 @@ +{ + "email": "gauriagain.kumar@example.org", + "phone": "9000090000", + "legal_business_name": "Acme Corp", + "business_type": "partnership", + "customer_facing_business_name": "Example", + "profile": { + "category": "healthcare", + "subcategory": "clinic", + "description": "Healthcare E-commerce platform", + "addresses": { + "operation": { + "street1": "507, Koramangala 6th block", + "street2": "Kormanagala", + "city": "Bengaluru", + "state": "Karnataka", + "postal_code": 560047, + "country": "IN" + }, + "registered": { + "street1": "507, Koramangala 1st block", + "street2": "MG Road", + "city": "Bengaluru", + "state": "Karnataka", + "postal_code": 560034, + "country": "IN" + } + }, + "business_model": "Online Clothing ( men, women, ethnic, modern ) fashion and lifestyle, accessories, t-shirt, shirt, track pant, shoes." + }, + "legal_info": { + "pan": "AAACL1234C", + "gst": "18AABCU9603R1ZM" + }, + "brand": { + "color": "FFFFFF" + }, + "notes": { + "internal_ref_id": "123123" + }, + "contact_name": "Gaurav Kumar", + "contact_info": { + "chargeback": { + "email": "cb@example.org" + }, + "refund": { + "email": "cb@example.org" + }, + "support": { + "email": "support@example.org", + "phone": "9999999998", + "policy_url": "https://www.google.com" + } + }, + "apps": { + "websites": [ + "https://www.example.org" + ], + "android": [ + { + "url": "playstore.example.org", + "name": "Example" + } + ], + "ios": [ + { + "url": "appstore.example.org", + "name": "Example" + } + ] + } +} diff --git a/tests/mocks/init_stakeholder.json b/tests/mocks/init_stakeholder.json new file mode 100644 index 00000000..6372c623 --- /dev/null +++ b/tests/mocks/init_stakeholder.json @@ -0,0 +1,28 @@ +{ + "percentage_ownership": 10, + "name": "Gaurav Kumar", + "email": "gaurav.kumar@example.com", + "relationship": { + "director": true, + "executive": false + }, + "phone": { + "primary": "9000090000", + "secondary": "9000090000" + }, + "addresses": { + "residential": { + "street": "506, Koramangala 1st block", + "city": "Bengaluru", + "state": "Karnataka", + "postal_code": "560034", + "country": "IN" + } + }, + "kyc": { + "pan": "AVOPB1111K" + }, + "notes": { + "random_key_by_partner": "random_value" + } +} diff --git a/tests/mocks/init_webhook.json b/tests/mocks/init_webhook.json new file mode 100644 index 00000000..89f32191 --- /dev/null +++ b/tests/mocks/init_webhook.json @@ -0,0 +1,13 @@ +{ + "url": "https://google.com", + "alert_email": "gaurav.kumar@example.com", + "secret": "12345", + "events": [ + "payment.authorized", + "payment.failed", + "payment.captured", + "payment.dispute.created", + "refund.failed", + "refund.created" + ] +} \ No newline at end of file diff --git a/tests/mocks/stakeholder_collection.json b/tests/mocks/stakeholder_collection.json new file mode 100644 index 00000000..9b793335 --- /dev/null +++ b/tests/mocks/stakeholder_collection.json @@ -0,0 +1,35 @@ +{ + "entity": "collection", + "items": [ + { + "id": "GZ13yPHLJof9IE", + "entity": "stakeholder", + "relationship": { + "director": true + }, + "phone": { + "primary": "9000090000", + "secondary": "9000090000" + }, + "notes": { + "random_key_by_partner": "random_value" + }, + "kyc": { + "pan": "AVOPB1111K" + }, + "name": "Gaurav Kumar", + "email": "gaurav.kumar@acme.org", + "percentage_ownership": 10, + "addresses": { + "residential": { + "street": "506, Koramangala 1st block", + "city": "Bengaluru", + "state": "Karnataka", + "postal_code": "560034", + "country": "in" + } + } + } + ], + "count": 1 +} diff --git a/tests/mocks/webhook_collection.json b/tests/mocks/webhook_collection.json new file mode 100644 index 00000000..5403aa8e --- /dev/null +++ b/tests/mocks/webhook_collection.json @@ -0,0 +1,29 @@ +{ + "entity": "collection", + "count": 1, + "items": [ + { + "id": "HK890egfiItP3H", + "created_at": 1624060358, + "updated_at": 1624060358, + "service": "beta-api-test", + "owner_id": "H3kYHQ635sBwXG", + "owner_type": "merchant", + "context": [], + "disabled_at": 0, + "url": "https://en1mwkqo5ioct.x.pipedream.net", + "alert_email": "gaurav.kumar@example.com", + "secret_exists": true, + "entity": "webhook", + "active": true, + "events": [ + "payment.authorized", + "payment.failed", + "payment.captured", + "payment.dispute.created", + "refund.failed", + "refund.created" + ] + } + ] +} diff --git a/tests/test_client_account.py b/tests/test_client_account.py new file mode 100644 index 00000000..60135dd5 --- /dev/null +++ b/tests/test_client_account.py @@ -0,0 +1,50 @@ +import responses +import json + +from .helpers import mock_file, ClientTestCase + + +class TestClientAccount(ClientTestCase): + + def setUp(self): + super(TestClientAccount, self).setUp() + self.base_url = '{}/accounts'.format(self.base_url_v2) + self.account_id = 'acc_GRWKk7qQsLnDjX' + + @responses.activate + def test_account_create(self): + init = mock_file('init_account') + result = mock_file('fake_account') + url = self.base_url + responses.add(responses.POST, + url, + status=200, + body=json.dumps(result), + match_querystring=True) + + self.assertEqual(self.client.account.create(init), result) + + @responses.activate + def test_account_fetch(self): + result = mock_file('fake_account') + url = '{}/{}'.format(self.base_url, self.account_id) + responses.add(responses.GET, url, status=200, body=json.dumps(result), + match_querystring=True) + self.assertEqual(self.client.account.fetch(self.account_id), result) + + @responses.activate + def test_account_edit(self): + init = { "customer_facing_business_name": "ABCD Ltd" } + result = mock_file('fake_account') + url = '{}/{}'.format(self.base_url, self.account_id) + responses.add(responses.PATCH, url, status=200, body=json.dumps(result), + match_querystring=True) + self.assertEqual(self.client.account.edit(self.account_id, init), result) + + @responses.activate + def test_account_delete(self): + result = mock_file('fake_account') + url = '{}/{}'.format(self.base_url, self.account_id) + responses.add(responses.DELETE, url, status=200, body=json.dumps(result), + match_querystring=True) + self.assertEqual(self.client.account.delete(self.account_id), result) \ No newline at end of file diff --git a/tests/test_client_card.py b/tests/test_client_card.py index cf2868e0..3cb72fd7 100644 --- a/tests/test_client_card.py +++ b/tests/test_client_card.py @@ -17,3 +17,18 @@ def test_card_fetch(self): responses.add(responses.GET, url, status=200, body=json.dumps(result), match_querystring=True) self.assertEqual(self.client.card.fetch(self.card_id), result) + + @responses.activate + def test_card_requestCardReference(self): + init = { + "number": "4854980604708430" + } + result = { + "network": "Visa", + "payment_account_reference": "V0010013819231376539033235990", + "network_reference_id": "1001381923137653903323591234sdfds90" + } + url = "{}/{}".format(self.base_url, "fingerprints") + responses.add(responses.POST, url, status=200, body=json.dumps(result), + match_querystring=True) + self.assertEqual(self.client.card.requestCardReference(init), result) diff --git a/tests/test_client_iin.py b/tests/test_client_iin.py new file mode 100644 index 00000000..80fe5dd7 --- /dev/null +++ b/tests/test_client_iin.py @@ -0,0 +1,20 @@ +import responses +import json + +from .helpers import mock_file, ClientTestCase + + +class TestClientIin(ClientTestCase): + + def setUp(self): + super(TestClientIin, self).setUp() + self.base_url = '{}/iins'.format(self.base_url) + self.token_iin = '412345' + + @responses.activate + def test_addon_fetch(self): + result = mock_file('fake_iin') + url = '{}/{}'.format(self.base_url, self.token_iin) + responses.add(responses.GET, url, status=200, body=json.dumps(result), + match_querystring=True) + self.assertEqual(self.client.iin.fetch(self.token_iin), result) diff --git a/tests/test_client_product.py b/tests/test_client_product.py new file mode 100644 index 00000000..baee0963 --- /dev/null +++ b/tests/test_client_product.py @@ -0,0 +1,98 @@ +import responses +import json + +from razorpay.constants.url import URL + +from .helpers import mock_file, ClientTestCase + + +class TestClientProduct(ClientTestCase): + + def setUp(self): + super(TestClientProduct, self).setUp() + self.base_url = '{}/accounts'.format(self.base_url_v2) + self.account_id = 'acc_GRWKk7qQsLnDjX' + self.product_id = 'acc_prd_HEgNpywUFctQ9e' + + @responses.activate + def test_product_requestProductConfiguration(self): + init = { + "product_name": "payment_gateway", + "tnc_accepted": True, + "ip": "233.233.233.234" + } + result = mock_file('fake_product') + url = '{}/{}{}'.format(self.base_url, self.account_id, URL.PRODUCT) + + responses.add(responses.POST, + url, + status=200, + body=json.dumps(result), + match_querystring=True) + + self.assertEqual(self.client.product.requestProductConfiguration( + self.account_id, init), result) + + @responses.activate + def test_product_fetch(self): + result = mock_file('fake_product') + url = '{}/{}{}/{}'.format(self.base_url, + self.account_id, URL.PRODUCT, self.product_id) + responses.add(responses.GET, url, status=200, body=json.dumps(result), + match_querystring=True) + self.assertEqual(self.client.product.fetch( + self.account_id, self.product_id), result) + + @responses.activate + def test_account_edit(self): + init = { + "notifications": { + "email": [ + "gaurav.kumar@example.com", + "acd@gmail.com" + ] + }, + "checkout": { + "theme_color": "#528FFF" + }, + "refund": { + "default_refund_speed": "optimum" + }, + "settlements": { + "account_number": "1234567890", + "ifsc_code": "HDFC0000317", + "beneficiary_name": "Gaurav Kumar" + }, + "tnc_accepted": True, + "ip": "233.233.233.234" + } + + result = mock_file('fake_account') + url = '{}/{}{}/{}'.format(self.base_url, + self.account_id, URL.PRODUCT, self.product_id) + + responses.add(responses.PATCH, url, status=200, body=json.dumps(result), + match_querystring=True) + self.assertEqual(self.client.product.edit( + self.account_id, self.product_id, init), result) + + @responses.activate + def test_product_fetchTnc(self): + result = { + "entity": "tnc_map", + "product_name": "payments", + "id": "tnc_map_HjOVhIdpVDZ0FB", + "tnc": { + "terms": "https://razorpay.com/terms", + "privacy": "https://razorpay.com/privacy", + "agreement": "https://razorpay.com/agreement" + }, + "last_published_at": 1640589653 + } + product_name = "payments" + + url = '{}{}/{}{}'.format(self.base_url_v2, URL.PRODUCT, product_name, URL.TNC ) + + responses.add(responses.GET, url, status=200, body=json.dumps(result), + match_querystring=True) + self.assertEqual(self.client.product.fetchTnc(product_name), result) diff --git a/tests/test_client_stakeholder.py b/tests/test_client_stakeholder.py new file mode 100644 index 00000000..6ed4aeef --- /dev/null +++ b/tests/test_client_stakeholder.py @@ -0,0 +1,85 @@ +import responses +import json + +from razorpay.constants.url import URL + +from .helpers import mock_file, ClientTestCase + + +class TestClientStakeholder(ClientTestCase): + + def setUp(self): + super(TestClientStakeholder, self).setUp() + self.base_url = '{}/accounts'.format(self.base_url_v2) + self.account_id = 'acc_GRWKk7qQsLnDjX' + self.stakeholder_id = 'sth_MDdinTcycAkdK3' + + @responses.activate + def test_stakeholder_create(self): + init = mock_file('init_stakeholder') + result = mock_file('fake_stakeholder') + url = '{}/{}{}'.format(self.base_url, self.account_id, URL.STAKEHOLDER) + responses.add(responses.POST, + url, + status=200, + body=json.dumps(result), + match_querystring=True) + + self.assertEqual(self.client.stakeholder.create( + self.account_id, init), result) + + @responses.activate + def test_stakeholder_fetch(self): + result = mock_file('fake_stakeholder') + url = '{}/{}{}/{}'.format(self.base_url, self.account_id, + URL.STAKEHOLDER, self.stakeholder_id) + responses.add(responses.GET, url, status=200, body=json.dumps(result), + match_querystring=True) + self.assertEqual(self.client.stakeholder.fetch( + self.account_id, self.stakeholder_id), result) + + @responses.activate + def test_stakeholder_edit(self): + init = { + "percentage_ownership": 20, + "name": "Gauri Kumar", + "relationship": { + "director": False, + "executive": True + }, + "phone": { + "primary": "9000090000", + "secondary": "9000090000" + }, + "addresses": { + "residential": { + "street": "507, Koramangala 1st block", + "city": "Bangalore", + "state": "Karnataka", + "postal_code": "560035", + "country": "IN" + } + }, + "kyc": { + "pan": "AVOPB1111J" + }, + "notes": { + "random_key_by_partner": "random_value2" + } + } + result = mock_file('fake_stakeholder') + url = '{}/{}{}/{}'.format(self.base_url, self.account_id, + URL.STAKEHOLDER, self.stakeholder_id) + responses.add(responses.PATCH, url, status=200, body=json.dumps(result), + match_querystring=True) + self.assertEqual(self.client.stakeholder.edit( + self.account_id, self.stakeholder_id, init), result) + + @responses.activate + def test_stakeholder_all(self): + result = mock_file('stakeholder_collection') + url = '{}/{}{}'.format(self.base_url, + self.account_id, URL.STAKEHOLDER) + responses.add(responses.GET, url, status=200, body=json.dumps(result), + match_querystring=True) + self.assertEqual(self.client.stakeholder.all(self.account_id), result) diff --git a/tests/test_client_token.py b/tests/test_client_token.py index c95efc38..6780278a 100644 --- a/tests/test_client_token.py +++ b/tests/test_client_token.py @@ -1,6 +1,8 @@ import responses import json +from razorpay.constants.url import URL + from .helpers import mock_file, ClientTestCase @@ -8,6 +10,7 @@ class TestClientCustomer(ClientTestCase): def setUp(self): super(TestClientCustomer, self).setUp() + self.url = self.base_url self.base_url = '{}/customers'.format(self.base_url) @responses.activate @@ -44,3 +47,59 @@ def test_token_delete(self): self.assertEqual( self.client.token.delete(self.customer_id, self.token_id), {'deleted': True}) + + @responses.activate + def test_token_create(self): + init = { + "customer_id": "cust_1Aa00000000001", + "method": "card", + "card": { + "number": "4111111111111111", + "cvv": "123", + "expiry_month": "12", + "expiry_year": "21", + "name": "Gaurav Kumar" + }, + "authentication": { + "provider": "razorpay", + "provider_reference_id": "pay_123wkejnsakd", + "authentication_reference_number": "100222021120200000000742753928" + }, + "notes": [] + } + result = mock_file('fake_merchant_token') + url = '{}{}'.format(self.url, URL.TOKEN) + responses.add(responses.POST, url, status=200, body=json.dumps(result), + match_querystring=True) + self.assertEqual(self.client.token.create(init), result) + + @responses.activate + def test_token_fetchToken(self): + init = { + "id": "token_4lsdksD31GaZ09" + } + result = mock_file('fake_merchant_token') + url = '{}{}/{}'.format(self.url, URL.TOKEN, "fetch") + responses.add(responses.POST, url, status=200, body=json.dumps(result)) + self.assertEqual( + self.client.token.fetchToken(init), + result) + + @responses.activate + def test_token_processPaymentOnAlternatePAorPG(self): + init = { + "id": "spt_4lsdksD31GaZ09" + } + result = { + "card": { + "number": "4111111111111111", + "expiry_month": "12", + "expiry_year": 2030 + } + } + + url = '{}{}/{}'.format(self.url, URL.TOKEN, "service_provider_tokens/token_transactional_data") + responses.add(responses.POST, url, status=200, body=json.dumps(result), match_querystring=True) + self.assertEqual( + self.client.token.processPaymentOnAlternatePAorPG(init), + result) diff --git a/tests/test_client_virtual_account.py b/tests/test_client_virtual_account.py index 8034c36c..61b4cede 100644 --- a/tests/test_client_virtual_account.py +++ b/tests/test_client_virtual_account.py @@ -1,3 +1,4 @@ +import unittest import responses import json from .helpers import mock_file, ClientTestCase @@ -149,9 +150,9 @@ def test_virtual_add_allowed_player(self): self.assertEqual(response['entity'], 'virtual_account') - @responses.activate + @unittest.skip def test_virtual_delete_allowed_player(self): - result = mock_file('fake_delete_allowed_payer') + result = None url = "{}/{}/allowed_payers/{}".format(self.base_url, self.fake_virtual_account_id, 'fake_allowed_player_id') responses.add(responses.DELETE, url, diff --git a/tests/test_client_webhook.py b/tests/test_client_webhook.py new file mode 100644 index 00000000..c7528ef7 --- /dev/null +++ b/tests/test_client_webhook.py @@ -0,0 +1,76 @@ +import responses +import json + +from razorpay.constants.url import URL + +from .helpers import mock_file, ClientTestCase + + +class TestClientWebhook(ClientTestCase): + + def setUp(self): + super(TestClientWebhook, self).setUp() + self.base_url = '{}{}'.format(self.base_url_v2, URL.ACCOUNT) + self.account_id = "acc_H3kYHQ635sBwXG" + self.webhookId = "HK890egfiItP3H" + + @responses.activate + def test_webhook_all(self): + result = mock_file('webhook_collection') + url = '{}/{}{}'.format(self.base_url, self.account_id, URL.WEBHOOK) + responses.add(responses.GET, url, status=200, body=json.dumps(result), + match_querystring=True) + self.assertEqual(self.client.webhook.all({},self.account_id), + result) + + @responses.activate + def test_webhook_fetch(self): + result = mock_file('fake_webhook') + url = '{}/{}{}/{}'.format(self.base_url, + self.account_id, URL.WEBHOOK, self.webhookId) + responses.add(responses.GET, url, status=200, body=json.dumps(result), + match_querystring=True) + self.assertEqual( + self.client.webhook.fetch(self.webhookId, self.account_id), + result) + + @responses.activate + def test_webhook_create(self): + init = mock_file('init_webhook') + result = mock_file('fake_webhook') + url = '{}/{}{}'.format(self.base_url, self.account_id, URL.WEBHOOK) + responses.add(responses.POST, + url, + status=200, + body=json.dumps(result), + match_querystring=True) + self.assertEqual( + self.client.webhook.create(init, self.account_id), + result) + + @responses.activate + def test_webhook_edit(self): + init = { + "url": "https://www.linkedin.com", + "events": [ + "refund.created" + ] + } + result = mock_file('fake_webhook') + url = '{}/{}{}/{}'.format(self.base_url, + self.account_id, URL.WEBHOOK, self.webhookId) + responses.add(responses.PATCH, url, status=200, body=json.dumps(result)) + self.assertEqual( + self.client.webhook.edit(self.webhookId, self.account_id, init), + result) + + @responses.activate + def test_webhook_delete(self): + + result = mock_file('fake_webhook') + url = '{}/{}{}/{}'.format(self.base_url, + self.account_id, URL.WEBHOOK, self.webhookId) + responses.add(responses.DELETE, url, status=200, body=json.dumps(result), match_querystring=True) + self.assertEqual( + self.client.webhook.delete(self.webhookId, self.account_id), + result) diff --git a/tests/test_multiple_client.py b/tests/test_multiple_client.py index 66fcffa4..ea229a30 100644 --- a/tests/test_multiple_client.py +++ b/tests/test_multiple_client.py @@ -1,3 +1,4 @@ +import unittest import responses import json @@ -19,7 +20,7 @@ def test_payment_primary_url(self): body=json.dumps(result), match_querystring=True) self.assertEqual(self.client.payment.all(), result) - @responses.activate + @unittest.skip def test_payment_secondary_url(self): result = mock_file('payment_collection') url = self.secondary_base_url