razorpay 3.2.2 → 3.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/.cursorignore +174 -0
  3. data/.github/workflows/ci.yml +8 -7
  4. data/CHANGELOG.md +16 -0
  5. data/README.md +2 -0
  6. data/documents/customer.md +242 -0
  7. data/documents/dispute.md +301 -0
  8. data/documents/documents.md +65 -0
  9. data/documents/order.md +71 -0
  10. data/documents/payment.md +253 -0
  11. data/documents/transfers.md +40 -0
  12. data/lib/razorpay/constants.rb +1 -1
  13. data/lib/razorpay/customer.rb +16 -0
  14. data/lib/razorpay/dispute.rb +26 -0
  15. data/lib/razorpay/document.rb +19 -0
  16. data/lib/razorpay/order.rb +8 -0
  17. data/lib/razorpay/payment.rb +4 -0
  18. data/lib/razorpay/transfer.rb +4 -0
  19. data/lib/razorpay/utility.rb +8 -3
  20. data/lib/razorpay.rb +2 -0
  21. data/test/fixtures/dispute_collection.json +67 -0
  22. data/test/fixtures/dispute_error.json +10 -0
  23. data/test/fixtures/document_error.json +10 -0
  24. data/test/fixtures/error_customer.json +10 -0
  25. data/test/fixtures/error_eligibility.json +10 -0
  26. data/test/fixtures/error_eligibility_check.json +10 -0
  27. data/test/fixtures/fake_bank_account.json +9 -0
  28. data/test/fixtures/fake_dispute.json +29 -0
  29. data/test/fixtures/fake_document.json +9 -0
  30. data/test/fixtures/fake_eligiblity.json +79 -0
  31. data/test/fixtures/fake_fulfillment.json +10 -0
  32. data/test/fixtures/fake_payment_expanded_details.json +38 -0
  33. data/test/fixtures/fake_payment_expanded_details_card.json +50 -0
  34. data/test/fixtures/fake_rto.json +15 -0
  35. data/test/fixtures/order_error.json +10 -0
  36. data/test/fixtures/payment_error.json +10 -0
  37. data/test/fixtures/reversals_collection.json +22 -0
  38. data/test/fixtures/transfer_error.json +10 -0
  39. data/test/razorpay/test_customer.rb +105 -0
  40. data/test/razorpay/test_dispute.rb +98 -0
  41. data/test/razorpay/test_document.rb +27 -0
  42. data/test/razorpay/test_order.rb +43 -1
  43. data/test/razorpay/test_payment.rb +23 -1
  44. data/test/razorpay/test_transfer.rb +17 -0
  45. data/test/razorpay/test_utility.rb +2 -2
  46. metadata +51 -6
@@ -775,6 +775,46 @@ Razorpay::Transfer.fetch(transferId).edit(para_attr)
775
775
 
776
776
  -------------------------------------------------------------------------------------------------------
777
777
 
778
+ ### Fetch Reversals for a Transfer
779
+ ```rb
780
+ transferId = "trf_JhemwjNekar9Za"
781
+ Razorpay::Transfer.reversals(transferId)
782
+ ```
783
+
784
+ **Parameters:**
785
+
786
+ | Name | Type | Description |
787
+ |---------------|-------------|---------------------------------------------|
788
+ | transferId* | string | The id of the transfer to be fetched |
789
+
790
+ **Response:**
791
+ ```json
792
+ {
793
+ "entity":"collection",
794
+ "count":1,
795
+ "items":[
796
+ {
797
+ "id":"rvrsl_Lt09xvyzskI7KZ",
798
+ "entity":"reversal",
799
+ "transfer_id":"trf_Lt048W7cgLdo1u",
800
+ "amount":50000,
801
+ "fee":0,
802
+ "tax":0,
803
+ "currency":"INR",
804
+ "notes":[
805
+
806
+ ],
807
+ "initiator_id":"Ghri4beeOuMTAb",
808
+ "customer_refund_id":null,
809
+ "utr":null,
810
+ "created_at":1684822489
811
+ }
812
+ ]
813
+ }
814
+ ```
815
+
816
+ -------------------------------------------------------------------------------------------------------
817
+
778
818
  **PN: * indicates mandatory fields**
779
819
  <br>
780
820
  <br>
@@ -2,7 +2,7 @@
2
2
  module Razorpay
3
3
  BASE_URI = 'https://api.razorpay.com'.freeze
4
4
  TEST_URL = 'https://api.razorpay.com/'.freeze
5
- VERSION = '3.2.2'.freeze
5
+ VERSION = '3.2.4'.freeze
6
6
  AUTH_URL = 'https://auth.razorpay.com'.freeze
7
7
  API_HOST = 'API'.freeze
8
8
  AUTH_HOST = 'AUTH'.freeze
@@ -38,5 +38,21 @@ module Razorpay
38
38
  def deleteToken(tokenId)
39
39
  self.class.request.delete "#{id}/tokens/#{tokenId}"
40
40
  end
41
+
42
+ def self.add_bank_account(id, options = {})
43
+ request.post "#{id}/bank_account", options
44
+ end
45
+
46
+ def self.delete_bank_account(id, bankAccountId)
47
+ request.delete "#{id}/bank_account/#{bankAccountId}"
48
+ end
49
+
50
+ def self.request_eligibility_check(options = {})
51
+ request.post "eligibility", options
52
+ end
53
+
54
+ def self.fetch_eligibility(eligibilityId)
55
+ request.get "eligibility/#{eligibilityId}"
56
+ end
41
57
  end
42
58
  end
@@ -0,0 +1,26 @@
1
+ require 'razorpay/request'
2
+ require 'razorpay/entity'
3
+
4
+ module Razorpay
5
+ class Dispute < Entity
6
+ def self.request
7
+ Razorpay::Request.new('disputes')
8
+ end
9
+
10
+ def self.fetch(id)
11
+ request.fetch id
12
+ end
13
+
14
+ def self.all(options = {})
15
+ request.all options
16
+ end
17
+
18
+ def self.accept(id, options={})
19
+ request.post "#{id}/accept", options
20
+ end
21
+
22
+ def self.contest(id, options)
23
+ request.patch "#{id}/contest", options
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,19 @@
1
+ require 'razorpay/request'
2
+ require 'razorpay/entity'
3
+
4
+ module Razorpay
5
+ # Document API allows you to create and fetch document on Razorpay
6
+ class Document < Entity
7
+ def self.request
8
+ Razorpay::Request.new('documents')
9
+ end
10
+
11
+ def self.create(options)
12
+ request.create options
13
+ end
14
+
15
+ def self.fetch(id)
16
+ request.fetch id
17
+ end
18
+ end
19
+ end
@@ -35,5 +35,13 @@ module Razorpay
35
35
  # Docs: https://razorpay.com/docs/api/payments/route/#fetch-transfer-for-an-order
36
36
  request.get "#{id}/?expand[]=transfers&status"
37
37
  end
38
+
39
+ def self.view_rto(id)
40
+ request.post "#{id}/rto_review"
41
+ end
42
+
43
+ def self.edit_fulfillment(id, options = {})
44
+ request.post "#{id}/fulfillment", options
45
+ end
38
46
  end
39
47
  end
@@ -112,5 +112,9 @@ module Razorpay
112
112
  def self.validate_vpa(data={})
113
113
  request.post "validate/vpa" , data
114
114
  end
115
+
116
+ def self.expand_details(id, options={})
117
+ request.get "#{id}", options
118
+ end
115
119
  end
116
120
  end
@@ -31,5 +31,9 @@ module Razorpay
31
31
  def self.fetch_settlements
32
32
  request.get "?expand[]=recipient_settlement"
33
33
  end
34
+
35
+ def self.reversals(id)
36
+ request.get "#{id}/reversals"
37
+ end
34
38
  end
35
39
  end
@@ -59,9 +59,13 @@ module Razorpay
59
59
  end
60
60
 
61
61
  def encrypt(data, secret)
62
- iv = secret[0, 12]
63
62
  key = secret[0, 16]
64
63
 
64
+ # Generate a fresh random 12-byte nonce per call (fixes AES-GCM nonce reuse).
65
+ # A static IV derived from the secret allows keystream recovery and tag forgery
66
+ # (NIST SP 800-38D §8.3 Forbidden Attack) using only two captured ciphertexts.
67
+ iv = OpenSSL::Random.random_bytes(12)
68
+
65
69
  cipher = OpenSSL::Cipher.new('aes-128-gcm')
66
70
  cipher.encrypt
67
71
  cipher.key = key
@@ -72,9 +76,10 @@ module Razorpay
72
76
  encrypted = cipher.update(data) + cipher.final
73
77
 
74
78
  tag = cipher.auth_tag
75
- combined_encrypted_data = encrypted + tag
76
79
 
77
- encrypted_data_hex = combined_encrypted_data.unpack1("H*")
80
+ # Output format: iv (12 bytes) || ciphertext || tag (16 bytes), hex-encoded.
81
+ # Receiver must read the first 24 hex chars as the IV before decrypting.
82
+ (iv + encrypted + tag).unpack1("H*")
78
83
  end
79
84
  end
80
85
  end
data/lib/razorpay.rb CHANGED
@@ -26,6 +26,8 @@ require 'razorpay/token'
26
26
  require 'razorpay/product'
27
27
  require 'razorpay/stakeholder'
28
28
  require 'razorpay/account'
29
+ require 'razorpay/document'
30
+ require 'razorpay/dispute'
29
31
  require 'razorpay/oauth_token'
30
32
 
31
33
  # Base Razorpay module
@@ -0,0 +1,67 @@
1
+ {
2
+ "entity": "collection",
3
+ "count": 2,
4
+ "items": [
5
+ {
6
+ "id": "disp_Esz7KAitoYM7PJ",
7
+ "entity": "dispute",
8
+ "payment_id": "pay_EsyWjHrfzb59eR",
9
+ "amount": 10000,
10
+ "currency": "INR",
11
+ "amount_deducted": 0,
12
+ "reason_code": "pre_arbitration",
13
+ "respond_by": 1590604200,
14
+ "status": "open",
15
+ "phase": "pre_arbitration",
16
+ "created_at": 1590059211,
17
+ "evidence": {
18
+ "amount": 10000,
19
+ "summary": null,
20
+ "shipping_proof": null,
21
+ "billing_proof": null,
22
+ "cancellation_proof": null,
23
+ "customer_communication": null,
24
+ "proof_of_service": null,
25
+ "explanation_letter": null,
26
+ "refund_confirmation": null,
27
+ "access_activity_log": null,
28
+ "refund_cancellation_policy": null,
29
+ "term_and_conditions": null,
30
+ "others": null,
31
+ "submitted_at": null
32
+ }
33
+ },
34
+ {
35
+ "id": "disp_Esyvk3kZj0isXk",
36
+ "entity": "dispute",
37
+ "payment_id": "pay_EsyWjHrfzb59eR",
38
+ "amount": 5000,
39
+ "currency": "INR",
40
+ "amount_deducted": 0,
41
+ "reason_code": "warning_bulletin_or_exception_file",
42
+ "respond_by": 1590604200,
43
+ "status": "won",
44
+ "phase": "chargeback",
45
+ "created_at": 1590058554,
46
+ "evidence": {
47
+ "amount": 5000,
48
+ "summary": null,
49
+ "shipping_proof": [
50
+ "doc_EFtmUsbwpXwBH9",
51
+ "doc_EFtmUsbwpXwBH8"
52
+ ],
53
+ "billing_proof": null,
54
+ "cancellation_proof": null,
55
+ "customer_communication": null,
56
+ "proof_of_service": null,
57
+ "explanation_letter": null,
58
+ "refund_confirmation": null,
59
+ "access_activity_log": null,
60
+ "refund_cancellation_policy": null,
61
+ "term_and_conditions": null,
62
+ "others": null,
63
+ "submitted_at": 1590604100
64
+ }
65
+ }
66
+ ]
67
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "error": {
3
+ "code": "BAD_REQUEST_ERROR",
4
+ "description": "The id provided does not exist",
5
+ "source": "business",
6
+ "step": "payment_initiation",
7
+ "reason": "input_validation_failed",
8
+ "metadata": {}
9
+ }
10
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "error": {
3
+ "code": "BAD_REQUEST_ERROR",
4
+ "description": "Invalid file id provided or merchant is unauthorized to access the fileId(s) provided",
5
+ "source": "NA",
6
+ "step": "NA",
7
+ "reason": "NA",
8
+ "metadata": {}
9
+ }
10
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "error": {
3
+ "code": "BAD_REQUEST_ERROR",
4
+ "description": "The id provided does not exist",
5
+ "source": "business",
6
+ "step": "payment_initiation",
7
+ "reason": "input_validation_failed",
8
+ "metadata": {}
9
+ }
10
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "error": {
3
+ "code": "BAD_REQUEST_ERROR",
4
+ "description": "The eligibility id does not exist.",
5
+ "source": "NA",
6
+ "step": "NA",
7
+ "reason": "NA",
8
+ "metadata": {}
9
+ }
10
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "error": {
3
+ "code": "BAD_REQUEST_ERROR",
4
+ "description": "Amount is required.",
5
+ "source": "NA",
6
+ "step": "NA",
7
+ "reason": "NA",
8
+ "metadata": {}
9
+ }
10
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "id": "ba_LSZht1Cm7xFTwF",
3
+ "entity": "bank_account",
4
+ "ifsc": "ICIC0001207",
5
+ "bank_name": "ICICI Bank",
6
+ "name": "Gaurav Kumar",
7
+ "notes": [],
8
+ "account_number": "XXXXXXXXXXXXXXX0434"
9
+ }
@@ -0,0 +1,29 @@
1
+ {
2
+ "id": "disp_XXXXXXXXXXXXX",
3
+ "entity": "dispute",
4
+ "payment_id": "pay_EsyWjHrfzb59eR",
5
+ "amount": 10000,
6
+ "currency": "INR",
7
+ "amount_deducted": 0,
8
+ "reason_code": "pre_arbitration",
9
+ "respond_by": 1590604200,
10
+ "status": "open",
11
+ "phase": "pre_arbitration",
12
+ "created_at": 1590059211,
13
+ "evidence": {
14
+ "amount": 10000,
15
+ "summary": "goods delivered",
16
+ "shipping_proof": null,
17
+ "billing_proof": null,
18
+ "cancellation_proof": null,
19
+ "customer_communication": null,
20
+ "proof_of_service": null,
21
+ "explanation_letter": null,
22
+ "refund_confirmation": null,
23
+ "access_activity_log": null,
24
+ "refund_cancellation_policy": null,
25
+ "term_and_conditions": null,
26
+ "others": null,
27
+ "submitted_at": null
28
+ }
29
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "entity": "document",
3
+ "id": "doc_O4KANwWi2kHGiV",
4
+ "purpose": "dispute_evidence",
5
+ "created_at": 1714368859,
6
+ "mime_type": "image/jpeg",
7
+ "display_name": "Screenshot 2022-09-12 at 5.48.23 PM",
8
+ "size": 334201
9
+ }
@@ -0,0 +1,79 @@
1
+ {
2
+ "amount": "500000",
3
+ "customer": {
4
+ "id": "KkBhM9EC1Y0HTm",
5
+ "contact": "+918220722114"
6
+ },
7
+ "instruments": [
8
+ {
9
+ "method": "emi",
10
+ "issuer": "HDFC",
11
+ "type": "debit",
12
+ "eligibility_req_id": "elig_KkCNLzlNeMYQyZ",
13
+ "eligibility": {
14
+ "status": "eligible"
15
+ }
16
+ },
17
+ {
18
+ "method": "paylater",
19
+ "provider": "getsimpl",
20
+ "eligibility_req_id": "elig_KkCNLzlNeMYQyZ",
21
+ "eligibility": {
22
+ "status": "eligible"
23
+ }
24
+ },
25
+ {
26
+ "method": "paylater",
27
+ "provider": "icic",
28
+ "eligibility_req_id": "elig_KkCNLzlNeMYQyZ",
29
+ "eligibility": {
30
+ "status": "eligible"
31
+ }
32
+ },
33
+ {
34
+ "method": "cardless_emi",
35
+ "provider": "walnut369",
36
+ "eligibility_req_id": "elig_KkCNLzlNeMYQyZ",
37
+ "eligibility": {
38
+ "status": "ineligible",
39
+ "error": {
40
+ "code": "GATEWAY_ERROR",
41
+ "description": "The customer has not been approved by the partner.",
42
+ "source": "business",
43
+ "step": "inquiry",
44
+ "reason": "user_not_approved"
45
+ }
46
+ }
47
+ },
48
+ {
49
+ "method": "cardless_emi",
50
+ "provider": "zestmoney",
51
+ "eligibility_req_id": "elig_KkCNLzlNeMYQyZ",
52
+ "eligibility": {
53
+ "status": "ineligible",
54
+ "error": {
55
+ "code": "GATEWAY_ERROR",
56
+ "description": "The customer has exhausted their credit limit.",
57
+ "source": "business",
58
+ "step": "inquiry",
59
+ "reason": "credit_limit_exhausted"
60
+ }
61
+ }
62
+ },
63
+ {
64
+ "method": "paylater",
65
+ "provider": "lazypay",
66
+ "eligibility_req_id": "elig_KkCNLzlNeMYQyZ",
67
+ "eligibility": {
68
+ "status": "ineligible",
69
+ "error": {
70
+ "code": "GATEWAY_ERROR",
71
+ "description": "The order amount is less than the minimum transaction amount.",
72
+ "source": "business",
73
+ "step": "inquiry",
74
+ "reason": "min_amt_required"
75
+ }
76
+ }
77
+ }
78
+ ]
79
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "entity": "order.fulfillment",
3
+ "order_id": "EKwxwAgItXXXX",
4
+ "payment_method": "upi",
5
+ "shipping": {
6
+ "waybill": "123456789",
7
+ "status": "rto",
8
+ "provider": "Bluedart"
9
+ }
10
+ }
@@ -0,0 +1,38 @@
1
+ {
2
+ "id": "fake_payment_id",
3
+ "entity": "payment",
4
+ "amount": 200000,
5
+ "currency": "INR",
6
+ "status": "authorized",
7
+ "order_id": null,
8
+ "invoice_id": null,
9
+ "international": false,
10
+ "method": "emi",
11
+ "amount_refunded": 0,
12
+ "refund_status": null,
13
+ "captured": false,
14
+ "description": null,
15
+ "card_id": "card_DG4ZdUO3xABb20",
16
+ "bank": "ICIC",
17
+ "wallet": null,
18
+ "vpa": null,
19
+ "email": "gaurav@example.com",
20
+ "contact": "+919972000005",
21
+ "notes": [],
22
+ "fee": null,
23
+ "tax": null,
24
+ "error_code": null,
25
+ "error_description": null,
26
+ "error_source": null,
27
+ "error_step": null,
28
+ "error_reason": null,
29
+ "emi": {
30
+ "issuer": "ICIC",
31
+ "rate": 1300,
32
+ "duration": 6
33
+ },
34
+ "acquirer_data": {
35
+ "auth_code": "828553"
36
+ },
37
+ "created_at": 1568026077
38
+ }
@@ -0,0 +1,50 @@
1
+ {
2
+ "id": "fake_payment_id",
3
+ "entity": "payment",
4
+ "amount": 100,
5
+ "currency": "INR",
6
+ "status": "failed",
7
+ "order_id": "order_H9o58N6qmLYQKC",
8
+ "invoice_id": null,
9
+ "terminal_id": "term_G5kJnYM9GhhLYT",
10
+ "international": false,
11
+ "method": "card",
12
+ "amount_refunded": 0,
13
+ "refund_status": null,
14
+ "captured": false,
15
+ "description": null,
16
+ "card_id": "card_H9oR0ocen1cmZq",
17
+ "card": {
18
+ "id": "card_H9oR0ocen1cmZq",
19
+ "entity": "card",
20
+ "name": "Gaurav",
21
+ "last4": "1213",
22
+ "network": "RuPay",
23
+ "type": "credit",
24
+ "issuer": "UTIB",
25
+ "international": false,
26
+ "emi": false,
27
+ "sub_type": "business"
28
+ },
29
+ "bank": null,
30
+ "wallet": null,
31
+ "vpa": null,
32
+ "email": "gaurav.kumar@example.com",
33
+ "contact": "+919000090000",
34
+ "notes": {
35
+ "email": "gaurav.kumar@example.com",
36
+ "phone": "09000090000"
37
+ },
38
+ "fee": null,
39
+ "tax": null,
40
+ "error_code": "BAD_REQUEST_ERROR",
41
+ "error_description": "Card issuer is invalid",
42
+ "error_source": "customer",
43
+ "error_step": "payment_authentication",
44
+ "error_reason": "incorrect_card_details",
45
+ "acquirer_data": {
46
+ "auth_code": null,
47
+ "authentication_reference_number": "100222021120200000000742753928"
48
+ },
49
+ "created_at": 1620807547
50
+ }
@@ -0,0 +1,15 @@
1
+ {
2
+ "risk_tier": "high",
3
+ "rto_reasons": [
4
+ {
5
+ "reason": "short_shipping_address",
6
+ "description": "Short shipping address",
7
+ "bucket": "address"
8
+ },
9
+ {
10
+ "reason": "address_pincode_state_mismatch",
11
+ "description": "Incorrect pincode state entered",
12
+ "bucket": "address"
13
+ }
14
+ ]
15
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "error": {
3
+ "code": "BAD_REQUEST_ERROR",
4
+ "description": "The id provided does not exist",
5
+ "source": "business",
6
+ "step": "payment_initiation",
7
+ "reason": "input_validation_failed",
8
+ "metadata": {}
9
+ }
10
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "error": {
3
+ "code": "BAD_REQUEST_ERROR",
4
+ "description": "The id provided does not exist",
5
+ "source": "business",
6
+ "step": "payment_initiation",
7
+ "reason": "input_validation_failed",
8
+ "metadata": {}
9
+ }
10
+ }
@@ -0,0 +1,22 @@
1
+ {
2
+ "entity":"collection",
3
+ "count":1,
4
+ "items":[
5
+ {
6
+ "id":"rvrsl_Lt09xvyzskI7KZ",
7
+ "entity":"reversal",
8
+ "transfer_id":"trf_Lt048W7cgLdo1u",
9
+ "amount":50000,
10
+ "fee":0,
11
+ "tax":0,
12
+ "currency":"INR",
13
+ "notes":[
14
+
15
+ ],
16
+ "initiator_id":"Ghri4beeOuMTAb",
17
+ "customer_refund_id":null,
18
+ "utr":null,
19
+ "created_at":1684822489
20
+ }
21
+ ]
22
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "error": {
3
+ "code": "BAD_REQUEST_ERROR",
4
+ "description": "The id provided does not exist",
5
+ "source": "business",
6
+ "step": "payment_initiation",
7
+ "reason": "input_validation_failed",
8
+ "metadata": {}
9
+ }
10
+ }