fawry 1.0.0 → 1.3.1

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.
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