pesapal 1.5.6 → 1.6.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 066f9356c08b057b12dee36ca4c18ac4ce6e4b2e
4
- data.tar.gz: dd01f73ffa683da11339838be6d73ee1244d6619
3
+ metadata.gz: 8af57eb900f2972e33b0415d47f6dd829bf1e292
4
+ data.tar.gz: 73ea9770d4c51b81fcc92bff9dfaaac46f1779c3
5
5
  SHA512:
6
- metadata.gz: d86aba866c7fe7ee64ca72c6f2a5f865d0d3da2b5f79cad59e71e9da575a09d5e98f7b8f25c3eefc652b71665da1366c66f12ad2f309c49c7992c140f3599324
7
- data.tar.gz: 5a921459134fa6dd99ab76c3d58045e43ad6a20bc8b6d390e6dd17773e422a065701e95e49f5b307afbaf442611d8680a6eb8cc87ef9916db1977495ec48f01b
6
+ metadata.gz: 5594d62643eec3357558ea3f133735be428c682e58e9f3040aaa2196e5aa758999b62e124e9956af5f0b42c96b681fbf0fc71b79077db24a49f222dacd5abe2a
7
+ data.tar.gz: dfe9baaca9c4488dcaa6e4744975e65937ebc013152033fca9912059e8dbbdca7ccfd038ea7acbf81116a3defbe93dc5ca35391471964b8f4a0c1c50a2923b5f
@@ -0,0 +1,3 @@
1
+ ruby:
2
+ enabled: true
3
+ config_file: .rubocop.yml
@@ -0,0 +1,15 @@
1
+ AllCops:
2
+ Include:
3
+ - '**/*.gemspec'
4
+ - '**/Gemfile'
5
+ - '**/Rakefile'
6
+ Exclude:
7
+ - 'vendor/**/*'
8
+ Metrics/LineLength:
9
+ Enabled: false
10
+ Metrics/ClassLength:
11
+ CountComments: false
12
+ Max: 150
13
+ Metrics/MethodLength:
14
+ CountComments: false
15
+ Max: 20
@@ -1,7 +1,8 @@
1
1
  language: ruby
2
2
  rvm:
3
+ - 2.1.2
4
+ - 2.1.1
3
5
  - 2.1.0
4
6
  - 2.0.0
5
7
  - 1.9.3
6
- - 1.9.2
7
8
  script: bundle exec rspec spec
@@ -1,6 +1,15 @@
1
1
  Changelog
2
2
  =========
3
3
 
4
+ v1.6.0
5
+ ------
6
+
7
+ * Enforce minimum required Ruby version, gem is tested for Ruby '>= 1.9.3'
8
+ * Add Rubocop as a development dependency and Hound to the workflow since we will use them to detect style guide violations
9
+ * Code cleanup here and there
10
+ * Avoid using set_ on method name, this changes the API slightly since we can't use set_env which was public
11
+
12
+
4
13
  v1.5.6
5
14
  ------
6
15
 
@@ -0,0 +1,29 @@
1
+ CONTRIBUTING
2
+ ============
3
+
4
+ Submitting a Pull Request
5
+ -------------------------
6
+
7
+ 1. [Fork the repository][fork].
8
+ 2. [Create a topic branch][branch] (`git checkout -b BRANCH_NAME`).
9
+ 3. [Install bundler][bundler].
10
+ 4. Check that tests pass with `rspec spec`.
11
+ 5. Write a failing test to capture existing bug or lack of feature.
12
+ 6. Run `rspec spec` to verify that test fails.
13
+ 7. Implement your feature or bug fix.
14
+ 8. Ensure tests pass.
15
+ 9. If it's a new feature or a bug fix, please add an entry to the CHANGELOG file.
16
+ 10. Check code style violations using [Rubocop][rubocop].
17
+ 11. Add a commit (`git commit -am 'AWESOME COMMIT MESSAGE'`).
18
+ 12. Push your changes to the branch (`git push origin BRANCH_NAME`).
19
+ 13. [Submit a pull request.][pr]
20
+ 14. You will get some feedback and may need to push additional commits
21
+ with more fixes to the same branch; this will update your pull request
22
+ automatically.
23
+
24
+ [branch]: http://git-scm.com/book/en/Git-Branching-Branching-Workflows#Topic-Branches
25
+ [bundler]: http://bundler.io
26
+ [fork]: https://help.github.com/articles/fork-a-repo/
27
+ [pr]: https://help.github.com/articles/using-pull-requests
28
+ [rubocop]: https://github.com/bbatsov/rubocop
29
+
@@ -1,19 +1,20 @@
1
+ # Since generators are not specific to this project, it's preferable you refer
2
+ # to the official documentation on the Rails site here;
3
+ # http://guides.rubyonrails.org/generators.html
1
4
  module Pesapal
2
- # Since generators are not specific to this project, it's preferable you refer
3
- # to the official documentation on the Rails site here;
4
- # http://guides.rubyonrails.org/generators.html
5
5
  module Generators
6
+ # Install pesapal generator
6
7
  class InstallGenerator < Rails::Generators::Base
7
- source_root File.expand_path("../../templates", __FILE__)
8
+ source_root File.expand_path('../../templates', __FILE__)
8
9
 
9
- desc "Creates a Pesapal config file to your application."
10
+ desc 'Creates a Pesapal config file to your application.'
10
11
 
11
12
  def copy_config
12
- copy_file "pesapal.yml", "config/pesapal.yml"
13
+ copy_file 'pesapal.yml', 'config/pesapal.yml'
13
14
  end
14
15
 
15
16
  def show_readme
16
- readme "README.md" if behavior == :invoke
17
+ readme 'README.md' if behavior == :invoke
17
18
  end
18
19
  end
19
20
  end
@@ -9,4 +9,3 @@ require 'pesapal/oauth'
9
9
  require 'pesapal/version'
10
10
 
11
11
  require 'pesapal/railtie' if defined?(Rails)
12
-
@@ -4,9 +4,11 @@ module Pesapal
4
4
  # Contains helper methods relating to any queries for payment details. See
5
5
  # {Pesapal::Merchant#query_payment_details} source.
6
6
  module Details
7
- # Prepares parameters to be used during the QueryPaymentDetails oAuth 1.0 call.
7
+ # Prepares parameters to be used during the QueryPaymentDetails oAuth 1.0
8
+ # call.
8
9
  #
9
- # The QueryPaymentDetails oAuth 1.0 call requires the following parameters;
10
+ # The QueryPaymentDetails oAuth 1.0 call requires the following
11
+ # parameters;
10
12
  #
11
13
  # 1. `oauth_consumer_key` - your Pesapal consumer key sent to you via email or obtained from the dashboard
12
14
  # 2. `oauth_nonce` - a random string, uniquely generated for each request. See [section 8 of the oAuth 1.0 spec][3]
@@ -17,10 +19,11 @@ module Pesapal
17
19
  # 7. `pesapal_merchant_reference` - the transaction merchant reference (same as `merchant_reference` defined below)
18
20
  # 8. `pesapal_transaction_tracking_id` - the transaction tracking id (same as `transaction_tracking_id` defined below)
19
21
  #
20
- # This method generates all the above **except** the `oauth_signature` which
21
- # is generated later by {Pesapal::Oauth.generate_oauth_signature} since
22
- # generation of this `oauth_signature` requires these parameters as inputs
23
- # anyway. See [section 9.2.1 of the oAuth 1.0 spec][1] for more details.
22
+ # This method generates all the above **except** the `oauth_signature`
23
+ # which is generated later by {Pesapal::Oauth.generate_oauth_signature}
24
+ # since generation of this `oauth_signature` requires these parameters as
25
+ # inputs anyway. See [section 9.2.1 of the oAuth 1.0 spec][1] for more
26
+ # details.
24
27
  #
25
28
  # [1]: http://oauth.net/core/1.0/#anchor16
26
29
  # [2]: http://oauth.net/core/1.0/#signing_process
@@ -36,16 +39,17 @@ module Pesapal
36
39
  # @param transaction_tracking_id [String] the unique id assigned by Pesapal
37
40
  # to the transaction after it's posted
38
41
  #
39
- # @return [Hash] parameters to be used in generating the oAuth 1.0 URL query parameters and the `oauth_signature` itself.
42
+ # @return [Hash] parameters to be used in generating the oAuth 1.0 URL
43
+ # query parameters and the `oauth_signature` itself.
40
44
  def self.set_parameters(consumer_key, merchant_reference, transaction_tracking_id)
41
45
  timestamp = Time.now.to_i.to_s
42
- { :oauth_consumer_key => consumer_key,
43
- :oauth_nonce => "#{timestamp}" + Pesapal::Oauth.generate_nonce(12),
44
- :oauth_signature_method => 'HMAC-SHA1',
45
- :oauth_timestamp => "#{timestamp}",
46
- :oauth_version => '1.0',
47
- :pesapal_merchant_reference => merchant_reference,
48
- :pesapal_transaction_tracking_id => transaction_tracking_id
46
+ { oauth_consumer_key: consumer_key,
47
+ oauth_nonce: "#{timestamp}" + Pesapal::Oauth.generate_nonce(12),
48
+ oauth_signature_method: 'HMAC-SHA1',
49
+ oauth_timestamp: "#{timestamp}",
50
+ oauth_version: '1.0',
51
+ pesapal_merchant_reference: merchant_reference,
52
+ pesapal_transaction_tracking_id: transaction_tracking_id
49
53
  }
50
54
  end
51
55
  end
@@ -82,15 +82,15 @@ module Pesapal
82
82
  #
83
83
  # ```
84
84
  # order_details = {
85
- # :amount => 1000,
86
- # :description => 'this is the transaction description',
87
- # :type => 'MERCHANT',
88
- # :reference => '808-707-606',
89
- # :first_name => 'Swaleh',
90
- # :last_name => 'Mdoe',
91
- # :email => 'user@example.com',
92
- # :phonenumber => '+254722222222',
93
- # :currency => 'KES'
85
+ # amount: 1000,
86
+ # description: 'this is the transaction description',
87
+ # type: 'MERCHANT',
88
+ # reference: '808-707-606',
89
+ # first_name: 'Swaleh',
90
+ # last_name: 'Mdoe',
91
+ # email: 'user@example.com',
92
+ # phonenumber: '+254722222222',
93
+ # currency: 'KES'
94
94
  # }
95
95
  # ```
96
96
  #
@@ -124,7 +124,7 @@ module Pesapal
124
124
 
125
125
  # Encode the XML
126
126
  encoder = HTMLEntities.new(:xhtml1)
127
- post_xml = encoder.encode post_xml
127
+ encoder.encode post_xml
128
128
  end
129
129
 
130
130
  # Prepares parameters to be used during the PostPesapalDirectOrderV4 oAuth 1.0 call.
@@ -163,13 +163,13 @@ module Pesapal
163
163
  # @return [Hash] parameters to be used in generating the oAuth 1.0 URL query parameters and the `oauth_signature` itself.
164
164
  def self.set_parameters(callback_url, consumer_key, post_xml)
165
165
  timestamp = Time.now.to_i.to_s
166
- { :oauth_callback => callback_url,
167
- :oauth_consumer_key => consumer_key,
168
- :oauth_nonce => "#{timestamp}" + Pesapal::Oauth.generate_nonce(12),
169
- :oauth_signature_method => 'HMAC-SHA1',
170
- :oauth_timestamp => "#{timestamp}",
171
- :oauth_version => '1.0',
172
- :pesapal_request_data => post_xml
166
+ { oauth_callback: callback_url,
167
+ oauth_consumer_key: consumer_key,
168
+ oauth_nonce: "#{timestamp}" + Pesapal::Oauth.generate_nonce(12),
169
+ oauth_signature_method: 'HMAC-SHA1',
170
+ oauth_timestamp: "#{timestamp}",
171
+ oauth_version: '1.0',
172
+ pesapal_request_data: post_xml
173
173
  }
174
174
  end
175
175
  end
@@ -39,15 +39,15 @@ module Pesapal
39
39
  # @return [Hash] parameters to be used in generating the oAuth 1.0 URL query parameters and the `oauth_signature` itself.
40
40
  def self.set_parameters(consumer_key, merchant_reference, transaction_tracking_id = nil)
41
41
  timestamp = Time.now.to_i.to_s
42
- params = { :oauth_consumer_key => consumer_key,
43
- :oauth_nonce => "#{timestamp}" + Pesapal::Oauth.generate_nonce(12),
44
- :oauth_signature_method => 'HMAC-SHA1',
45
- :oauth_timestamp => "#{timestamp}",
46
- :oauth_version => '1.0',
47
- :pesapal_merchant_reference => merchant_reference
42
+ params = { oauth_consumer_key: consumer_key,
43
+ oauth_nonce: "#{timestamp}" + Pesapal::Oauth.generate_nonce(12),
44
+ oauth_signature_method: 'HMAC-SHA1',
45
+ oauth_timestamp: "#{timestamp}",
46
+ oauth_version: '1.0',
47
+ pesapal_merchant_reference: merchant_reference
48
48
  }
49
49
  params[:pesapal_transaction_tracking_id] = transaction_tracking_id unless transaction_tracking_id.nil?
50
- return params
50
+ params
51
51
  end
52
52
  end
53
53
  end
@@ -140,17 +140,17 @@ module Pesapal
140
140
  # }
141
141
  # ```
142
142
  #
143
- # @note You can change the environment at runtime using {#set_env}
143
+ # @note You can change the environment at runtime using {#change_env}
144
144
  #
145
145
  # @param env [Symbol] the environment we want to use i.e. `:development` or
146
146
  # `:production`. Leaving it blank sets environment intelligently to
147
147
  # `Rails.env` (if Rails) or `:development` (if non-Rails).
148
148
  def initialize(env = false)
149
- set_env env
149
+ change_env env
150
150
  if defined?(Rails)
151
- set_configuration Rails.application.config.pesapal_credentials
151
+ configure Rails.application.config.pesapal_credentials
152
152
  else
153
- set_configuration
153
+ configure
154
154
  end
155
155
  end
156
156
 
@@ -159,7 +159,7 @@ module Pesapal
159
159
  # PesaPal will present the user with a page which contains the available
160
160
  # payment options and will redirect to your site to the _callback url_ once
161
161
  # the user has completed the payment process. A tracking id will be returned
162
- # as a query parameter this can be used subsequently to track the payment
162
+ # as a query parameter - this can be used subsequently to track the payment
163
163
  # status on Pesapal for the transaction later on.
164
164
  #
165
165
  # Generating the URL is a 3-step process:
@@ -190,7 +190,7 @@ module Pesapal
190
190
  @params = Pesapal::Helper::Post.set_parameters(@config[:callback_url], @config[:consumer_key], @post_xml)
191
191
 
192
192
  # generate oauth signature and add signature to the request parameters
193
- @params[:oauth_signature] = Pesapal::Oauth::generate_oauth_signature("GET", @api_endpoints[:postpesapaldirectorderv4], @params, @config[:consumer_secret], @token_secret)
193
+ @params[:oauth_signature] = Pesapal::Oauth.generate_oauth_signature('GET', @api_endpoints[:postpesapaldirectorderv4], @params, @config[:consumer_secret], @token_secret)
194
194
 
195
195
  # change params (with signature) to a query string
196
196
  query_string = Pesapal::Oauth.generate_encoded_params_query_string @params
@@ -239,7 +239,7 @@ module Pesapal
239
239
  @params = Pesapal::Helper::Details.set_parameters(@config[:consumer_key], merchant_reference, transaction_tracking_id)
240
240
 
241
241
  # generate oauth signature and add signature to the request parameters
242
- @params[:oauth_signature] = Pesapal::Oauth.generate_oauth_signature("GET", @api_endpoints[:querypaymentdetails], @params, @config[:consumer_secret], @token_secret)
242
+ @params[:oauth_signature] = Pesapal::Oauth.generate_oauth_signature('GET', @api_endpoints[:querypaymentdetails], @params, @config[:consumer_secret], @token_secret)
243
243
 
244
244
  # change params (with signature) to a query string
245
245
  query_string = Pesapal::Oauth.generate_encoded_params_query_string @params
@@ -255,10 +255,10 @@ module Pesapal
255
255
  response = CGI.parse response.body
256
256
  response = response['pesapal_response_data'][0].split(',')
257
257
 
258
- { :method => response[1],
259
- :status => response[2],
260
- :merchant_reference => response[3],
261
- :transaction_tracking_id => response[0]
258
+ { method: response[1],
259
+ status: response[2],
260
+ merchant_reference: response[3],
261
+ transaction_tracking_id: response[0]
262
262
  }
263
263
  end
264
264
 
@@ -294,7 +294,7 @@ module Pesapal
294
294
  @params = Pesapal::Helper::Status.set_parameters(@config[:consumer_key], merchant_reference, transaction_tracking_id)
295
295
 
296
296
  # generate oauth signature and add signature to the request parameters
297
- @params[:oauth_signature] = Pesapal::Oauth.generate_oauth_signature("GET", @api_endpoints[:querypaymentstatus], @params, @config[:consumer_secret], @token_secret)
297
+ @params[:oauth_signature] = Pesapal::Oauth.generate_oauth_signature('GET', @api_endpoints[:querypaymentstatus], @params, @config[:consumer_secret], @token_secret)
298
298
 
299
299
  # change params (with signature) to a query string
300
300
  query_string = Pesapal::Oauth.generate_encoded_params_query_string @params
@@ -344,7 +344,7 @@ module Pesapal
344
344
  #
345
345
  # @return [Hash] contains Pesapal endpoints appropriate for the set
346
346
  # environment
347
- def set_env(env = false)
347
+ def change_env(env = false)
348
348
  env = env.to_s.downcase
349
349
  if env == 'production'
350
350
  @env = 'production'
@@ -352,7 +352,7 @@ module Pesapal
352
352
  @env = 'development'
353
353
  @env = Rails.env if defined?(Rails)
354
354
  end
355
- set_endpoints
355
+ assign_endpoints
356
356
  end
357
357
 
358
358
  # Generates the appropriate IPN response depending on the status of the
@@ -381,8 +381,8 @@ module Pesapal
381
381
  # @note It's up to you to send the response back to Pesapal by providing the
382
382
  # `:response` back to the IPN. The hard part is done.
383
383
  #
384
- # @param notification_type [String] the IPN notification type, should be set
385
- # to CHANGE always
384
+ # @param notification_type [String] the IPN notification type, overridden
385
+ # and set to CHANGE internally. Left here for extensibility.
386
386
  #
387
387
  # @param merchant_reference [String] the unique id generated for the
388
388
  # transaction by your application before posting the order
@@ -393,12 +393,13 @@ module Pesapal
393
393
  # @return [Hash] contains the status and IPN response that should be sent
394
394
  # back to Pesapal
395
395
  def ipn_listener(notification_type, merchant_reference, transaction_tracking_id)
396
+ notification_type = 'CHANGE'
396
397
  status = query_payment_status(merchant_reference, transaction_tracking_id)
397
- output = { :status => status, :response => nil }
398
+ output = { status: status, response: nil }
398
399
 
399
400
  case status
400
- when 'COMPLETED' then output[:response] = "pesapal_notification_type=CHANGE&pesapal_transaction_tracking_id=#{transaction_tracking_id}&pesapal_merchant_reference=#{merchant_reference}"
401
- when 'FAILED' then output[:response] = "pesapal_notification_type=CHANGE&pesapal_transaction_tracking_id=#{transaction_tracking_id}&pesapal_merchant_reference=#{merchant_reference}"
401
+ when 'COMPLETED' then output[:response] = "pesapal_notification_type=#{notification_type}&pesapal_transaction_tracking_id=#{transaction_tracking_id}&pesapal_merchant_reference=#{merchant_reference}"
402
+ when 'FAILED' then output[:response] = "pesapal_notification_type=#{notification_type}&pesapal_transaction_tracking_id=#{transaction_tracking_id}&pesapal_merchant_reference=#{merchant_reference}"
402
403
  end
403
404
 
404
405
  output
@@ -406,8 +407,8 @@ module Pesapal
406
407
 
407
408
  private
408
409
 
409
- # Set API endpoints depending on the environment.
410
- def set_endpoints
410
+ # Assign API endpoints depending on the environment.
411
+ def assign_endpoints
411
412
  if @env == 'production'
412
413
  @api_domain = 'https://www.pesapal.com'
413
414
  else
@@ -422,13 +423,12 @@ module Pesapal
422
423
  @api_endpoints
423
424
  end
424
425
 
425
- # Set credentials through hash that passed in (does a little processing to
426
- # remove unwanted data & uses default if nothing is input).
427
- def set_configuration(consumer_details = {})
428
- # set the configuration
429
- @config = { :callback_url => 'http://0.0.0.0:3000/pesapal/callback',
430
- :consumer_key => '<YOUR_CONSUMER_KEY>',
431
- :consumer_secret => '<YOUR_CONSUMER_SECRET>'
426
+ # Configure credentials through hash that passed in (does a little
427
+ # processing to remove unwanted data & uses default if nothing is input).
428
+ def configure(consumer_details = {})
429
+ @config = { callback_url: 'http://0.0.0.0:3000/pesapal/callback',
430
+ consumer_key: '<YOUR_CONSUMER_KEY>',
431
+ consumer_secret: '<YOUR_CONSUMER_SECRET>'
432
432
  }
433
433
 
434
434
  valid_config_keys = @config.keys
@@ -114,7 +114,6 @@ module Pesapal
114
114
  #
115
115
  # @return [String] valid signature base string.
116
116
  def self.generate_signature_base_string(http_method, absolute_url, params)
117
-
118
117
  # step 1: convert the http method to uppercase
119
118
  http_method = http_method.upcase
120
119
 
@@ -156,11 +155,11 @@ module Pesapal
156
155
  # > String MUST include the scheme, authority, and path, and MUST exclude
157
156
  # > the query and fragment as defined by [RFC3986] section 3._
158
157
  #
159
- # > _If the absolute request URL is not available to the Service Provider (it
160
- # > is always available to the Consumer), it can be constructed by combining
161
- # > the scheme being used, the HTTP Host header, and the relative HTTP
162
- # > request URL. If the Host header is not available, the Service Provider
163
- # > SHOULD use the host name communicated to the Consumer in the
158
+ # > _If the absolute request URL is not available to the Service Provider
159
+ # > (it is always available to the Consumer), it can be constructed by
160
+ # > combining the scheme being used, the HTTP Host header, and the relative
161
+ # > HTTP request URL. If the Host header is not available, the Service
162
+ # > Provider SHOULD use the host name communicated to the Consumer in the
164
163
  # > documentation or other means._
165
164
  #
166
165
  # > _The Service Provider SHOULD document the form of URL used in the
@@ -184,7 +183,7 @@ module Pesapal
184
183
  path = u.path
185
184
  port = u.port
186
185
 
187
- port = (scheme == 'http' && port != 80) || (scheme == 'https' && port != 443) ? ":#{port}" : ""
186
+ port = (scheme == 'http' && port != 80) || (scheme == 'https' && port != 443) ? ":#{port}" : ''
188
187
  path = (path && path != '') ? path : '/'
189
188
 
190
189
  "#{scheme}://#{host}#{port}#{path}"
@@ -209,8 +208,8 @@ module Pesapal
209
208
  def self.parameter_encode(str)
210
209
  # reserved character regexp, per section 5.1
211
210
  reserved_characters = /[^a-zA-Z0-9\-\.\_\~]/
212
- # Apparently we can't force_encoding on a frozen string since that would modify it.
213
- # What we can do is work with a copy
211
+ # Apparently we can't force_encoding on a frozen string since that would
212
+ # modify it. What we can do is work with a copy
214
213
  URI.escape(str.dup.to_s.force_encoding(Encoding::UTF_8), reserved_characters)
215
214
  end
216
215
  end
@@ -9,14 +9,16 @@ module Pesapal
9
9
  begin
10
10
  config.pesapal_credentials = YAML.load(IO.read(path_to_yaml))[Rails.env]
11
11
  rescue Errno::ENOENT
12
- logger.info('YAML configuration file couldn\'t be found.'); return
12
+ logger.info('YAML configuration file couldn\'t be found.')
13
+ return
13
14
  rescue Psych::SyntaxError
14
- logger.info('YAML configuration file contains invalid syntax. Will use using defaults.'); return
15
+ logger.info('YAML configuration file contains invalid syntax. Will use using defaults.')
16
+ return
15
17
  end
16
18
  else
17
- config.pesapal_credentials = { :callback_url => 'http://0.0.0.0:3000/pesapal/callback',
18
- :consumer_key => '<YOUR_CONSUMER_KEY>',
19
- :consumer_secret => '<YOUR_CONSUMER_SECRET>'
19
+ config.pesapal_credentials = { callback_url: 'http://0.0.0.0:3000/pesapal/callback',
20
+ consumer_key: '<YOUR_CONSUMER_KEY>',
21
+ consumer_secret: '<YOUR_CONSUMER_SECRET>'
20
22
  }
21
23
  end
22
24
  end
@@ -4,5 +4,5 @@ module Pesapal
4
4
  # This gem's version (learn about [Semantic Versioning][1]).
5
5
  #
6
6
  # [1]: http://semver.org/
7
- VERSION = '1.5.6'
7
+ VERSION = '1.6.0'
8
8
  end
@@ -1,5 +1,6 @@
1
1
  lib = File.expand_path('../lib', __FILE__)
2
2
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require 'english'
3
4
  require 'pesapal/version'
4
5
 
5
6
  Gem::Specification.new do |spec|
@@ -13,17 +14,19 @@ Gem::Specification.new do |spec|
13
14
  spec.homepage = 'http://itsmrwave.github.io/pesapal-gem'
14
15
  spec.license = 'MIT'
15
16
 
16
- spec.files = `git ls-files`.split($/)
17
- spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
- spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
17
+ spec.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
18
+ spec.executables = spec.files.grep(/^bin\//) { |f| File.basename(f) }
19
+ spec.test_files = spec.files.grep(/^(test|spec|features)\//)
19
20
  spec.require_paths = ['lib']
20
21
 
21
- spec.required_ruby_version = '>= 1.9.2'
22
+ spec.required_ruby_version = '>= 1.9.3'
22
23
 
23
24
  spec.add_development_dependency 'bundler'
24
25
  spec.add_development_dependency 'coveralls'
26
+ spec.add_development_dependency 'faker'
25
27
  spec.add_development_dependency 'rake'
26
28
  spec.add_development_dependency 'rspec'
29
+ spec.add_development_dependency 'rubocop'
27
30
  spec.add_development_dependency 'webmock'
28
31
 
29
32
  spec.add_runtime_dependency 'htmlentities'
@@ -2,401 +2,361 @@ require 'spec_helper'
2
2
 
3
3
  describe Pesapal::Merchant do
4
4
 
5
+ let(:order_details) do
6
+ { amount: 1000,
7
+ description: Faker::Lorem.sentence,
8
+ type: 'MERCHANT',
9
+ reference: '111-222-333',
10
+ first_name: Faker::Name.first_name,
11
+ last_name: Faker::Name.last_name,
12
+ email: Faker::Internet.email,
13
+ phonenumber: Faker::PhoneNumber.phone_number,
14
+ currency: 'KES' # ['USD', 'KES', 'UGX', 'TZA'].sample
15
+ }
16
+ end
17
+
18
+ let(:default_credentials) do
19
+ { callback_url: 'http://0.0.0.0:3000/pesapal/callback',
20
+ consumer_key: '<YOUR_CONSUMER_KEY>',
21
+ consumer_secret: '<YOUR_CONSUMER_SECRET>'
22
+ }
23
+ end
24
+
25
+ let(:demo_endpoints) do
26
+ { postpesapaldirectorderv4: 'http://demo.pesapal.com/API/PostPesapalDirectOrderV4',
27
+ querypaymentstatus: 'http://demo.pesapal.com/API/QueryPaymentStatus',
28
+ querypaymentdetails: 'http://demo.pesapal.com/API/QueryPaymentDetails'
29
+ }
30
+ end
31
+
32
+ let(:production_endpoints) do
33
+ { postpesapaldirectorderv4: 'https://www.pesapal.com/API/PostPesapalDirectOrderV4',
34
+ querypaymentstatus: 'https://www.pesapal.com/API/QueryPaymentStatus',
35
+ querypaymentdetails: 'https://www.pesapal.com/API/QueryPaymentDetails'
36
+ }
37
+ end
38
+
5
39
  context 'when mode not specified' do
6
40
 
7
- before :each do
8
- @pesapal = Pesapal::Merchant.new
9
- end
41
+ let(:pesapal) { Pesapal::Merchant.new }
10
42
 
11
43
  describe '#new' do
12
44
 
13
45
  it 'is valid object' do
14
- expect(@pesapal).to be_an_instance_of(Pesapal::Merchant)
46
+ expect(pesapal).to be_an_instance_of(Pesapal::Merchant)
15
47
  end
16
48
 
17
49
  it 'sets default environment variable' do
18
- expect(@pesapal.send(:env)).to eq 'development'
50
+ expect(pesapal.send(:env)).to eq 'development'
19
51
  end
20
52
 
21
53
  it 'sets default credentials' do
22
- expect(@pesapal.config).to eq(default_credentials)
54
+ expect(pesapal.config).to eq(default_credentials)
23
55
  end
24
56
 
25
57
  it 'sets default order details' do
26
- expect(@pesapal.order_details).to eq({})
58
+ expect(pesapal.order_details).to eq({})
27
59
  end
28
60
  end
29
61
 
30
- describe '#set_env' do
62
+ describe '#change_env' do
31
63
 
32
64
  it 'sets default environment variable' do
33
- @pesapal.set_env
34
- expect(@pesapal.send(:env)).to eq 'development'
65
+ pesapal.change_env
66
+ expect(pesapal.send(:env)).to eq 'development'
35
67
  end
36
68
 
37
69
  it 'sets endpoints for default environment' do
38
- expect(@pesapal.set_env).to eq(demo_endpoints)
70
+ expect(pesapal.change_env).to eq(demo_endpoints)
39
71
  end
40
72
  end
41
73
 
42
74
  describe '#generate_order_url' do
43
75
 
44
76
  it 'generates iframe url string' do
45
- @pesapal.order_details = { :amount => 1000,
46
- :description => 'This is the description for the test transaction.',
47
- :type => 'MERCHANT',
48
- :reference => '111-222-333',
49
- :first_name => 'Swaleh',
50
- :last_name => 'Mdoe',
51
- :email => 'test@example.com',
52
- :phonenumber => '+254711000333',
53
- :currency => 'KES'
54
- }
55
- expect(@pesapal.generate_order_url).to match /http:\/\/demo.pesapal.com\/API\/PostPesapalDirectOrderV4\?oauth_callback=.*oauth_consumer_key=.*oauth_nonce=.*oauth_signature=.*oauth_signature_method=HMAC-SHA1&oauth_timestamp.*oauth_version=1.0&pesapal_request_data=.*/
77
+ pesapal.order_details = order_details
78
+ expect(pesapal.generate_order_url).to match %r{http://demo.pesapal.com/API/PostPesapalDirectOrderV4\?oauth_callback=.*oauth_consumer_key=.*oauth_nonce=.*oauth_signature=.*oauth_signature_method=HMAC-SHA1&oauth_timestamp.*oauth_version=1.0&pesapal_request_data=.*}
56
79
  end
57
80
  end
58
81
 
59
82
  describe '#query_payment_status' do
60
83
 
61
- before :each do
62
- @request = stub_request(:get, /http:\/\/demo.pesapal.com\/API\/QueryPaymentStatus\?oauth_consumer_key=.*oauth_nonce=.*oauth_signature=.*oauth_signature_method=HMAC-SHA1&oauth_timestamp.*oauth_version=1.0&pesapal_merchant_reference=.*&pesapal_transaction_tracking_id=.*/)
63
- end
84
+ let(:request) { stub_request(:get, %r{http://demo.pesapal.com/API/QueryPaymentStatus\?oauth_consumer_key=.*oauth_nonce=.*oauth_signature=.*oauth_signature_method=HMAC-SHA1&oauth_timestamp.*oauth_version=1.0&pesapal_merchant_reference=.*&pesapal_transaction_tracking_id=.*}) }
64
85
 
65
86
  it 'gets pending payment status' do
66
- @request.to_return(:status => 200, :body => 'pesapal_response_data=PENDING')
67
- expect(@pesapal.query_payment_status('merchant_reference', 'transaction_tracking_id')).to eq('PENDING')
87
+ request.to_return(status: 200, body: 'pesapal_response_data=PENDING')
88
+ expect(pesapal.query_payment_status('merchant_reference', 'transaction_tracking_id')).to eq('PENDING')
68
89
  end
69
90
 
70
91
  it 'gets completed payment status' do
71
- @request.to_return(:status => 200, :body => 'pesapal_response_data=COMPLETED')
72
- expect(@pesapal.query_payment_status('merchant_reference', 'transaction_tracking_id')).to eq('COMPLETED')
92
+ request.to_return(status: 200, body: 'pesapal_response_data=COMPLETED')
93
+ expect(pesapal.query_payment_status('merchant_reference', 'transaction_tracking_id')).to eq('COMPLETED')
73
94
  end
74
95
 
75
96
  it 'gets failed payment status' do
76
- @request.to_return(:status => 200, :body => 'pesapal_response_data=FAILED')
77
- expect(@pesapal.query_payment_status('merchant_reference', 'transaction_tracking_id')).to eq('FAILED')
97
+ request.to_return(status: 200, body: 'pesapal_response_data=FAILED')
98
+ expect(pesapal.query_payment_status('merchant_reference', 'transaction_tracking_id')).to eq('FAILED')
78
99
  end
79
100
 
80
101
  it 'gets invalid payment status' do
81
- @request.to_return(:status => 200, :body => 'pesapal_response_data=INVALID')
82
- expect(@pesapal.query_payment_status('merchant_reference', 'transaction_tracking_id')).to eq('INVALID')
102
+ request.to_return(status: 200, body: 'pesapal_response_data=INVALID')
103
+ expect(pesapal.query_payment_status('merchant_reference', 'transaction_tracking_id')).to eq('INVALID')
83
104
  end
84
105
  end
85
106
 
86
107
  describe '#query_payment_details' do
87
108
 
88
- before :each do
89
- @request = stub_request(:get, /http:\/\/demo.pesapal.com\/API\/QueryPaymentDetails\?oauth_consumer_key=.*oauth_nonce=.*oauth_signature=.*oauth_signature_method=HMAC-SHA1&oauth_timestamp.*oauth_version=1.0&pesapal_merchant_reference=.*&pesapal_transaction_tracking_id=.*/)
90
- end
109
+ let(:request) { stub_request(:get, %r{http://demo.pesapal.com/API/QueryPaymentDetails\?oauth_consumer_key=.*oauth_nonce=.*oauth_signature=.*oauth_signature_method=HMAC-SHA1&oauth_timestamp.*oauth_version=1.0&pesapal_merchant_reference=.*&pesapal_transaction_tracking_id=.*}) }
91
110
 
92
111
  it 'gets pending payment details' do
93
- @request.to_return(:status => 200, :body => 'pesapal_response_data=transaction_tracking_id,payment_method,payment_status,merchant_reference')
94
- expect(@pesapal.query_payment_details('merchant_reference', 'transaction_tracking_id')).to eq({ :method => 'payment_method',
95
- :status => 'payment_status',
96
- :merchant_reference => 'merchant_reference',
97
- :transaction_tracking_id => 'transaction_tracking_id'
98
- })
112
+ request.to_return(status: 200, body: 'pesapal_response_data=transaction_tracking_id,payment_method,payment_status,merchant_reference')
113
+ expect(pesapal.query_payment_details('merchant_reference', 'transaction_tracking_id')).to eq(method: 'payment_method',
114
+ status: 'payment_status',
115
+ merchant_reference: 'merchant_reference',
116
+ transaction_tracking_id: 'transaction_tracking_id'
117
+ )
99
118
  end
100
119
  end
101
120
 
102
121
  describe '#ipn_listener' do
103
122
 
104
- before :each do
105
- @request = stub_request(:get, /http:\/\/demo.pesapal.com\/API\/QueryPaymentStatus\?oauth_consumer_key=.*oauth_nonce=.*oauth_signature=.*oauth_signature_method=HMAC-SHA1&oauth_timestamp.*oauth_version=1.0&pesapal_merchant_reference=.*&pesapal_transaction_tracking_id=.*/)
106
- end
123
+ let(:request) { stub_request(:get, %r{http://demo.pesapal.com/API/QueryPaymentStatus\?oauth_consumer_key=.*oauth_nonce=.*oauth_signature=.*oauth_signature_method=HMAC-SHA1&oauth_timestamp.*oauth_version=1.0&pesapal_merchant_reference=.*&pesapal_transaction_tracking_id=.*}) }
107
124
 
108
125
  it 'gets ipn response for pending status' do
109
- @request.to_return(:status => 200, :body => 'pesapal_response_data=PENDING')
110
- expect(@pesapal.ipn_listener('CHANGE', 'merchant_reference', 'transaction_tracking_id')).to eq({:status => 'PENDING', :response => nil})
126
+ request.to_return(status: 200, body: 'pesapal_response_data=PENDING')
127
+ expect(pesapal.ipn_listener('CHANGE', 'merchant_reference', 'transaction_tracking_id')).to eq(status: 'PENDING', response: nil)
111
128
  end
112
129
 
113
130
  it 'gets ipn response for completed status' do
114
- @request.to_return(:status => 200, :body => 'pesapal_response_data=COMPLETED')
115
- expect(@pesapal.ipn_listener('CHANGE', 'merchant_reference', 'transaction_tracking_id')).to eq({:status => 'COMPLETED', :response => 'pesapal_notification_type=CHANGE&pesapal_transaction_tracking_id=transaction_tracking_id&pesapal_merchant_reference=merchant_reference'})
131
+ request.to_return(status: 200, body: 'pesapal_response_data=COMPLETED')
132
+ expect(pesapal.ipn_listener('CHANGE', 'merchant_reference', 'transaction_tracking_id')).to eq(status: 'COMPLETED', response: 'pesapal_notification_type=CHANGE&pesapal_transaction_tracking_id=transaction_tracking_id&pesapal_merchant_reference=merchant_reference')
116
133
  end
117
134
 
118
135
  it 'gets ipn response for failed status' do
119
- @request.to_return(:status => 200, :body => 'pesapal_response_data=FAILED')
120
- expect(@pesapal.ipn_listener('CHANGE', 'merchant_reference', 'transaction_tracking_id')).to eq({:status => 'FAILED', :response => 'pesapal_notification_type=CHANGE&pesapal_transaction_tracking_id=transaction_tracking_id&pesapal_merchant_reference=merchant_reference'})
136
+ request.to_return(status: 200, body: 'pesapal_response_data=FAILED')
137
+ expect(pesapal.ipn_listener('CHANGE', 'merchant_reference', 'transaction_tracking_id')).to eq(status: 'FAILED', response: 'pesapal_notification_type=CHANGE&pesapal_transaction_tracking_id=transaction_tracking_id&pesapal_merchant_reference=merchant_reference')
121
138
  end
122
139
 
123
140
  it 'gets ipn response for invalid status' do
124
- @request.to_return(:status => 200, :body => 'pesapal_response_data=INVALID')
125
- expect(@pesapal.ipn_listener('CHANGE', 'merchant_reference', 'transaction_tracking_id')).to eq({:status => 'INVALID', :response => nil})
141
+ request.to_return(status: 200, body: 'pesapal_response_data=INVALID')
142
+ expect(pesapal.ipn_listener('CHANGE', 'merchant_reference', 'transaction_tracking_id')).to eq(status: 'INVALID', response: nil)
126
143
  end
127
144
  end
128
145
  end
129
146
 
130
147
  context 'when mode is specified as development' do
131
148
 
132
- before :each do
133
- @pesapal = Pesapal::Merchant.new(:development)
134
- end
149
+ let(:pesapal) { Pesapal::Merchant.new(:development) }
135
150
 
136
151
  describe '#new(:development)' do
137
152
 
138
153
  it 'is valid object' do
139
- expect(@pesapal).to be_an_instance_of(Pesapal::Merchant)
154
+ expect(pesapal).to be_an_instance_of(Pesapal::Merchant)
140
155
  end
141
156
 
142
157
  it 'sets environment variable' do
143
- expect(@pesapal.send(:env)).to eq 'development'
158
+ expect(pesapal.send(:env)).to eq 'development'
144
159
  end
145
160
 
146
161
  it 'sets credentials' do
147
- expect(@pesapal.config).to eq(default_credentials)
162
+ expect(pesapal.config).to eq(default_credentials)
148
163
  end
149
164
 
150
165
  it 'sets order details' do
151
- expect(@pesapal.order_details).to eq({})
166
+ expect(pesapal.order_details).to eq({})
152
167
  end
153
168
  end
154
169
 
155
- describe '#set_env(:development)' do
170
+ describe '#change_env(:development)' do
156
171
 
157
172
  it 'sets environment variable' do
158
- @pesapal.set_env :development
159
- expect(@pesapal.send(:env)).to eq 'development'
173
+ pesapal.change_env :development
174
+ expect(pesapal.send(:env)).to eq 'development'
160
175
  end
161
176
 
162
177
  it 'sets endpoints for environment' do
163
- expect(@pesapal.set_env :development).to eq(demo_endpoints)
178
+ expect(pesapal.change_env :development).to eq(demo_endpoints)
164
179
  end
165
180
  end
166
181
 
167
182
  describe '#generate_order_url' do
168
183
 
169
184
  it 'generates iframe url string' do
170
- @pesapal.order_details = { :amount => 1000,
171
- :description => 'This is the description for the test transaction.',
172
- :type => 'MERCHANT',
173
- :reference => '111-222-333',
174
- :first_name => 'Swaleh',
175
- :last_name => 'Mdoe',
176
- :email => 'test@example.com',
177
- :phonenumber => '+254711000333',
178
- :currency => 'KES'
179
- }
180
- expect(@pesapal.generate_order_url).to match /http:\/\/demo.pesapal.com\/API\/PostPesapalDirectOrderV4\?oauth_callback=.*oauth_consumer_key=.*oauth_nonce=.*oauth_signature=.*oauth_signature_method=HMAC-SHA1&oauth_timestamp.*oauth_version=1.0&pesapal_request_data=.*/
185
+ pesapal.order_details = order_details
186
+ expect(pesapal.generate_order_url).to match %r{http://demo.pesapal.com/API/PostPesapalDirectOrderV4\?oauth_callback=.*oauth_consumer_key=.*oauth_nonce=.*oauth_signature=.*oauth_signature_method=HMAC-SHA1&oauth_timestamp.*oauth_version=1.0&pesapal_request_data=.*}
181
187
  end
182
188
  end
183
189
 
184
190
  describe '#query_payment_status' do
185
191
 
186
- before :each do
187
- @request = stub_request(:get, /http:\/\/demo.pesapal.com\/API\/QueryPaymentStatus\?oauth_consumer_key=.*oauth_nonce=.*oauth_signature=.*oauth_signature_method=HMAC-SHA1&oauth_timestamp.*oauth_version=1.0&pesapal_merchant_reference=.*&pesapal_transaction_tracking_id=.*/)
188
- end
192
+ let(:request) { stub_request(:get, %r{http://demo.pesapal.com/API/QueryPaymentStatus\?oauth_consumer_key=.*oauth_nonce=.*oauth_signature=.*oauth_signature_method=HMAC-SHA1&oauth_timestamp.*oauth_version=1.0&pesapal_merchant_reference=.*&pesapal_transaction_tracking_id=.*}) }
189
193
 
190
194
  it 'gets pending payment status' do
191
- @request.to_return(:status => 200, :body => 'pesapal_response_data=PENDING')
192
- expect(@pesapal.query_payment_status('merchant_reference', 'transaction_tracking_id')).to eq('PENDING')
195
+ request.to_return(status: 200, body: 'pesapal_response_data=PENDING')
196
+ expect(pesapal.query_payment_status('merchant_reference', 'transaction_tracking_id')).to eq('PENDING')
193
197
  end
194
198
 
195
199
  it 'gets completed payment status' do
196
- @request.to_return(:status => 200, :body => 'pesapal_response_data=COMPLETED')
197
- expect(@pesapal.query_payment_status('merchant_reference', 'transaction_tracking_id')).to eq('COMPLETED')
200
+ request.to_return(status: 200, body: 'pesapal_response_data=COMPLETED')
201
+ expect(pesapal.query_payment_status('merchant_reference', 'transaction_tracking_id')).to eq('COMPLETED')
198
202
  end
199
203
 
200
204
  it 'gets failed payment status' do
201
- @request.to_return(:status => 200, :body => 'pesapal_response_data=FAILED')
202
- expect(@pesapal.query_payment_status('merchant_reference', 'transaction_tracking_id')).to eq('FAILED')
205
+ request.to_return(status: 200, body: 'pesapal_response_data=FAILED')
206
+ expect(pesapal.query_payment_status('merchant_reference', 'transaction_tracking_id')).to eq('FAILED')
203
207
  end
204
208
 
205
209
  it 'gets invalid payment status' do
206
- @request.to_return(:status => 200, :body => 'pesapal_response_data=INVALID')
207
- expect(@pesapal.query_payment_status('merchant_reference', 'transaction_tracking_id')).to eq('INVALID')
210
+ request.to_return(status: 200, body: 'pesapal_response_data=INVALID')
211
+ expect(pesapal.query_payment_status('merchant_reference', 'transaction_tracking_id')).to eq('INVALID')
208
212
  end
209
213
  end
210
214
 
211
215
  describe '#query_payment_details' do
212
216
 
213
- before :each do
214
- @request = stub_request(:get, /http:\/\/demo.pesapal.com\/API\/QueryPaymentDetails\?oauth_consumer_key=.*oauth_nonce=.*oauth_signature=.*oauth_signature_method=HMAC-SHA1&oauth_timestamp.*oauth_version=1.0&pesapal_merchant_reference=.*&pesapal_transaction_tracking_id=.*/)
215
- end
217
+ let(:request) { stub_request(:get, %r{http://demo.pesapal.com/API/QueryPaymentDetails\?oauth_consumer_key=.*oauth_nonce=.*oauth_signature=.*oauth_signature_method=HMAC-SHA1&oauth_timestamp.*oauth_version=1.0&pesapal_merchant_reference=.*&pesapal_transaction_tracking_id=.*}) }
216
218
 
217
219
  it 'gets pending payment details' do
218
- @request.to_return(:status => 200, :body => 'pesapal_response_data=transaction_tracking_id,payment_method,payment_status,merchant_reference')
219
- expect(@pesapal.query_payment_details('merchant_reference', 'transaction_tracking_id')).to eq({ :method => 'payment_method',
220
- :status => 'payment_status',
221
- :merchant_reference => 'merchant_reference',
222
- :transaction_tracking_id => 'transaction_tracking_id'
223
- })
220
+ request.to_return(status: 200, body: 'pesapal_response_data=transaction_tracking_id,payment_method,payment_status,merchant_reference')
221
+ expect(pesapal.query_payment_details('merchant_reference', 'transaction_tracking_id')).to eq(method: 'payment_method',
222
+ status: 'payment_status',
223
+ merchant_reference: 'merchant_reference',
224
+ transaction_tracking_id: 'transaction_tracking_id'
225
+ )
224
226
  end
225
227
  end
226
228
 
227
229
  describe '#ipn_listener' do
228
230
 
229
- before :each do
230
- @request = stub_request(:get, /http:\/\/demo.pesapal.com\/API\/QueryPaymentStatus\?oauth_consumer_key=.*oauth_nonce=.*oauth_signature=.*oauth_signature_method=HMAC-SHA1&oauth_timestamp.*oauth_version=1.0&pesapal_merchant_reference=.*&pesapal_transaction_tracking_id=.*/)
231
- end
231
+ let(:request) { stub_request(:get, %r{http://demo.pesapal.com/API/QueryPaymentStatus\?oauth_consumer_key=.*oauth_nonce=.*oauth_signature=.*oauth_signature_method=HMAC-SHA1&oauth_timestamp.*oauth_version=1.0&pesapal_merchant_reference=.*&pesapal_transaction_tracking_id=.*}) }
232
232
 
233
233
  it 'gets ipn response for pending status' do
234
- @request.to_return(:status => 200, :body => 'pesapal_response_data=PENDING')
235
- expect(@pesapal.ipn_listener('CHANGE', 'merchant_reference', 'transaction_tracking_id')).to eq({:status => 'PENDING', :response => nil})
234
+ request.to_return(status: 200, body: 'pesapal_response_data=PENDING')
235
+ expect(pesapal.ipn_listener('CHANGE', 'merchant_reference', 'transaction_tracking_id')).to eq(status: 'PENDING', response: nil)
236
236
  end
237
237
 
238
238
  it 'gets ipn response for completed status' do
239
- @request.to_return(:status => 200, :body => 'pesapal_response_data=COMPLETED')
240
- expect(@pesapal.ipn_listener('CHANGE', 'merchant_reference', 'transaction_tracking_id')).to eq({:status => 'COMPLETED', :response => 'pesapal_notification_type=CHANGE&pesapal_transaction_tracking_id=transaction_tracking_id&pesapal_merchant_reference=merchant_reference'})
239
+ request.to_return(status: 200, body: 'pesapal_response_data=COMPLETED')
240
+ expect(pesapal.ipn_listener('CHANGE', 'merchant_reference', 'transaction_tracking_id')).to eq(status: 'COMPLETED', response: 'pesapal_notification_type=CHANGE&pesapal_transaction_tracking_id=transaction_tracking_id&pesapal_merchant_reference=merchant_reference')
241
241
  end
242
242
 
243
243
  it 'gets ipn response for failed status' do
244
- @request.to_return(:status => 200, :body => 'pesapal_response_data=FAILED')
245
- expect(@pesapal.ipn_listener('CHANGE', 'merchant_reference', 'transaction_tracking_id')).to eq({:status => 'FAILED', :response => 'pesapal_notification_type=CHANGE&pesapal_transaction_tracking_id=transaction_tracking_id&pesapal_merchant_reference=merchant_reference'})
244
+ request.to_return(status: 200, body: 'pesapal_response_data=FAILED')
245
+ expect(pesapal.ipn_listener('CHANGE', 'merchant_reference', 'transaction_tracking_id')).to eq(status: 'FAILED', response: 'pesapal_notification_type=CHANGE&pesapal_transaction_tracking_id=transaction_tracking_id&pesapal_merchant_reference=merchant_reference')
246
246
  end
247
247
 
248
248
  it 'gets ipn response for invalid status' do
249
- @request.to_return(:status => 200, :body => 'pesapal_response_data=INVALID')
250
- expect(@pesapal.ipn_listener('CHANGE', 'merchant_reference', 'transaction_tracking_id')).to eq({:status => 'INVALID', :response => nil})
249
+ request.to_return(status: 200, body: 'pesapal_response_data=INVALID')
250
+ expect(pesapal.ipn_listener('CHANGE', 'merchant_reference', 'transaction_tracking_id')).to eq(status: 'INVALID', response: nil)
251
251
  end
252
252
  end
253
253
  end
254
254
 
255
255
  context 'when mode is specified as production' do
256
256
 
257
- before :each do
258
- @pesapal = Pesapal::Merchant.new(:production)
259
- end
257
+ let(:pesapal) { Pesapal::Merchant.new(:production) }
260
258
 
261
259
  describe '#new(:production)' do
262
260
 
263
261
  it 'is valid object' do
264
- expect(@pesapal).to be_an_instance_of(Pesapal::Merchant)
262
+ expect(pesapal).to be_an_instance_of(Pesapal::Merchant)
265
263
  end
266
264
 
267
265
  it 'sets environment variable' do
268
- expect(@pesapal.send(:env)).to eq 'production'
266
+ expect(pesapal.send(:env)).to eq 'production'
269
267
  end
270
268
 
271
269
  it 'sets credentials' do
272
- expect(@pesapal.config).to eq(default_credentials)
270
+ expect(pesapal.config).to eq(default_credentials)
273
271
  end
274
272
 
275
273
  it 'sets order details' do
276
- expect(@pesapal.order_details).to eq({})
274
+ expect(pesapal.order_details).to eq({})
277
275
  end
278
276
  end
279
277
 
280
- describe '#set_env(:production)' do
278
+ describe '#change_env(:production)' do
281
279
 
282
280
  it 'sets environment variable' do
283
- @pesapal.set_env :production
284
- expect(@pesapal.send(:env)).to eq 'production'
281
+ pesapal.change_env :production
282
+ expect(pesapal.send(:env)).to eq 'production'
285
283
  end
286
284
 
287
285
  it 'sets endpoints for environment' do
288
- expect(@pesapal.set_env :production).to eq(production_endpoints)
286
+ expect(pesapal.change_env :production).to eq(production_endpoints)
289
287
  end
290
288
  end
291
289
 
292
290
  describe '#generate_order_url' do
293
291
 
294
292
  it 'generates iframe url string' do
295
- @pesapal.order_details = { :amount => 1000,
296
- :description => 'This is the description for the test transaction.',
297
- :type => 'MERCHANT',
298
- :reference => '111-222-333',
299
- :first_name => 'Swaleh',
300
- :last_name => 'Mdoe',
301
- :email => 'test@example.com',
302
- :phonenumber => '+254711000333',
303
- :currency => 'KES'
304
- }
305
- expect(@pesapal.generate_order_url).to match /https:\/\/www.pesapal.com\/API\/PostPesapalDirectOrderV4\?oauth_callback=.*oauth_consumer_key=.*oauth_nonce=.*oauth_signature=.*oauth_signature_method=HMAC-SHA1&oauth_timestamp.*oauth_version=1.0&pesapal_request_data=.*/
293
+ pesapal.order_details = order_details
294
+ expect(pesapal.generate_order_url).to match %r{https://www.pesapal.com/API/PostPesapalDirectOrderV4\?oauth_callback=.*oauth_consumer_key=.*oauth_nonce=.*oauth_signature=.*oauth_signature_method=HMAC-SHA1&oauth_timestamp.*oauth_version=1.0&pesapal_request_data=.*}
306
295
  end
307
296
  end
308
297
 
309
298
  describe '#query_payment_status' do
310
299
 
311
- before :each do
312
- @request = stub_request(:get, /https:\/\/www.pesapal.com\/API\/QueryPaymentStatus\?oauth_consumer_key=.*oauth_nonce=.*oauth_signature=.*oauth_signature_method=HMAC-SHA1&oauth_timestamp.*oauth_version=1.0&pesapal_merchant_reference=.*&pesapal_transaction_tracking_id=.*/)
313
- end
300
+ let(:request) { stub_request(:get, %r{https://www.pesapal.com/API/QueryPaymentStatus\?oauth_consumer_key=.*oauth_nonce=.*oauth_signature=.*oauth_signature_method=HMAC-SHA1&oauth_timestamp.*oauth_version=1.0&pesapal_merchant_reference=.*&pesapal_transaction_tracking_id=.*}) }
314
301
 
315
302
  it 'gets pending payment status' do
316
- @request.to_return(:status => 200, :body => 'pesapal_response_data=PENDING')
317
- expect(@pesapal.query_payment_status('merchant_reference', 'transaction_tracking_id')).to eq('PENDING')
303
+ request.to_return(status: 200, body: 'pesapal_response_data=PENDING')
304
+ expect(pesapal.query_payment_status('merchant_reference', 'transaction_tracking_id')).to eq('PENDING')
318
305
  end
319
306
 
320
307
  it 'gets completed payment status' do
321
- @request.to_return(:status => 200, :body => 'pesapal_response_data=COMPLETED')
322
- expect(@pesapal.query_payment_status('merchant_reference', 'transaction_tracking_id')).to eq('COMPLETED')
308
+ request.to_return(status: 200, body: 'pesapal_response_data=COMPLETED')
309
+ expect(pesapal.query_payment_status('merchant_reference', 'transaction_tracking_id')).to eq('COMPLETED')
323
310
  end
324
311
 
325
312
  it 'gets failed payment status' do
326
- @request.to_return(:status => 200, :body => 'pesapal_response_data=FAILED')
327
- expect(@pesapal.query_payment_status('merchant_reference', 'transaction_tracking_id')).to eq('FAILED')
313
+ request.to_return(status: 200, body: 'pesapal_response_data=FAILED')
314
+ expect(pesapal.query_payment_status('merchant_reference', 'transaction_tracking_id')).to eq('FAILED')
328
315
  end
329
316
 
330
317
  it 'gets invalid payment status' do
331
- @request.to_return(:status => 200, :body => 'pesapal_response_data=INVALID')
332
- expect(@pesapal.query_payment_status('merchant_reference', 'transaction_tracking_id')).to eq('INVALID')
318
+ request.to_return(status: 200, body: 'pesapal_response_data=INVALID')
319
+ expect(pesapal.query_payment_status('merchant_reference', 'transaction_tracking_id')).to eq('INVALID')
333
320
  end
334
321
  end
335
322
 
336
323
  describe '#query_payment_details' do
337
324
 
338
- before :each do
339
- @request = stub_request(:get, /https:\/\/www.pesapal.com\/API\/QueryPaymentDetails\?oauth_consumer_key=.*oauth_nonce=.*oauth_signature=.*oauth_signature_method=HMAC-SHA1&oauth_timestamp.*oauth_version=1.0&pesapal_merchant_reference=.*&pesapal_transaction_tracking_id=.*/)
340
- end
325
+ let(:request) { stub_request(:get, %r{https://www.pesapal.com/API/QueryPaymentDetails\?oauth_consumer_key=.*oauth_nonce=.*oauth_signature=.*oauth_signature_method=HMAC-SHA1&oauth_timestamp.*oauth_version=1.0&pesapal_merchant_reference=.*&pesapal_transaction_tracking_id=.*}) }
341
326
 
342
327
  it 'gets pending payment details' do
343
- @request.to_return(:status => 200, :body => 'pesapal_response_data=transaction_tracking_id,payment_method,payment_status,merchant_reference')
344
- expect(@pesapal.query_payment_details('merchant_reference', 'transaction_tracking_id')).to eq({ :method => 'payment_method',
345
- :status => 'payment_status',
346
- :merchant_reference => 'merchant_reference',
347
- :transaction_tracking_id => 'transaction_tracking_id'
348
- })
328
+ request.to_return(status: 200, body: 'pesapal_response_data=transaction_tracking_id,payment_method,payment_status,merchant_reference')
329
+ expect(pesapal.query_payment_details('merchant_reference', 'transaction_tracking_id')).to eq(method: 'payment_method',
330
+ status: 'payment_status',
331
+ merchant_reference: 'merchant_reference',
332
+ transaction_tracking_id: 'transaction_tracking_id'
333
+ )
349
334
  end
350
335
  end
351
336
 
352
337
  describe '#ipn_listener' do
353
338
 
354
- before :each do
355
- @request = stub_request(:get, /https:\/\/www.pesapal.com\/API\/QueryPaymentStatus\?oauth_consumer_key=.*oauth_nonce=.*oauth_signature=.*oauth_signature_method=HMAC-SHA1&oauth_timestamp.*oauth_version=1.0&pesapal_merchant_reference=.*&pesapal_transaction_tracking_id=.*/)
356
- end
339
+ let(:request) { stub_request(:get, %r{https://www.pesapal.com/API/QueryPaymentStatus\?oauth_consumer_key=.*oauth_nonce=.*oauth_signature=.*oauth_signature_method=HMAC-SHA1&oauth_timestamp.*oauth_version=1.0&pesapal_merchant_reference=.*&pesapal_transaction_tracking_id=.*}) }
357
340
 
358
341
  it 'gets ipn response for pending status' do
359
- @request.to_return(:status => 200, :body => 'pesapal_response_data=PENDING')
360
- expect(@pesapal.ipn_listener('CHANGE', 'merchant_reference', 'transaction_tracking_id')).to eq({:status => 'PENDING', :response => nil})
342
+ request.to_return(status: 200, body: 'pesapal_response_data=PENDING')
343
+ expect(pesapal.ipn_listener('CHANGE', 'merchant_reference', 'transaction_tracking_id')).to eq(status: 'PENDING', response: nil)
361
344
  end
362
345
 
363
346
  it 'gets ipn response for completed status' do
364
- @request.to_return(:status => 200, :body => 'pesapal_response_data=COMPLETED')
365
- expect(@pesapal.ipn_listener('CHANGE', 'merchant_reference', 'transaction_tracking_id')).to eq({:status => 'COMPLETED', :response => 'pesapal_notification_type=CHANGE&pesapal_transaction_tracking_id=transaction_tracking_id&pesapal_merchant_reference=merchant_reference'})
347
+ request.to_return(status: 200, body: 'pesapal_response_data=COMPLETED')
348
+ expect(pesapal.ipn_listener('CHANGE', 'merchant_reference', 'transaction_tracking_id')).to eq(status: 'COMPLETED', response: 'pesapal_notification_type=CHANGE&pesapal_transaction_tracking_id=transaction_tracking_id&pesapal_merchant_reference=merchant_reference')
366
349
  end
367
350
 
368
351
  it 'gets ipn response for failed status' do
369
- @request.to_return(:status => 200, :body => 'pesapal_response_data=FAILED')
370
- expect(@pesapal.ipn_listener('CHANGE', 'merchant_reference', 'transaction_tracking_id')).to eq({:status => 'FAILED', :response => 'pesapal_notification_type=CHANGE&pesapal_transaction_tracking_id=transaction_tracking_id&pesapal_merchant_reference=merchant_reference'})
352
+ request.to_return(status: 200, body: 'pesapal_response_data=FAILED')
353
+ expect(pesapal.ipn_listener('CHANGE', 'merchant_reference', 'transaction_tracking_id')).to eq(status: 'FAILED', response: 'pesapal_notification_type=CHANGE&pesapal_transaction_tracking_id=transaction_tracking_id&pesapal_merchant_reference=merchant_reference')
371
354
  end
372
355
 
373
356
  it 'gets ipn response for invalid status' do
374
- @request.to_return(:status => 200, :body => 'pesapal_response_data=INVALID')
375
- expect(@pesapal.ipn_listener('CHANGE', 'merchant_reference', 'transaction_tracking_id')).to eq({:status => 'INVALID', :response => nil})
357
+ request.to_return(status: 200, body: 'pesapal_response_data=INVALID')
358
+ expect(pesapal.ipn_listener('CHANGE', 'merchant_reference', 'transaction_tracking_id')).to eq(status: 'INVALID', response: nil)
376
359
  end
377
360
  end
378
361
  end
379
-
380
- private
381
-
382
- def default_credentials
383
- { :callback_url => 'http://0.0.0.0:3000/pesapal/callback',
384
- :consumer_key => '<YOUR_CONSUMER_KEY>',
385
- :consumer_secret => '<YOUR_CONSUMER_SECRET>'
386
- }
387
- end
388
-
389
- def demo_endpoints
390
- { :postpesapaldirectorderv4 => 'http://demo.pesapal.com/API/PostPesapalDirectOrderV4',
391
- :querypaymentstatus=>'http://demo.pesapal.com/API/QueryPaymentStatus',
392
- :querypaymentdetails=>'http://demo.pesapal.com/API/QueryPaymentDetails'
393
- }
394
- end
395
-
396
- def production_endpoints
397
- { :postpesapaldirectorderv4 => 'https://www.pesapal.com/API/PostPesapalDirectOrderV4',
398
- :querypaymentstatus=>'https://www.pesapal.com/API/QueryPaymentStatus',
399
- :querypaymentdetails=>'https://www.pesapal.com/API/QueryPaymentDetails'
400
- }
401
- end
402
362
  end
@@ -3,6 +3,7 @@
3
3
  require 'coveralls'
4
4
  Coveralls.wear!
5
5
 
6
+ require 'faker'
6
7
  require 'webmock/rspec'
7
8
  require_relative '../lib/pesapal'
8
9
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pesapal
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.6
4
+ version: 1.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Job King'ori Maina
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-04-26 00:00:00.000000000 Z
11
+ date: 2014-10-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -38,6 +38,20 @@ dependencies:
38
38
  - - '>='
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: faker
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: rake
43
57
  requirement: !ruby/object:Gem::Requirement
@@ -66,6 +80,20 @@ dependencies:
66
80
  - - '>='
67
81
  - !ruby/object:Gem::Version
68
82
  version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rubocop
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
69
97
  - !ruby/object:Gem::Dependency
70
98
  name: webmock
71
99
  requirement: !ruby/object:Gem::Requirement
@@ -103,10 +131,13 @@ extra_rdoc_files: []
103
131
  files:
104
132
  - .coveralls.yml
105
133
  - .gitignore
134
+ - .hound.yml
106
135
  - .rspec
136
+ - .rubocop.yml
107
137
  - .travis.yml
108
138
  - .yardopts
109
139
  - CHANGELOG.md
140
+ - CONTRIBUTING.md
110
141
  - Gemfile
111
142
  - LICENSE.md
112
143
  - README.md
@@ -137,7 +168,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
137
168
  requirements:
138
169
  - - '>='
139
170
  - !ruby/object:Gem::Version
140
- version: 1.9.2
171
+ version: 1.9.3
141
172
  required_rubygems_version: !ruby/object:Gem::Requirement
142
173
  requirements:
143
174
  - - '>='