rma-payment-gateway 1.0.1 → 1.0.3

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 93083bc4a39780d2b7387e013edf0e71d01bcdd128582383c0805edf8173f461
4
- data.tar.gz: 1dbea3526aed562579e070a1cc99470be1ff94d76bce1c2f6fd8780c6b033bbf
3
+ metadata.gz: 7e2093f132f0620f9d9455eae15c1d2b4b2a7eb31fc4cfab608fe0244683c50b
4
+ data.tar.gz: e62e9cef18f17683d4eb208f56dc09ca8d3991fa7ce7471f73dc93672d6854b0
5
5
  SHA512:
6
- metadata.gz: f9f2d09bf865b4b4575fc18e54f990e98cd13f732c53a337a78ccbcc9ae8de7a94cdd9ac52a2b0a91a3191d803672bcd9d6e1fb4464cf883e3c3bd445c3d0f51
7
- data.tar.gz: 94d79e7619c070b68d7e29704d27bcc2e6bfca44dd745801e1be6b63ea8220e9bc24629eb4212971364d41268a2f1fb68d5b251f96ba435fef8c05e1c32b59de
6
+ metadata.gz: '0699e0a7456ca06ebac7a52e187b58aab1cab83ebf0cf835c10d78aa6d42891fba070094ade6ddc3d46b91d3780dd4a50783ae77fa8b83e250250a90bd3fb956'
7
+ data.tar.gz: '088a8cc8091ddbbde76bf65ea34ed473e6f51a4f4a64aedbb7d0b26801a70f20a21e5cc74c24c2091d4aad87bf297e4469a0cf231838435ef3c57d20463e6f42'
@@ -33,7 +33,7 @@ module Rma
33
33
 
34
34
  validate_account_inquiry_response!(response)
35
35
 
36
- response["result"]
36
+ response
37
37
  rescue StandardError => e
38
38
  raise AuthenticationError, "Failed to fetch account inquiry: #{e.message}"
39
39
  end
@@ -41,27 +41,20 @@ module Rma
41
41
  private
42
42
 
43
43
  def account_inquiry_request_body
44
- params = {
44
+ {
45
45
  bfs_bfsTxnId: transaction_id,
46
46
  bfs_remitterBankId: bank_id,
47
47
  bfs_remitterAccNo: account_no,
48
48
  bfs_benfId: client.config.beneficiary_id,
49
49
  bfs_msgType: "AE"
50
50
  }
51
-
52
- # Convert to URL-encoded format
53
- URI.encode_www_form(params)
54
51
  end
55
52
 
56
53
  def validate_account_inquiry_response!(response)
57
- unless response.is_a?(Hash) && response["result"]["bfs_responseCode"] == "00"
58
- error_detail = response["result"]["bfs_responseDesc"] || "Unknown error"
54
+ unless response.is_a?(Hash) && response["bfs_responseCode"] == "00"
55
+ error_detail = response["bfs_responseDesc"] || "Unknown error"
59
56
  raise AuthenticationError, "Account inquiry failed: #{error_detail}"
60
57
  end
61
-
62
- return if response["result"]
63
-
64
- raise AuthenticationError, "No response data in response"
65
58
  end
66
59
  end
67
60
  end
@@ -32,7 +32,7 @@ module Rma
32
32
 
33
33
  validate_authorization_response!(response)
34
34
 
35
- response["result"]
35
+ response
36
36
  rescue StandardError => e
37
37
  raise AuthenticationError, "Failed to authorize: #{e.message}"
38
38
  end
@@ -40,7 +40,7 @@ module Rma
40
40
  private
41
41
 
42
42
  def authorization_request_body
43
- params = {
43
+ {
44
44
  bfs_benfTxnTime: Utils.generate_timestamp,
45
45
  bfs_orderNo: order_no,
46
46
  bfs_benfBankCode: "01",
@@ -52,9 +52,6 @@ module Rma
52
52
  bfs_msgType: "AR",
53
53
  bfs_version: "5.0"
54
54
  }
55
-
56
- # Convert to URL-encoded format
57
- URI.encode_www_form(params)
58
55
  end
59
56
 
60
57
  def validate_authorization_request!
@@ -65,14 +62,10 @@ module Rma
65
62
  end
66
63
 
67
64
  def validate_authorization_response!(response)
68
- unless response.is_a?(Hash) && response["result"]["bfs_responseCode"] == "00"
69
- error_detail = response["result"]["bfs_responseDesc"] || "Unknown error"
65
+ unless response.is_a?(Hash) && response["bfs_responseCode"] == "00"
66
+ error_detail = response["bfs_responseDesc"] || "Unknown error"
70
67
  raise AuthenticationError, "Authorization failed: #{error_detail}"
71
68
  end
72
-
73
- return if response["result"]
74
-
75
- raise AuthenticationError, "No response data in response"
76
69
  end
77
70
  end
78
71
  end
@@ -2,6 +2,7 @@
2
2
 
3
3
  require "faraday"
4
4
  require "json"
5
+ require "openssl"
5
6
 
6
7
  module Rma
7
8
  module Payment
@@ -17,13 +18,17 @@ module Rma
17
18
  #
18
19
  # @param config [Rma::Payment::Gateway::Configuration] Configuration instance
19
20
  class Client
20
- attr_reader :config, :access_token, :private_key
21
+ attr_reader :config, :access_token
21
22
 
22
23
  def initialize(config = nil)
23
24
  @config = config || Rma::Payment::Gateway.configuration
24
25
  validate_configuration!
25
26
  end
26
27
 
28
+ def private_key
29
+ @private_key ||= load_private_key
30
+ end
31
+
27
32
  # Authorization methods
28
33
  def authorization
29
34
  @authorization ||= Authorization.new(self)
@@ -41,7 +46,8 @@ module Rma
41
46
 
42
47
  # HTTP request methods
43
48
  def post(body: {}, headers: {})
44
- request(:post, body: body, headers: headers)
49
+ signed = body.empty? ? body : body.merge(bfs_checkSum: compute_checksum(body))
50
+ request(:post, body: signed, headers: headers)
45
51
  end
46
52
 
47
53
  def get(headers: {})
@@ -50,6 +56,23 @@ module Rma
50
56
 
51
57
  private
52
58
 
59
+ def compute_checksum(params)
60
+ sorted_values = params.sort_by { |k, _| k }.to_h.values.join("|")
61
+ signature = private_key.sign(OpenSSL::Digest.new("SHA1"), sorted_values)
62
+ signature.unpack1("H*")&.upcase
63
+ end
64
+
65
+ def load_private_key
66
+ key_content = if !config.rsa_key_path.to_s.strip.empty?
67
+ File.read(config.rsa_key_path)
68
+ else
69
+ config.rsa_key
70
+ end
71
+ OpenSSL::PKey::RSA.new(key_content)
72
+ rescue OpenSSL::PKey::RSAError => e
73
+ raise ConfigurationError, "Invalid RSA key: #{e.message}"
74
+ end
75
+
53
76
  def validate_configuration!
54
77
  raise ConfigurationError, "Configuration is required" if config.nil?
55
78
  return if config.valid?
@@ -72,7 +95,7 @@ module Rma
72
95
  def connection
73
96
  @connection ||= Faraday.new(url: config.base_url) do |conn|
74
97
  conn.request :url_encoded
75
- conn.response :json, content_type: /\bjson$/
98
+ conn.response :json
76
99
  conn.adapter Faraday.default_adapter
77
100
  conn.options.timeout = config.timeout
78
101
  conn.options.open_timeout = config.open_timeout
@@ -87,7 +110,7 @@ module Rma
87
110
  def handle_response(response)
88
111
  case response.status
89
112
  when 200..299
90
- response.body
113
+ parse_body(response.body)
91
114
  when 400..499
92
115
  handle_client_error(response)
93
116
  when 500..599
@@ -98,25 +121,32 @@ module Rma
98
121
  end
99
122
 
100
123
  def handle_client_error(response)
101
- body = response.body || {}
102
- error_message = body["result"]["bfs_responseDesc"] || "Client error"
103
-
104
- raise InvalidParameterError.new(
105
- error_message,
106
- response_code: body["result"]["bfs_responseCode"],
107
- response_detail: body["result"]["bfs_responseDesc"]
108
- )
124
+ body = parse_body(response.body) || {}
125
+ error_message = body["bfs_responseDesc"] || "Client error"
126
+ raise InvalidParameterError, error_message
109
127
  end
110
128
 
111
129
  def handle_server_error(response)
112
- body = response.body || {}
113
- error_message = body["result"]["bfs_responseDesc"] || "Server error"
114
-
115
- raise APIError.new(
116
- error_message,
117
- response_code: body["result"]["bfs_responseCode"],
118
- response_description: body["result"]["bfs_responseDesc"]
119
- )
130
+ body = parse_body(response.body) || {}
131
+ error_message = body["bfs_responseDesc"] || "Server error"
132
+ raise APIError, error_message
133
+ end
134
+
135
+ def parse_body(body)
136
+ return body if body.is_a?(Hash)
137
+ return {} if body.nil? || body.empty?
138
+
139
+ begin
140
+ return JSON.parse(body)
141
+ rescue JSON::ParserError
142
+ # Not JSON, fall through to URL-encoded parsing
143
+ end
144
+
145
+ parse_url_encoded(body)
146
+ end
147
+
148
+ def parse_url_encoded(query_string)
149
+ Rack::Utils.parse_nested_query(query_string)
120
150
  end
121
151
  end
122
152
  end
@@ -30,7 +30,7 @@ module Rma
30
30
 
31
31
  validate_debit_request_response!(response)
32
32
 
33
- response["result"]
33
+ response
34
34
  rescue StandardError => e
35
35
  raise AuthenticationError, "Failed to fetch debit request: #{e.message}"
36
36
  end
@@ -38,26 +38,19 @@ module Rma
38
38
  private
39
39
 
40
40
  def debit_request_body
41
- params = {
41
+ {
42
42
  bfs_bfsTxnId: transaction_id,
43
43
  bfs_remitterOtp: otp,
44
44
  bfs_benfId: client.config.beneficiary_id,
45
45
  bfs_msgType: "DR"
46
46
  }
47
-
48
- # Convert to URL-encoded format
49
- URI.encode_www_form(params)
50
47
  end
51
48
 
52
49
  def validate_debit_request_response!(response)
53
- unless response.is_a?(Hash) && response["result"]["bfs_responseCode"] == "00"
54
- error_detail = response["result"]["bfs_responseDesc"] || "Unknown error"
50
+ unless response.is_a?(Hash) && response["bfs_responseCode"] == "00"
51
+ error_detail = response["bfs_responseDesc"] || "Unknown error"
55
52
  raise AuthenticationError, "Debit request failed: #{error_detail}"
56
53
  end
57
-
58
- return if response["result"]
59
-
60
- raise AuthenticationError, "No response data in response"
61
54
  end
62
55
  end
63
56
  end
@@ -21,7 +21,7 @@ module Rma
21
21
  return false if account_number.nil? || account_number.empty?
22
22
 
23
23
  # Account numbers should be numeric and between 8-15 digits
24
- account_number.to_s.match?(/^\d{8,15}$/)
24
+ account_number.to_s.match?(/^\d{8,40}$/)
25
25
  end
26
26
 
27
27
  # Validate phone number format (Bhutan)
@@ -49,7 +49,7 @@ module Rma
49
49
  def self.valid_amount?(amount)
50
50
  return false if amount.nil?
51
51
 
52
- amount.is_a?(Numeric) && amount >= 0
52
+ amount.is_a?(Numeric) && amount > 0
53
53
  end
54
54
 
55
55
  # Format amount to 2 decimal places
@@ -3,7 +3,7 @@
3
3
  module Rma
4
4
  module Payment
5
5
  module Gateway
6
- VERSION = "1.0.1"
6
+ VERSION = "1.0.3"
7
7
  end
8
8
  end
9
9
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rma-payment-gateway
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tashi Dendup