pesapal 1.8.0 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -13
- data/.gitignore +5 -15
- data/.rubocop.yml +18 -10
- data/.travis.yml +6 -4
- data/CHANGELOG.md +12 -1
- data/LICENSE.md +1 -1
- data/README.md +10 -15
- data/docs/.ruby-version +1 -0
- data/docs/Gemfile +4 -0
- data/docs/README.md +10 -0
- data/docs/_config.yml +27 -0
- data/docs/_includes/google-analytics.html +8 -0
- data/docs/_layouts/default.html +53 -0
- data/docs/assets/javascripts/scale.fix.js +17 -0
- data/docs/assets/stylesheets/pygment_trac.css +69 -0
- data/docs/assets/stylesheets/styles.css +287 -0
- data/docs/favicon.ico +0 -0
- data/docs/index.md +302 -0
- data/lib/pesapal.rb +0 -2
- data/lib/pesapal/helper/details.rb +5 -3
- data/lib/pesapal/helper/post.rb +5 -3
- data/lib/pesapal/helper/status.rb +8 -7
- data/lib/pesapal/merchant.rb +55 -141
- data/lib/pesapal/oauth.rb +13 -11
- data/lib/pesapal/version.rb +1 -1
- data/pesapal.gemspec +9 -4
- data/spec/pesapal_merchant_spec.rb +25 -86
- metadata +68 -34
- data/lib/generators/pesapal/install_generator.rb +0 -21
- data/lib/generators/templates/README.md +0 -21
- data/lib/generators/templates/pesapal.yml +0 -9
- data/lib/pesapal/railtie.rb +0 -26
data/docs/favicon.ico
ADDED
Binary file
|
data/docs/index.md
ADDED
@@ -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
|
data/lib/pesapal.rb
CHANGED
@@ -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
|
-
|
47
|
-
|
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:
|
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
|
data/lib/pesapal/helper/post.rb
CHANGED
@@ -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
|
-
|
166
|
+
|
167
|
+
{
|
168
|
+
oauth_callback: callback_url,
|
167
169
|
oauth_consumer_key: consumer_key,
|
168
|
-
oauth_nonce:
|
170
|
+
oauth_nonce: timestamp + Pesapal::Oauth.generate_nonce(12),
|
169
171
|
oauth_signature_method: 'HMAC-SHA1',
|
170
|
-
oauth_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 = {
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
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
|
data/lib/pesapal/merchant.rb
CHANGED
@@ -64,7 +64,7 @@ module Pesapal
|
|
64
64
|
|
65
65
|
private
|
66
66
|
|
67
|
-
attr_reader :
|
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
|
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`.
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
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(
|
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
|
-
"#{
|
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(
|
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 "#{
|
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
|
-
{
|
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(
|
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 "#{
|
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] =
|
398
|
-
when 'FAILED' then output[:response] =
|
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
|
-
|
407
|
-
|
408
|
-
|
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
|
-
|
333
|
+
def api_endpoint
|
334
|
+
'https://' + api_domain
|
420
335
|
end
|
421
336
|
|
422
|
-
|
423
|
-
|
424
|
-
|
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
|
-
|
341
|
+
def querypaymentstatus_url
|
342
|
+
api_endpoint + '/API/QueryPaymentStatus'
|
343
|
+
end
|
431
344
|
|
432
|
-
|
345
|
+
def querypaymentdetails_url
|
346
|
+
api_endpoint + '/API/QueryPaymentDetails'
|
433
347
|
end
|
434
348
|
end
|
435
349
|
end
|