pesapal 1.8.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Binary file
@@ -0,0 +1,302 @@
1
+ ---
2
+ title: Get
3
+ layout: default
4
+ ---
5
+
6
+ Synopsis
7
+ --------
8
+
9
+ Basically it's a gem that makes it easy to integrate your app with
10
+ [Pesapal's][24] payment gateway. It Handles all the [oAuth stuff][1] abstracting
11
+ any direct interaction with the API endpoints so that you can focus on what
12
+ matters. _Building awesome_.
13
+
14
+ All this with no 3rd party oAuth library dependencies, it handles all the oAuth
15
+ flows on its own so your app is one dependency less.
16
+
17
+ The gem should be [up on RubyGems.org][7], it's [accompanying API reference
18
+ here][13], the [CHANGELOG here][21] and [all the releases here][12].
19
+
20
+ Ps: This documentation is based off `v2.0.0`. For older versions, rely on the
21
+ version specific documentation. You can find the link on [RubyGems.org][7].
22
+
23
+ Installation
24
+ ------------
25
+
26
+ Add this line to your application's Gemfile:
27
+
28
+ gem 'pesapal'
29
+
30
+ And then execute:
31
+
32
+ $ bundle
33
+
34
+ Or install it yourself as:
35
+
36
+ $ gem install pesapal
37
+
38
+ Usage
39
+ -----
40
+
41
+ ### Initialization
42
+
43
+ Initialize Pesapal object and choose the environment, there are two environments;
44
+ `:development` and `:production`. They determine if the code will interact
45
+ with the testing or the live Pesapal API.
46
+
47
+ ```ruby
48
+ # Sets environment to :development
49
+ pesapal = Pesapal::Merchant.new(:development)
50
+
51
+ # Sets environment to :production
52
+ pesapal = Pesapal::Merchant.new(:production)
53
+ ```
54
+
55
+ ### Configuration
56
+
57
+ Use a hash as shown below (please note that Pesapal provides different keys for
58
+ different environments, make sure you choose the right one).
59
+
60
+ ```ruby
61
+ pesapal.config = {
62
+ callback_url: 'http://0.0.0.0:3000/pesapal/callback',
63
+ consumer_key: '<YOUR_CONSUMER_KEY>',
64
+ consumer_secret: '<YOUR_CONSUMER_SECRET>'
65
+ }
66
+ ```
67
+
68
+ ### Posting An Order
69
+
70
+ Once you've finalized the configuration, set up the order details in a hash as
71
+ shown in the example below ... all keys **MUST** be present. If there's one that
72
+ you wish to ignore just leave it with a blank string but make sure it's included
73
+ e.g. the phonenumber.
74
+
75
+ ```ruby
76
+ pesapal.order_details = {
77
+ amount: 1000,
78
+ description: 'this is the transaction description',
79
+ type: 'MERCHANT',
80
+ reference: '808-707-606',
81
+ first_name: 'Swaleh',
82
+ last_name: 'Mdoe',
83
+ email: 'user@example.com',
84
+ phonenumber: '+254722222222',
85
+ currency: 'KES'
86
+ }
87
+ ```
88
+
89
+ Then generate the transaction url as below. In the example, the value is
90
+ assigned to the variable `order_url` which you can pass on to the templating
91
+ system of your choice to generate an iframe. Please note that this method
92
+ utilizes all that information set in the previous steps in generating the url so
93
+ it's important that it's the last step in the post order process.
94
+
95
+ ```ruby
96
+ # generate transaction url
97
+ order_url = pesapal.generate_order_url
98
+
99
+ # order_url will a string with the url example;
100
+ # http://demo.pesapal.com/API/PostPesapalDirectOrderV4?oauth_callback=http%3A%2F%2F1.2.3.4%3A3000%2Fpesapal%2Fcallback&oauth_consumer_key=A9MXocJiHK1P4w0M%2F%2FYzxgIVMX557Jt4&oauth_nonce=13804335543pDXs4q3djsy&oauth_signature=BMmLR0AVInfoBI9D4C38YDA9eSM%3D&oauth_signature_method=HMAC-SHA1&oauth_timestamp=1380433554&oauth_version=1.0&pesapal_request_data=%26lt%3B%3Fxml%20version%3D%26quot%3B1.0%26quot%3B%20encoding%3D%26quot%3Butf-8%26quot%3B%3F%26gt%3B%26lt%3BPesapalDirectOrderInfo%20xmlns%3Axsi%3D%26quot%3Bhttp%3A%2F%2Fwww.w3.org%2F2001%2FXMLSchema-instance%26quot%3B%20xmlns%3Axsd%3D%26quot%3Bhttp%3A%2F%2Fwww.w3.org%2F2001%2FXMLSchema%26quot%3B%20Amount%3D%26quot%3B1000%26quot%3B%20Description%3D%26quot%3Bthis%20is%20the%20transaction%20description%26quot%3B%20Type%3D%26quot%3BMERCHANT%26quot%3B%20Reference%3D%26quot%3B808%26quot%3B%20FirstName%3D%26quot%3BSwaleh%26quot%3B%20LastName%3D%26quot%3BMdoe%26quot%3B%20Email%3D%26quot%3Bj%40kingori.co%26quot%3B%20PhoneNumber%3D%26quot%3B%2B254722222222%26quot%3B%20xmlns%3D%26quot%3Bhttp%3A%2F%2Fwww.pesapal.com%26quot%3B%20%2F%26gt%3B
101
+ ```
102
+
103
+ _Ps: Please note the `:callback_url` value in the `pesapal.config` hash ...
104
+ after the user successfully posts the order, the response will be sent to this
105
+ url. Refer to [official Pesapal Step-By-Step integration guide][18] for more
106
+ details._
107
+
108
+ ### Querying Payment Status
109
+
110
+ Use this to query the status of the transaction. When a transaction is posted to
111
+ Pesapal, it may be in a PENDING, COMPLETED, FAILED or INVALID state. If the
112
+ transaction is PENDING, the payment may complete or fail at a later stage.
113
+
114
+ Both the unique merchant reference generated by your system (compulsory) and the
115
+ pesapal transaction tracking id (optional) are input parameters to this method
116
+ but if you don't ensure that the merchant reference is unique for each order on
117
+ your system, you may get INVALID as the response. Because of this, it is
118
+ recommended that you provide both the merchant reference and transaction
119
+ tracking id as parameters to guarantee uniqueness.
120
+
121
+ ```ruby
122
+ # option 1: using merchant reference only
123
+ payment_status = pesapal.query_payment_status("<MERCHANT_REFERENCE>")
124
+
125
+ # option 2: using merchant reference and transaction id (recommended)
126
+ payment_status = pesapal.query_payment_status("<MERCHANT_REFERENCE>","<TRANSACTION_ID>")
127
+ ```
128
+
129
+ ### Querying Payment Details
130
+
131
+ Same as querying payment status above, but the return value contains more
132
+ information (and is a hash as opposed to a string).
133
+
134
+ ```ruby
135
+ # pass in merchant reference and transaction id
136
+ payment_details = pesapal.query_payment_details("<MERCHANT_REFERENCE>","<TRANSACTION_ID>")
137
+ ```
138
+
139
+ The result is a hash that looks something like this ...
140
+
141
+ ```ruby
142
+ {
143
+ method: "<PAYMENT_METHOD>",
144
+ status: "<PAYMENT_STATUS>",
145
+ merchant_reference: "<MERCHANT_REFERENCE>",
146
+ transaction_tracking_id: "<TRANSACTION_ID>"
147
+ }
148
+ ```
149
+
150
+ ### IPN Listening
151
+
152
+ Use the `ipn_listener` method to listen to Pesapal IPN calls to easily create an
153
+ appropriate response, example below.
154
+
155
+ ```ruby
156
+ # pass in the notification type, merchant reference and transaction id
157
+ response_to_ipn = pesapal.ipn_listener("<NOTIFICATION_TYPE>", "<MERCHANT_REFERENCE>","<TRANSACTION_ID>")
158
+ ```
159
+
160
+ The variable, `response_to_ipn`, now holds a response as the one shown below.
161
+ Using the status you can customise any actions (e.g. database inserts and
162
+ updates) and finally, it's up to you to send the `:response` back to pesapal. The
163
+ hard part is done for you.
164
+
165
+ ```ruby
166
+ {
167
+ status: "<PAYMENT_STATUS>",
168
+ response: "<IPN_RESPONSE>"
169
+ }
170
+ ```
171
+
172
+ _Ps: Refer to Pesapal official documentation to make sure you understand what
173
+ data Pesapal sends to IPN and what result they expect back._
174
+
175
+
176
+ Support & Issues
177
+ ----------------
178
+
179
+ In case you are having any issues using this gem please **_do not_** email me
180
+ directly, I'd rather you [submit new issues (and even requests) here][23] ...
181
+ obviously after [checking if the issue has already been raised and closed][6].
182
+ This way, other people get to share in the conversation that would have been
183
+ private and out of their reach.
184
+
185
+
186
+ Contributing
187
+ ------------
188
+
189
+ ### To gem's code
190
+
191
+ Submitting a pull request;
192
+
193
+ 1. [Fork the repository][fork].
194
+ 2. [Create a topic branch][branch] (`git checkout -b BRANCH_NAME`).
195
+ 3. [Install bundler][bundler].
196
+ 4. Check that tests pass with `rspec spec`.
197
+ 5. Write a failing test to capture existing bug or lack of feature.
198
+ 6. Run `rspec spec` to verify that test fails.
199
+ 7. Implement your feature or bug fix.
200
+ 8. Ensure tests pass.
201
+ 9. If it's a new feature or a bug fix, please add an entry to the CHANGELOG file.
202
+ 10. Check code style violations using [Rubocop][rubocop].
203
+ 11. Add a commit (`git commit -am 'AWESOME COMMIT MESSAGE'`).
204
+ 12. Push your changes to the branch (`git push origin BRANCH_NAME`).
205
+ 13. [Submit a pull request.][pr]
206
+ 14. You will get some feedback and may need to push additional commits
207
+ with more fixes to the same branch; this will update your pull request
208
+ automatically.
209
+
210
+ [branch]: http://git-scm.com/book/en/Git-Branching-Branching-Workflows#Topic-Branches
211
+ [bundler]: http://bundler.io
212
+ [fork]: https://help.github.com/articles/fork-a-repo/
213
+ [pr]: https://help.github.com/articles/using-pull-requests
214
+ [rubocop]: https://github.com/bbatsov/rubocop
215
+
216
+
217
+ ### To gem's documentation
218
+
219
+ Gem documentation is of two types, feel free to contribute to any;
220
+
221
+ 1. Gem home page at [itskingori.github.io/pesapal-gem][26] _(simple step-by-step)_
222
+ 2. API documetation generated by [Yard][25] _(very comprehensive)_
223
+
224
+ Gem home page is built on [Jekyll][27], which is a fun and easy to use static
225
+ site generator and [hosted on GitHub Pages][30]. The code is in the `docs/`
226
+ folder if you want to have a peek.
227
+
228
+ Preview the gem API documentation locally by installing [Yard][25] (`gem install
229
+ yard`) and call `$ yard server` to set up a local documentation server usually
230
+ running on `http://0.0.0.0:8808`. The result should be similar to the API
231
+ documention up on [rubydoc.info/gems/pesapal][13].
232
+
233
+ _Ps: If you've written code and can't figure out why they aren't passing (or if
234
+ you've written your own tests ... just send a pull a request. We can then do a
235
+ [code review][32])_.
236
+
237
+
238
+ Testing
239
+ -------
240
+
241
+ Tests run [RSpec][31] which is a Behaviour-Driven Development tool. To run
242
+ tests, call;
243
+
244
+ ```bash
245
+ $ bundle exec rspec spec
246
+ ```
247
+
248
+
249
+ References
250
+ ----------
251
+
252
+ * [oAuth 1.0 Spec][1]
253
+ * [Developing a RubyGem using Bundler][2]
254
+ * [RailsGuides][20]
255
+ * [Make your own gem][3]
256
+ * [Getting started with RSpec][33]
257
+ * [Pesapal API Reference (Official)][4]
258
+ * [Pesapal Step-By-Step Reference (Official)][18]
259
+ * [Pesapal PHP API Reference (Unofficial)][5]
260
+
261
+
262
+ License
263
+ -------
264
+
265
+ [King'ori J. Maina][10] © 2013-{{ 'now' | date: "%Y" }}. The [MIT License bundled therein][11] is a
266
+ permissive license that is short and to the point. It lets people do anything
267
+ they want as long as they provide attribution and waive liability.
268
+
269
+
270
+ [1]: http://oauth.net/core/1.0/
271
+ [2]: https://github.com/radar/guides/blob/master/gem-development.md
272
+ [3]: http://guides.rubygems.org/make-your-own-gem/
273
+ [4]: http://developer.pesapal.com/how-to-integrate/api-reference
274
+ [5]: https://github.com/itskingori/pesapal-php#pesapal-php-api-reference-unofficial
275
+ [6]: https://github.com/itskingori/pesapal-gem/issues?state=closed
276
+ [7]: https://rubygems.org/gems/pesapal
277
+ [8]: https://github.com/itskingori/pesapal-gem/fork
278
+ [9]: https://github.com/itskingori/pesapal-gem#contributing--testing
279
+ [10]: http://kingori.co/
280
+ [11]: https://raw.githubusercontent.com/itskingori/pesapal-gem/master/LICENSE.txt
281
+ [12]: https://github.com/itskingori/pesapal-gem/releases/
282
+ [13]: http://rubydoc.info/gems/pesapal/frames/file/README.md
283
+ [14]: https://github.com/itskingori/mo
284
+ [15]: https://github.com/itskingori/mo/tree/master/convention#-convention
285
+ [16]: http://kingori.co/articles/2013/09/modus-operandi/
286
+ [17]: https://github.com/itskingori/pesapal-gem/pulls
287
+ [18]: http://developer.pesapal.com/how-to-integrate/step-by-step
288
+ [19]: https://github.com/itskingori/pesapal-gem/graphs/contributors
289
+ [20]: http://guides.rubyonrails.org/
290
+ [21]: https://raw.githubusercontent.com/itskingori/pesapal-gem/master/CHANGELOG.md
291
+ [22]: https://travis-ci.org/itskingori/pesapal-gem/pull_requests
292
+ [23]: https://github.com/itskingori/pesapal-gem/issues/new
293
+ [24]: https://www.pesapal.com/
294
+ [25]: http://yardoc.org/
295
+ [26]: https://itskingori.github.io/pesapal-gem
296
+ [27]: http://jekyllrb.com/
297
+ [28]: http://jekyllrb.com/docs/home/
298
+ [29]: https://github.com/itskingori/pesapal-gem/tree/gh-pages
299
+ [30]: https://pages.github.com/
300
+ [31]: https://relishapp.com/rspec/
301
+ [32]: http://en.wikipedia.org/wiki/Code_review
302
+ [33]: https://relishapp.com/rspec/docs/gettingstarted
@@ -7,5 +7,3 @@ require 'pesapal/helper/status'
7
7
  require 'pesapal/merchant'
8
8
  require 'pesapal/oauth'
9
9
  require 'pesapal/version'
10
-
11
- require 'pesapal/railtie' if defined?(Rails)
@@ -43,10 +43,12 @@ module Pesapal
43
43
  # query parameters and the `oauth_signature` itself.
44
44
  def self.set_parameters(consumer_key, merchant_reference, transaction_tracking_id)
45
45
  timestamp = Time.now.to_i.to_s
46
- { oauth_consumer_key: consumer_key,
47
- oauth_nonce: "#{timestamp}" + Pesapal::Oauth.generate_nonce(12),
46
+
47
+ {
48
+ oauth_consumer_key: consumer_key,
49
+ oauth_nonce: timestamp + Pesapal::Oauth.generate_nonce(12),
48
50
  oauth_signature_method: 'HMAC-SHA1',
49
- oauth_timestamp: "#{timestamp}",
51
+ oauth_timestamp: timestamp,
50
52
  oauth_version: '1.0',
51
53
  pesapal_merchant_reference: merchant_reference,
52
54
  pesapal_transaction_tracking_id: transaction_tracking_id
@@ -163,11 +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,
166
+
167
+ {
168
+ oauth_callback: callback_url,
167
169
  oauth_consumer_key: consumer_key,
168
- oauth_nonce: "#{timestamp}" + Pesapal::Oauth.generate_nonce(12),
170
+ oauth_nonce: timestamp + Pesapal::Oauth.generate_nonce(12),
169
171
  oauth_signature_method: 'HMAC-SHA1',
170
- oauth_timestamp: "#{timestamp}",
172
+ oauth_timestamp: timestamp,
171
173
  oauth_version: '1.0',
172
174
  pesapal_request_data: post_xml
173
175
  }
@@ -39,13 +39,14 @@ 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
48
- }
42
+ params = {
43
+ oauth_consumer_key: consumer_key,
44
+ oauth_nonce: timestamp + Pesapal::Oauth.generate_nonce(12),
45
+ oauth_signature_method: 'HMAC-SHA1',
46
+ oauth_timestamp: timestamp,
47
+ oauth_version: '1.0',
48
+ pesapal_merchant_reference: merchant_reference
49
+ }
49
50
  params[:pesapal_transaction_tracking_id] = transaction_tracking_id unless transaction_tracking_id.nil?
50
51
  params
51
52
  end
@@ -64,7 +64,7 @@ module Pesapal
64
64
 
65
65
  private
66
66
 
67
- attr_reader :api_domain, :api_endpoints, :env
67
+ attr_reader :env
68
68
 
69
69
  def params
70
70
  @params ||= nil
@@ -87,71 +87,22 @@ module Pesapal
87
87
  # will interact with the testing or the live Pesapal API. Like so ...
88
88
  #
89
89
  # ```ruby
90
- # # Sets environment intelligently to 'Rails.env' (if Rails) or :development (if non-Rails)
91
- # pesapal = Pesapal::Merchant.new
92
- #
93
- # # Sets environment to :development
90
+ # # Sets environment to :development explicitly
94
91
  # pesapal = Pesapal::Merchant.new(:development)
95
92
  #
96
93
  # # Sets environment to :production
97
94
  # pesapal = Pesapal::Merchant.new(:production)
98
95
  # ```
99
96
  #
100
- # A few things to note about the constructor as it behaves differently
101
- # depending on the context within which it is called i.e. _Rails_ app vs
102
- # _non-Rails_ app ...
103
- #
104
- # ### Case 1: Rails app
105
- #
106
- # The constructor attempts to set configuration details that should be
107
- # available at runtime from `Rails.application.config.pesapal_credentials`.
108
- # This contains values loaded at application start from a YAML file located
109
- # at `config/pesapal.yml` which typically looks like this:
110
- #
111
- # ```yaml
112
- # development:
113
- # callback_url: 'http://0.0.0.0:3000/pesapal/callback'
114
- # consumer_key: '<YOUR_DEV_CONSUMER_KEY>'
115
- # consumer_secret: '<YOUR_DEV_CONSUMER_SECRET>'
116
- #
117
- # production:
118
- # callback_url: 'http://1.2.3.4:3000/pesapal/callback'
119
- # consumer_key: '<YOUR_PROD_CONSUMER_KEY>'
120
- # consumer_secret: '<YOUR_PROD_CONSUMER_SECRET>'
121
- # ```
122
- #
123
- # The appropriate credentials are picked and set to {#config} instance
124
- # attribute depending on set environment. The setting of environment is
125
- # explained above. It's worth nothing that if for some reason the YAML file
126
- # could not be read, then it fallbacks to setting {#config} instance
127
- # attribute with default values. The exact definition of default values is
128
- # shown below.
129
- #
130
- # ### Case 2: Non-Rails app
131
- #
132
- # Since (and if) no predefined configuration files are available, the
133
- # constructor sets the {#config} instance attribute up with default values
134
- # as shown below:
135
- #
136
- # ```
137
- # { :callback_url => 'http://0.0.0.0:3000/pesapal/callback',
138
- # :consumer_key => '<YOUR_CONSUMER_KEY>',
139
- # :consumer_secret => '<YOUR_CONSUMER_SECRET>'
140
- # }
141
- # ```
142
- #
143
- # @note You can change the environment at runtime using {#change_env}
144
- #
145
97
  # @param env [Symbol] the environment we want to use i.e. `:development` or
146
- # `:production`. Leaving it blank sets environment intelligently to
147
- # `Rails.env` (if Rails) or `:development` (if non-Rails).
148
- def initialize(env = false)
149
- change_env env
150
- if defined?(Rails)
151
- configure Rails.application.config.pesapal_credentials
152
- else
153
- configure
154
- end
98
+ # `:production`.
99
+ def initialize(env = :development)
100
+ @env = env.to_s.downcase
101
+ @config = {
102
+ callback_url: 'http://0.0.0.0:3000/pesapal/callback',
103
+ consumer_key: '<YOUR_CONSUMER_KEY>',
104
+ consumer_secret: '<YOUR_CONSUMER_SECRET>'
105
+ }
155
106
  end
156
107
 
157
108
  # Generate URL that's used to post a transaction to PesaPal.
@@ -185,17 +136,20 @@ module Pesapal
185
136
  # build xml with input data, the format is standard so no editing is
186
137
  # required
187
138
  @post_xml = Pesapal::Helper::Post.generate_post_xml @order_details
188
-
189
139
  # initialize setting of @params (oauth_signature left empty)
190
140
  @params = Pesapal::Helper::Post.set_parameters(@config[:callback_url], @config[:consumer_key], @post_xml)
191
-
192
141
  # 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)
194
-
142
+ @params[:oauth_signature] = Pesapal::Oauth.generate_oauth_signature(
143
+ 'GET',
144
+ postpesapaldirectorderv4_url,
145
+ @params,
146
+ @config[:consumer_secret],
147
+ @token_secret
148
+ )
195
149
  # change params (with signature) to a query string
196
150
  query_string = Pesapal::Oauth.generate_encoded_params_query_string @params
197
151
 
198
- "#{@api_endpoints[:postpesapaldirectorderv4]}?#{query_string}"
152
+ "#{postpesapaldirectorderv4_url}?#{query_string}"
199
153
  end
200
154
 
201
155
  # Same as {#query_payment_status}, but additional information is returned in
@@ -237,15 +191,19 @@ module Pesapal
237
191
  def query_payment_details(merchant_reference, transaction_tracking_id)
238
192
  # initialize setting of @params (oauth_signature left empty)
239
193
  @params = Pesapal::Helper::Details.set_parameters(@config[:consumer_key], merchant_reference, transaction_tracking_id)
240
-
241
194
  # 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)
243
-
195
+ @params[:oauth_signature] = Pesapal::Oauth.generate_oauth_signature(
196
+ 'GET',
197
+ querypaymentdetails_url,
198
+ @params,
199
+ @config[:consumer_secret],
200
+ @token_secret
201
+ )
244
202
  # change params (with signature) to a query string
245
203
  query_string = Pesapal::Oauth.generate_encoded_params_query_string @params
246
204
 
247
205
  # get status response
248
- uri = URI.parse "#{@api_endpoints[:querypaymentdetails]}?#{query_string}"
206
+ uri = URI.parse "#{querypaymentdetails_url}?#{query_string}"
249
207
  http = Net::HTTP.new(uri.host, uri.port)
250
208
  http.use_ssl = true
251
209
  http.verify_mode = OpenSSL::SSL::VERIFY_PEER
@@ -253,7 +211,8 @@ module Pesapal
253
211
  response = CGI.parse response.body
254
212
  response = response['pesapal_response_data'][0].split(',')
255
213
 
256
- { method: response[1],
214
+ {
215
+ method: response[1],
257
216
  status: response[2],
258
217
  merchant_reference: response[3],
259
218
  transaction_tracking_id: response[0]
@@ -290,15 +249,19 @@ module Pesapal
290
249
  def query_payment_status(merchant_reference, transaction_tracking_id = nil)
291
250
  # initialize setting of @params (oauth_signature left empty)
292
251
  @params = Pesapal::Helper::Status.set_parameters(@config[:consumer_key], merchant_reference, transaction_tracking_id)
293
-
294
252
  # generate oauth signature and add signature to the request parameters
295
- @params[:oauth_signature] = Pesapal::Oauth.generate_oauth_signature('GET', @api_endpoints[:querypaymentstatus], @params, @config[:consumer_secret], @token_secret)
296
-
253
+ @params[:oauth_signature] = Pesapal::Oauth.generate_oauth_signature(
254
+ 'GET',
255
+ querypaymentstatus_url,
256
+ @params,
257
+ @config[:consumer_secret],
258
+ @token_secret
259
+ )
297
260
  # change params (with signature) to a query string
298
261
  query_string = Pesapal::Oauth.generate_encoded_params_query_string @params
299
262
 
300
263
  # get status response
301
- uri = URI.parse "#{@api_endpoints[:querypaymentstatus]}?#{query_string}"
264
+ uri = URI.parse "#{querypaymentstatus_url}?#{query_string}"
302
265
  http = Net::HTTP.new(uri.host, uri.port)
303
266
  http.use_ssl = true
304
267
  http.verify_mode = OpenSSL::SSL::VERIFY_PEER
@@ -307,50 +270,6 @@ module Pesapal
307
270
  response['pesapal_response_data'][0]
308
271
  end
309
272
 
310
- # Set the environment in use.
311
- #
312
- # Useful especially if you want to change the environment at runtime from
313
- # what was set during initialization in the constructor. It also makes sure
314
- # that we use the appropriate endpoints when making calls to Pesapal. See
315
- # below:
316
- #
317
- # ```
318
- # # endpoint values set if :development
319
- # {
320
- # :postpesapaldirectorderv4 => "http://demo.pesapal.com/API/PostPesapalDirectOrderV4",
321
- # :querypaymentstatus => "http://demo.pesapal.com/API/QueryPaymentStatus",
322
- # :querypaymentdetails => "http://demo.pesapal.com/API/QueryPaymentDetails"
323
- # }
324
- #
325
- # # endpoint values set if :production
326
- # {
327
- # :postpesapaldirectorderv4 => "https://www.pesapal.com/API/PostPesapalDirectOrderV4",
328
- # :querypaymentstatus => "https://www.pesapal.com/API/QueryPaymentStatus",
329
- # :querypaymentdetails => "https://www.pesapal.com/API/QueryPaymentDetails"
330
- # }
331
- # ```
332
- #
333
- # @note For a Rails app, you'd expect that calling this would also flip the
334
- # credentials if there was a YAML file containing both environment
335
- # credentials but that's not the case. It could be something that we can
336
- # add later.
337
- #
338
- # @param env [Symbol] the environment we want to use i.e. :development or
339
- # :production
340
- #
341
- # @return [Hash] contains Pesapal endpoints appropriate for the set
342
- # environment
343
- def change_env(env = false)
344
- env = env.to_s.downcase
345
- if env == 'production'
346
- @env = 'production'
347
- else
348
- @env = 'development'
349
- @env = Rails.env if defined?(Rails)
350
- end
351
- assign_endpoints
352
- end
353
-
354
273
  # Generates the appropriate IPN response depending on the status of the
355
274
  # transaction.
356
275
  #
@@ -393,9 +312,13 @@ module Pesapal
393
312
  status = query_payment_status(merchant_reference, transaction_tracking_id)
394
313
  output = { status: status, response: nil }
395
314
 
315
+ response = "pesapal_notification_type=#{notification_type}"
316
+ response += "&pesapal_transaction_tracking_id=#{transaction_tracking_id}"
317
+ response += "&pesapal_merchant_reference=#{merchant_reference}"
318
+
396
319
  case status
397
- when 'COMPLETED' then output[:response] = "pesapal_notification_type=#{notification_type}&pesapal_transaction_tracking_id=#{transaction_tracking_id}&pesapal_merchant_reference=#{merchant_reference}"
398
- when 'FAILED' then output[:response] = "pesapal_notification_type=#{notification_type}&pesapal_transaction_tracking_id=#{transaction_tracking_id}&pesapal_merchant_reference=#{merchant_reference}"
320
+ when 'COMPLETED' then output[:response] = response
321
+ when 'FAILED' then output[:response] = response
399
322
  end
400
323
 
401
324
  output
@@ -403,33 +326,24 @@ module Pesapal
403
326
 
404
327
  private
405
328
 
406
- # Assign API endpoints depending on the environment.
407
- def assign_endpoints
408
- if @env == 'production'
409
- @api_domain = 'https://www.pesapal.com'
410
- else
411
- @api_domain = 'https://demo.pesapal.com'
412
- end
413
-
414
- @api_endpoints = {}
415
- @api_endpoints[:postpesapaldirectorderv4] = "#{@api_domain}/API/PostPesapalDirectOrderV4"
416
- @api_endpoints[:querypaymentstatus] = "#{@api_domain}/API/QueryPaymentStatus"
417
- @api_endpoints[:querypaymentdetails] = "#{@api_domain}/API/QueryPaymentDetails"
329
+ def api_domain
330
+ @env == 'production' ? 'www.pesapal.com' : 'demo.pesapal.com'
331
+ end
418
332
 
419
- @api_endpoints
333
+ def api_endpoint
334
+ 'https://' + api_domain
420
335
  end
421
336
 
422
- # Configure credentials through hash that passed in (does a little
423
- # processing to remove unwanted data & uses default if nothing is input).
424
- def configure(consumer_details = {})
425
- @config = { callback_url: 'http://0.0.0.0:3000/pesapal/callback',
426
- consumer_key: '<YOUR_CONSUMER_KEY>',
427
- consumer_secret: '<YOUR_CONSUMER_SECRET>'
428
- }
337
+ def postpesapaldirectorderv4_url
338
+ api_endpoint + '/API/PostPesapalDirectOrderV4'
339
+ end
429
340
 
430
- valid_config_keys = @config.keys
341
+ def querypaymentstatus_url
342
+ api_endpoint + '/API/QueryPaymentStatus'
343
+ end
431
344
 
432
- consumer_details.each { |k, v| @config[k.to_sym] = v if valid_config_keys.include? k.to_sym }
345
+ def querypaymentdetails_url
346
+ api_endpoint + '/API/QueryPaymentDetails'
433
347
  end
434
348
  end
435
349
  end