fawry 1.0.0 → 1.3.1

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile CHANGED
@@ -2,10 +2,17 @@
2
2
 
3
3
  require 'bundler/gem_tasks'
4
4
  require 'rspec/core/rake_task'
5
+ require 'rubocop/rake_task'
5
6
 
6
7
  RSpec::Core::RakeTask.new(:spec)
8
+ RuboCop::RakeTask.new(:rubocop)
7
9
 
8
- task default: :spec
10
+ task default: :rspec_rubocop
11
+
12
+ task :rspec_rubocop do
13
+ Rake::Task['rubocop'].invoke
14
+ Rake::Task['spec'].invoke
15
+ end
9
16
 
10
17
  desc 'Start a console session with Fawry gem loaded'
11
18
  task :console do
data/fawry.gemspec CHANGED
@@ -7,14 +7,14 @@ require 'fawry/version'
7
7
  Gem::Specification.new do |spec|
8
8
  spec.name = 'fawry'
9
9
  spec.version = Fawry::VERSION
10
- spec.authors = ['Amr Bakry']
11
- spec.email = ['amrrbakry17@gmail.com']
10
+ spec.authors = ['Amr El Bakry']
11
+ spec.email = ['amrr@hey.com']
12
12
 
13
13
  spec.summary = "A library to interface with Fawry's payment gateway API (charge, refund, payment status,
14
14
  service callback)."
15
15
  spec.homepage = 'https://github.com/amrrbakry/fawry'
16
16
  spec.license = 'MIT'
17
- spec.required_ruby_version = '~> 2.6'
17
+ spec.required_ruby_version = '>= 2.6'
18
18
 
19
19
  spec.metadata['homepage_uri'] = 'https://github.com/amrrbakry/fawry'
20
20
  spec.metadata['source_code_uri'] = 'https://github.com/amrrbakry/fawry'
@@ -32,10 +32,10 @@ Gem::Specification.new do |spec|
32
32
  spec.add_dependency 'faraday', '~> 0.17.0'
33
33
 
34
34
  spec.add_development_dependency 'bundler', '~> 2.0'
35
- spec.add_development_dependency 'byebug', '~> 11.0', '>= 11.0.1'
36
- spec.add_development_dependency 'rake', '~> 10.0'
35
+ spec.add_development_dependency 'byebug', '~> 11.0'
36
+ spec.add_development_dependency 'rake', '~> 13.0'
37
37
  spec.add_development_dependency 'rspec', '~> 3.0'
38
38
  spec.add_development_dependency 'rspec_junit_formatter'
39
- spec.add_development_dependency 'rubocop', '~> 0.76.0'
40
- spec.add_development_dependency 'webmock', '~> 3.7', '>= 3.7.6'
39
+ spec.add_development_dependency 'rubocop', '~> 1.11'
40
+ spec.add_development_dependency 'webmock', '~> 3.12'
41
41
  end
data/lib/fawry.rb CHANGED
@@ -1,20 +1,33 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'fawry/version'
4
+ require 'fawry/utils'
4
5
  require 'fawry/connection'
6
+ require 'fawry/config'
5
7
  require 'fawry/errors'
6
- require 'fawry/utils'
7
8
  require 'fawry/fawry_request'
8
9
  require 'fawry/fawry_response'
9
10
  require 'fawry/fawry_callback'
10
11
  require 'fawry/requests/charge_request'
11
12
  require 'fawry/requests/refund_request'
12
13
  require 'fawry/requests/payment_status_request'
14
+ require 'fawry/requests/create_card_token_request'
15
+ require 'fawry/requests/list_tokens_request'
16
+ require 'fawry/requests/delete_token_request'
13
17
  require 'fawry/contracts/charge_request_contract'
14
18
  require 'fawry/contracts/refund_request_contract'
15
19
  require 'fawry/contracts/payment_status_request_contract'
20
+ require 'fawry/contracts/create_card_token_request_contract'
21
+ require 'fawry/contracts/list_tokens_request_contract'
22
+ require 'fawry/contracts/delete_token_request_contract'
16
23
 
17
24
  module Fawry
25
+ configure do |config|
26
+ config.sandbox = false
27
+ config.fawry_secure_key = nil
28
+ config.fawry_merchant_code = nil
29
+ end
30
+
18
31
  class << self
19
32
  # Sends a charge request to Fawry API
20
33
  # performs param validation and builds
@@ -112,6 +125,92 @@ module Fawry
112
125
  FawryRequest.new('payment_status', params, opts).fire_payment_status_request
113
126
  end
114
127
 
128
+ # Sends a card token request to Fawry API
129
+ # performs param validation and builds
130
+ # the request signature
131
+ #
132
+ # @param params [Hash] list of params to send to fawry
133
+ # required(:customer_profile_id).value(:string)
134
+ # required(:customer_mobile).value(:string)
135
+ # required(:merchant_code).value(:string)
136
+ # required(:customer_email).value(:string)
137
+ # required(:card_number).value(:string)
138
+ # required(:expiry_year).value(:string)
139
+ # required(:expiry_month).value(:string)
140
+ # required(:cvv).value(:string)
141
+ #
142
+ # @param opts [Hash] list of options to
143
+ # configure the request
144
+ # @option opts :sandbox [Boolean] whether to
145
+ # send the request to fawry sandbox env or not
146
+ # false by default
147
+ #
148
+ # @raise [Fawry::InvalidFawryRequestError] raised when one
149
+ # or more of the params are invalid. the message
150
+ # specifices which params and why are they invalid
151
+ #
152
+ # @return [Fawry::FawryResponse] an object that
153
+ # has Fawry API response keys as instance methods
154
+ # plus some convenience methods e.g. success?
155
+
156
+ def create_card_token(params, opts = {})
157
+ FawryRequest.new('create_card_token', params, opts).fire_create_card_token_request
158
+ end
159
+
160
+ # Sends a list tokens request to Fawry API
161
+ # performs param validation and builds
162
+ # the request signature
163
+ #
164
+ # @param params [Hash] list of params to send to fawry
165
+ # required(:merchant_code).value(:string)
166
+ # required(:customer_profile_id).value(:string)
167
+ # optional(:fawry_secure_key).value(:string)
168
+ #
169
+ # @param opts [Hash] list of options to
170
+ # configure the request
171
+ # @option opts :sandbox [Boolean] whether to
172
+ # send the request to fawry sandbox env or not
173
+ # false by default
174
+ #
175
+ # @raise [Fawry::InvalidFawryRequestError] raised when one
176
+ # or more of the params are invalid. the message
177
+ # specifices which params and why are they invalid
178
+ #
179
+ # @return [Fawry::FawryResponse] an object that
180
+ # has Fawry API response keys as instance methods
181
+ # plus some convenience methods e.g. success?
182
+
183
+ def list_tokens(params, opts = {})
184
+ FawryRequest.new('list_tokens', params, opts).fire_list_tokens_request
185
+ end
186
+
187
+ # Sends delete token request to Fawry API
188
+ # performs param validation and builds
189
+ # the request signature
190
+ #
191
+ # @param params [Hash] list of params to send to fawry
192
+ # required(:customer_profile_id).value(:string)
193
+ # optional(:merchant_code).value(:string)
194
+ # optional(:fawry_secure_key).value(:string)
195
+ #
196
+ # @param opts [Hash] list of options to
197
+ # configure the request
198
+ # @option opts :sandbox [Boolean] whether to
199
+ # send the request to fawry sandbox env or not
200
+ # false by default
201
+ #
202
+ # @raise [Fawry::InvalidFawryRequestError] raised when one
203
+ # or more of the params are invalid. the message
204
+ # specifices which params and why are they invalid
205
+ #
206
+ # @return [Fawry::FawryResponse] an object that
207
+ # has Fawry API response keys as instance methods
208
+ # plus some convenience methods e.g. success?
209
+
210
+ def delete_token(params, opts = {})
211
+ FawryRequest.new('delete_token', params, opts).fire_delete_token_request
212
+ end
213
+
115
214
  # Parses Fawry callback v2 into
116
215
  # FawryCallback object with callback
117
216
  # params as instance methods
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Fawry
4
+ class << self
5
+ attr_accessor :configuration
6
+
7
+ def configure
8
+ self.configuration ||= Configuration.new
9
+
10
+ yield(configuration)
11
+ end
12
+ end
13
+
14
+ class Configuration
15
+ attr_accessor :sandbox, :fawry_secure_key, :fawry_merchant_code
16
+ end
17
+ end
@@ -5,13 +5,16 @@ require 'json'
5
5
 
6
6
  module Fawry
7
7
  class Connection
8
- FAWRY_BASE_URL = 'https://www.atfawry.com/ECommerceWeb/Fawry/payments/'
8
+ FAWRY_BASE_URL = 'https://www.atfawry.com/ECommerceWeb/Fawry/'
9
9
 
10
- FAWRY_SANDBOX_BASE_URL = 'https://atfawry.fawrystaging.com//ECommerceWeb/Fawry/payments/'
10
+ FAWRY_SANDBOX_BASE_URL = 'https://atfawry.fawrystaging.com//ECommerceWeb/Fawry/'
11
11
 
12
12
  class << self
13
+ include Utils
14
+
13
15
  def post(path, params, body, options)
14
- conn = options[:sandbox] ? sandbox_connection : connection
16
+ sandbox = Fawry.configuration.sandbox || TRUTH_VALUES.include?(ENV.fetch('FAWRY_SANDBOX', options[:sandbox]))
17
+ conn = sandbox ? sandbox_connection : connection
15
18
 
16
19
  conn.post(path) do |request|
17
20
  request.params = params
@@ -20,7 +23,8 @@ module Fawry
20
23
  end
21
24
 
22
25
  def get(path, params, body, options)
23
- conn = options[:sandbox] ? sandbox_connection : connection
26
+ sandbox = Fawry.configuration.sandbox || TRUTH_VALUES.include?(ENV.fetch('FAWRY_SANDBOX', options[:sandbox]))
27
+ conn = sandbox ? sandbox_connection : connection
24
28
 
25
29
  conn.get(path) do |request|
26
30
  request.params = params
@@ -30,16 +34,28 @@ module Fawry
30
34
  end
31
35
  end
32
36
 
37
+ def delete(path, params, body, options)
38
+ sandbox = Fawry.configuration.sandbox || TRUTH_VALUES.include?(ENV.fetch('FAWRY_SANDBOX', options[:sandbox]))
39
+ conn = sandbox ? sandbox_connection : connection
40
+
41
+ conn.delete(path) do |request|
42
+ request.params = params
43
+ request.body = body.to_json
44
+ # Fawry doesn't understand encoded params
45
+ request.options = request.options.merge(params_encoder: ParamsSpecialEncoder)
46
+ end
47
+ end
48
+
33
49
  private
34
50
 
35
51
  def connection
36
52
  @connection ||= Faraday.new(url: FAWRY_BASE_URL, headers: { 'Content-Type': 'application/json',
37
- 'Accept': 'application/json' })
53
+ Accept: 'application/json' })
38
54
  end
39
55
 
40
56
  def sandbox_connection
41
57
  @sandbox_connection ||= Faraday.new(url: FAWRY_SANDBOX_BASE_URL, headers: { 'Content-Type': 'application/json',
42
- 'Accept': 'application/json' })
58
+ Accept: 'application/json' })
43
59
  end
44
60
 
45
61
  # Fawry does not understand encoded params
@@ -17,6 +17,7 @@ module Fawry
17
17
  required(:price).value(:decimal)
18
18
  required(:quantity).value(:integer)
19
19
  end
20
+ optional(:language).value(included_in?: %w[ar-eg en-gb])
20
21
  optional(:merchant_code).value(:string)
21
22
  optional(:fawry_secure_key).value(:string)
22
23
  optional(:currency_code).value(:string)
@@ -39,14 +40,16 @@ module Fawry
39
40
  end
40
41
 
41
42
  rule(:fawry_secure_key) do
42
- if ENV['FAWRY_SECURE_KEY'].nil? && value.nil?
43
- key(:fawry_secure_key).failure('fawry secure key is required as a param or an env var')
43
+ if Fawry.configuration.fawry_secure_key.nil? && ENV['FAWRY_SECURE_KEY'].nil? && value.nil?
44
+ key(:fawry_secure_key).failure('fawry secure key is required in either Fawry.configuration or'\
45
+ 'as an environment variable (FAWRY_SECURE_KEY), or as an argument to this method')
44
46
  end
45
47
  end
46
48
 
47
49
  rule(:merchant_code) do
48
- if ENV['FAWRY_MERCHANT_CODE'].nil? && value.nil?
49
- key(:merchant_code).failure('fawry merchant code is required as a param or an env var')
50
+ if Fawry.configuration.fawry_merchant_code.nil? && ENV['FAWRY_MERCHANT_CODE'].nil? && value.nil?
51
+ key(:merchant_code).failure('fawry merchant code is required in either Fawry.configuration or'\
52
+ 'as an environment variable (FAWRY_MERCHANT_CODE), or as an argument to this method')
50
53
  end
51
54
  end
52
55
  end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'dry-validation'
4
+
5
+ module Fawry
6
+ module Contracts
7
+ class CreateCardTokenRequestContract < Dry::Validation::Contract
8
+ params do
9
+ required(:customer_profile_id).value(:string)
10
+ required(:customer_mobile).value(:string)
11
+ required(:merchant_code).value(:string)
12
+ required(:customer_email).value(:string)
13
+ required(:card_number).value(:string)
14
+ required(:expiry_year).value(:string)
15
+ required(:expiry_month).value(:string)
16
+ required(:cvv).value(:string)
17
+ end
18
+
19
+ rule(:customer_email) do
20
+ unless /\A[\w+\-.]+@[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i.match?(value)
21
+ key? && key.failure('has invalid format')
22
+ end
23
+ end
24
+
25
+ rule(:merchant_code) do
26
+ if Fawry.configuration.fawry_merchant_code.nil? && ENV['FAWRY_MERCHANT_CODE'].nil? && value.nil?
27
+ key(:merchant_code).failure('fawry merchant code is required in either Fawry.configuration or'\
28
+ 'as an environment variable (FAWRY_MERCHANT_CODE), or as an argument to this method')
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'dry-validation'
4
+
5
+ module Fawry
6
+ module Contracts
7
+ class DeleteTokenRequestContract < Dry::Validation::Contract
8
+ params do
9
+ required(:merchant_code).value(:string)
10
+ required(:customer_profile_id).value(:string)
11
+ required(:fawry_secure_key).value(:string)
12
+ required(:card_token).value(:string)
13
+ end
14
+
15
+ rule(:fawry_secure_key) do
16
+ if Fawry.configuration.fawry_secure_key.nil? && ENV['FAWRY_SECURE_KEY'].nil? && value.nil?
17
+ key(:fawry_secure_key).failure('fawry secure key is required in either Fawry.configuration or'\
18
+ 'as an environment variable (FAWRY_SECURE_KEY), or as an argument to this method')
19
+ end
20
+ end
21
+
22
+ rule(:merchant_code) do
23
+ if Fawry.configuration.fawry_merchant_code.nil? && ENV['FAWRY_MERCHANT_CODE'].nil? && value.nil?
24
+ key(:merchant_code).failure('fawry merchant code is required in either Fawry.configuration or'\
25
+ 'as an environment variable (FAWRY_MERCHANT_CODE), or as an argument to this method')
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'dry-validation'
4
+
5
+ module Fawry
6
+ module Contracts
7
+ class ListTokensRequestContract < Dry::Validation::Contract
8
+ params do
9
+ required(:merchant_code).value(:string)
10
+ required(:customer_profile_id).value(:string)
11
+ optional(:fawry_secure_key).value(:string)
12
+ end
13
+
14
+ rule(:fawry_secure_key) do
15
+ if Fawry.configuration.fawry_secure_key.nil? && ENV['FAWRY_SECURE_KEY'].nil? && value.nil?
16
+ key(:fawry_secure_key).failure('fawry secure key is required in either Fawry.configuration or'\
17
+ 'as an environment variable (FAWRY_SECURE_KEY), or as an argument to this method')
18
+ end
19
+ end
20
+
21
+ rule(:merchant_code) do
22
+ if Fawry.configuration.fawry_merchant_code.nil? && ENV['FAWRY_MERCHANT_CODE'].nil? && value.nil?
23
+ key(:merchant_code).failure('fawry merchant code is required in either Fawry.configuration or'\
24
+ 'as an environment variable (FAWRY_MERCHANT_CODE), or as an argument to this method')
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -12,14 +12,16 @@ module Fawry
12
12
  end
13
13
 
14
14
  rule(:fawry_secure_key) do
15
- if ENV['FAWRY_SECURE_KEY'].nil? && value.nil?
16
- key(:fawry_secure_key).failure('fawry secure key is required as a param or an env var')
15
+ if Fawry.configuration.fawry_secure_key.nil? && ENV['FAWRY_SECURE_KEY'].nil? && value.nil?
16
+ key(:fawry_secure_key).failure('fawry secure key is required in either Fawry.configuration or'\
17
+ 'as an environment variable (FAWRY_SECURE_KEY), or as an argument to this method')
17
18
  end
18
19
  end
19
20
 
20
21
  rule(:merchant_code) do
21
- if ENV['FAWRY_MERCHANT_CODE'].nil? && value.nil?
22
- key(:merchant_code).failure('fawry merchant code is required as a param or an env var')
22
+ if Fawry.configuration.fawry_merchant_code.nil? && ENV['FAWRY_MERCHANT_CODE'].nil? && value.nil?
23
+ key(:merchant_code).failure('fawry merchant code is required in either Fawry.configuration or'\
24
+ 'as an environment variable (FAWRY_MERCHANT_CODE), or as an argument to this method')
23
25
  end
24
26
  end
25
27
  end
@@ -14,14 +14,16 @@ module Fawry
14
14
  end
15
15
 
16
16
  rule(:fawry_secure_key) do
17
- if ENV['FAWRY_SECURE_KEY'].nil? && value.nil?
18
- key(:fawry_secure_key).failure('fawry secure key is required as a param or an env var')
17
+ if Fawry.configuration.fawry_secure_key.nil? && ENV['FAWRY_SECURE_KEY'].nil? && value.nil?
18
+ key(:fawry_secure_key).failure('fawry secure key is required in either Fawry.configuration or'\
19
+ 'as an environment variable (FAWRY_SECURE_KEY), or as an argument to this method')
19
20
  end
20
21
  end
21
22
 
22
23
  rule(:merchant_code) do
23
- if ENV['FAWRY_MERCHANT_CODE'].nil? && value.nil?
24
- key(:merchant_code).failure('fawry merchant code is required as a param or an env var')
24
+ if Fawry.configuration.fawry_merchant_code.nil? && ENV['FAWRY_MERCHANT_CODE'].nil? && value.nil?
25
+ key(:merchant_code).failure('fawry merchant code is required in either Fawry.configuration or'\
26
+ 'as an environment variable (FAWRY_MERCHANT_CODE), or as an argument to this method')
25
27
  end
26
28
  end
27
29
  end
data/lib/fawry/errors.rb CHANGED
@@ -2,5 +2,6 @@
2
2
 
3
3
  module Fawry
4
4
  class InvalidFawryRequestError < StandardError; end
5
+
5
6
  class InvalidSignatureError < StandardError; end
6
7
  end
@@ -8,7 +8,7 @@ module Fawry
8
8
 
9
9
  def initialize(callback_params, opts)
10
10
  @callback_params = callback_params
11
- @fawry_secure_key = ENV.fetch('FAWRY_SECURE_KEY')
11
+ @fawry_secure_key = Fawry.configuration.fawry_secure_key || ENV.fetch('FAWRY_SECURE_KEY')
12
12
  @options = opts
13
13
  end
14
14