pesapal 1.8.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|