pesapal 0.2.1 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +14 -0
- data/README.md +91 -36
- data/lib/pesapal/merchant/details.rb +24 -0
- data/lib/pesapal/merchant/post.rb +1 -1
- data/lib/pesapal/merchant/status.rb +29 -0
- data/lib/pesapal/merchant.rb +63 -15
- data/lib/pesapal/version.rb +1 -1
- data/lib/pesapal.rb +2 -0
- data/pesapal.gemspec +1 -1
- metadata +3 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2b77c7352914478f5db52c64dd9e5611cd9c8652
|
4
|
+
data.tar.gz: 382a808b6a1d6464587477cd0ab30aa4c6e53b5b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 74576337022966c7ae613394507be8f2a4d1611fee53067430b80ae7d2376a8c34acb21cf933ab6c9f8697c119892c3608b17e9fd4604c59977fea2c6dd4e646
|
7
|
+
data.tar.gz: 35fe01d3f3a0dbe097474e85710e65862f14a041ea5726df5c21ff2f1c13e94796b7ea07036acca4b800f672f034f4572481126939cdd0ea1bc8c680c6c7ea5f
|
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,20 @@
|
|
1
1
|
Changelog
|
2
2
|
=========
|
3
3
|
|
4
|
+
v1.0.0
|
5
|
+
------
|
6
|
+
|
7
|
+
* Automate release date to reduce chances of forgetting to update it
|
8
|
+
* Add new functionality: Query Payment Status
|
9
|
+
* Add new functionality: Query Payment Details
|
10
|
+
* Add `set_mode()` method to enable changing mode at runtime
|
11
|
+
* `api_domain` & `api_endpoints` are now private, use `set_mode` to alter them
|
12
|
+
|
13
|
+
v0.2.1
|
14
|
+
------
|
15
|
+
|
16
|
+
* Fix screwed up rubygem date
|
17
|
+
|
4
18
|
v0.2.0
|
5
19
|
------
|
6
20
|
|
data/README.md
CHANGED
@@ -7,10 +7,10 @@ Make authenticated Pesapal API calls without the fuss! Handles all the [oAuth
|
|
7
7
|
stuff][1] abstracting any direct interaction with the API endpoints so that you
|
8
8
|
can focus on what matters. _Building awesome_.
|
9
9
|
|
10
|
-
This gem
|
11
|
-
|
12
|
-
|
13
|
-
|
10
|
+
This gem, in a nutshell, allows you to easily post an order, query payment
|
11
|
+
status and fetch payment details.
|
12
|
+
|
13
|
+
If you are [feeling generous and want to contribute, feel free][9].
|
14
14
|
|
15
15
|
Submit [issues and requests here][6] and [find all the releases here][12].
|
16
16
|
|
@@ -19,11 +19,6 @@ The gem should be [up on RubyGems.org][7] and it's [accompanying RubyDoc referen
|
|
19
19
|
_Ps: No 3rd party oAuth library dependencies, it handles all the oAuth flows on
|
20
20
|
it's own so your app is one dependency less._
|
21
21
|
|
22
|
-
_Ps 2: We are still at pre-release stage ... target is version 1.0.0 for a
|
23
|
-
public release (suitable for production deployment with the basic functionality
|
24
|
-
in place). As a result always check the documentation carefully on upgrades to
|
25
|
-
mitigate breaking changes._
|
26
|
-
|
27
22
|
|
28
23
|
Installation
|
29
24
|
------------
|
@@ -49,7 +44,13 @@ Usage
|
|
49
44
|
-----
|
50
45
|
|
51
46
|
|
52
|
-
###
|
47
|
+
### Initialization ###
|
48
|
+
|
49
|
+
There are 3 ways to initialize the Pesapal object:
|
50
|
+
|
51
|
+
1. YAML config at `/config/pesapal.yml` (default & recommended)
|
52
|
+
2. YAML config at custom location
|
53
|
+
3. Config hash
|
53
54
|
|
54
55
|
Initialize Pesapal object and choose the mode, there are two modes;
|
55
56
|
`:development` and `:production`. They determine if the code will interact
|
@@ -60,12 +61,18 @@ with the testing or the live Pesapal API.
|
|
60
61
|
pesapal = Pesapal::Merchant.new(:development)
|
61
62
|
```
|
62
63
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
`"#{Rails.root}/config/pesapal.yml"`
|
67
|
-
|
68
|
-
|
64
|
+
####Option 1####
|
65
|
+
|
66
|
+
In the case, the configuration has already been loaded (at application start by
|
67
|
+
initializer) from a YAML file located at `"#{Rails.root}/config/pesapal.yml"` by
|
68
|
+
default. This is the recommended method.
|
69
|
+
|
70
|
+
####Option 2####
|
71
|
+
|
72
|
+
It's also possible to set the configuration details from a YAML file at the
|
73
|
+
location of your choice upon initialization as shown in the example below. This
|
74
|
+
option overrides the default YAML config (explained above) and will be loaded
|
75
|
+
everytime during initialization (which is not a good idea for production).
|
69
76
|
|
70
77
|
```ruby
|
71
78
|
# initiate pesapal object set to development mode and use the YAML file found at
|
@@ -73,6 +80,29 @@ starts and not everytime an object is initialized.
|
|
73
80
|
pesapal = Pesapal::Merchant.new(:development, "<PATH_TO_YAML_FILE>")
|
74
81
|
```
|
75
82
|
|
83
|
+
####Option 3####
|
84
|
+
|
85
|
+
If you wish not to use the YAML config method or the YAML file for some reason
|
86
|
+
does not exist, then the object is set up with some bogus credentials which
|
87
|
+
would not work anyway and therefore, the other option is that you set them
|
88
|
+
yourself. Which, you can do using a hash as shown below (please note that
|
89
|
+
Pesapal provides different keys for different modes and since this is like an
|
90
|
+
override, there's the assumption that you chose the right one).
|
91
|
+
|
92
|
+
```ruby
|
93
|
+
# set pesapal api configuration manually (override YAML & bogus credentials)
|
94
|
+
pesapal.config = { :callback_url => 'http://0.0.0.0:3000/pesapal/callback'
|
95
|
+
:consumer_key => '<YOUR_CONSUMER_KEY>',
|
96
|
+
:consumer_secret => '<YOUR_CONSUMER_SECRET>'
|
97
|
+
}
|
98
|
+
```
|
99
|
+
|
100
|
+
_Ps: You can change the mode using `pesapal.set_mode(:development)` (example) if
|
101
|
+
for some reason you want to override what was set in the constructor._
|
102
|
+
|
103
|
+
|
104
|
+
###YAML Configuration###
|
105
|
+
|
76
106
|
The YAML file should look something like this. If you ran the generator you
|
77
107
|
should have it already in place with some default values. Feel free to change
|
78
108
|
them appropriately.
|
@@ -89,27 +119,8 @@ production:
|
|
89
119
|
consumer_secret: '<YOUR_CONSUMER_SECRET>'
|
90
120
|
```
|
91
121
|
|
92
|
-
If the YAML file does not exist, then the object is set up with some bogus
|
93
|
-
credentials which would not work anyway and therefore, the next logical step is
|
94
|
-
that you set them yourself. Which, you can do using a hash as shown below
|
95
|
-
(please note that Pesapal provides different keys for different modes and since
|
96
|
-
this is like an override, there's the assumption that you chose the right one).
|
97
|
-
|
98
|
-
```ruby
|
99
|
-
# set pesapal api configuration manually (override YAML & bogus credentials)
|
100
|
-
pesapal.config = { :callback_url => 'http://0.0.0.0:3000/pesapal/callback'
|
101
|
-
:consumer_key => '<YOUR_CONSUMER_KEY>',
|
102
|
-
:consumer_secret => '<YOUR_CONSUMER_SECRET>'
|
103
|
-
}
|
104
|
-
```
|
105
|
-
|
106
|
-
_Ps: Make sure this hash has the appropriate values before running any methods
|
107
|
-
that interact with the API as the methods pick from these values. This means
|
108
|
-
that you can also override them at runtime for a truly dynamic/complex app that
|
109
|
-
might have different values for different scenarios._
|
110
|
-
|
111
122
|
|
112
|
-
###
|
123
|
+
### Posting An Order ###
|
113
124
|
|
114
125
|
Once you've finalized the configuration, set up the order details in a hash as
|
115
126
|
shown in the example below ... all keys **MUST** be present. If there's one that
|
@@ -149,6 +160,50 @@ url. Refer to [official Pesapal Step-By-Step integration guide][18] for more
|
|
149
160
|
details._
|
150
161
|
|
151
162
|
|
163
|
+
### Querying Payment Status ###
|
164
|
+
|
165
|
+
Use this to query the status of the transaction. When a transaction is posted to
|
166
|
+
Pesapal, it may be in a PENDING, COMPLETED, FAILED or INVALID state. If the
|
167
|
+
transaction is PENDING, the payment may complete or fail at a later stage.
|
168
|
+
|
169
|
+
Both the unique merchant reference generated by your system (compulsory) and the
|
170
|
+
pesapal transaction tracking id (optional) are input parameters to this method
|
171
|
+
but if you don't ensure that the merchant reference is unique for each order on
|
172
|
+
your system, you may get INVALID as the response. Because of this, it is
|
173
|
+
recommended that you provide both the merchant reference and transaction
|
174
|
+
tracking id as parameters to guarantee uniqueness.
|
175
|
+
|
176
|
+
```ruby
|
177
|
+
# option 1: using merchant reference only
|
178
|
+
payment_status = pesapal.query_payment_status("<MERCHANT_REFERENCE>")
|
179
|
+
|
180
|
+
# option 2: using merchant reference and transaction id (recommended)
|
181
|
+
payment_status = pesapal.query_payment_status("<MERCHANT_REFERENCE>","<TRANSACTION_ID>")
|
182
|
+
```
|
183
|
+
|
184
|
+
|
185
|
+
### Querying Payment Details ###
|
186
|
+
|
187
|
+
Same as querying payment status above, but the return value contains more
|
188
|
+
information (and is a hash as opposed to a string).
|
189
|
+
|
190
|
+
```ruby
|
191
|
+
# pass in merchant reference and transaction id
|
192
|
+
payment_details = pesapal.query_payment_details("<MERCHANT_REFERENCE>","<TRANSACTION_ID>")
|
193
|
+
```
|
194
|
+
|
195
|
+
The result is a hash that looks something like this ...
|
196
|
+
|
197
|
+
```
|
198
|
+
{
|
199
|
+
:method=>"MPESA",
|
200
|
+
:status=>"COMPLETED",
|
201
|
+
:merchant_reference=>"<MERCHANT_REFERENCE>",
|
202
|
+
:transaction_tracking_id=>"<TRANSACTION_ID>"
|
203
|
+
}
|
204
|
+
```
|
205
|
+
|
206
|
+
|
152
207
|
Contributing
|
153
208
|
------------
|
154
209
|
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Pesapal
|
2
|
+
|
3
|
+
module Details
|
4
|
+
|
5
|
+
# set parameters required by the QueryPaymentDetails call
|
6
|
+
def Details.set_parameters(consumer_key, merchant_reference, transaction_tracking_id)
|
7
|
+
|
8
|
+
# parameters required by the QueryPaymentDetails call (excludes
|
9
|
+
# oauth_signature parameter as per the instructions here
|
10
|
+
# http://developer.pesapal.com/how-to-integrate/api-reference#QueryPaymentDetails)
|
11
|
+
|
12
|
+
timestamp = Time.now.to_i.to_s
|
13
|
+
|
14
|
+
params = { :oauth_consumer_key => consumer_key,
|
15
|
+
:oauth_nonce => "#{timestamp}" + Pesapal::Oauth.generate_nonce(12),
|
16
|
+
:oauth_signature_method => 'HMAC-SHA1',
|
17
|
+
:oauth_timestamp => "#{timestamp}",
|
18
|
+
:oauth_version => '1.0',
|
19
|
+
:pesapal_merchant_reference => merchant_reference,
|
20
|
+
:pesapal_transaction_tracking_id => transaction_tracking_id
|
21
|
+
}
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -28,7 +28,7 @@ module Pesapal
|
|
28
28
|
"#{post_xml}"
|
29
29
|
end
|
30
30
|
|
31
|
-
# set parameters required by the PostPesapalDirectOrderV4
|
31
|
+
# set parameters required by the PostPesapalDirectOrderV4 call
|
32
32
|
def Post.set_parameters(callback_url, consumer_key, post_xml)
|
33
33
|
|
34
34
|
# parameters required by the PostPesapalDirectOrderV4 call (excludes
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Pesapal
|
2
|
+
|
3
|
+
module Status
|
4
|
+
|
5
|
+
# set parameters required by the QueryPaymentStatus & QueryPaymentStatusByMerchantRef calls
|
6
|
+
def Status.set_parameters(consumer_key, merchant_reference, transaction_tracking_id = nil)
|
7
|
+
|
8
|
+
# parameters required by the QueryPaymentStatus call (excludes
|
9
|
+
# oauth_signature parameter as per the instructions here
|
10
|
+
# http://developer.pesapal.com/how-to-integrate/api-reference)
|
11
|
+
|
12
|
+
timestamp = Time.now.to_i.to_s
|
13
|
+
|
14
|
+
params = { :oauth_consumer_key => consumer_key,
|
15
|
+
:oauth_nonce => "#{timestamp}" + Pesapal::Oauth.generate_nonce(12),
|
16
|
+
:oauth_signature_method => 'HMAC-SHA1',
|
17
|
+
:oauth_timestamp => "#{timestamp}",
|
18
|
+
:oauth_version => '1.0',
|
19
|
+
:pesapal_merchant_reference => merchant_reference
|
20
|
+
}
|
21
|
+
|
22
|
+
unless transaction_tracking_id.nil? # do, if not true
|
23
|
+
params[:pesapal_transaction_tracking_id] = transaction_tracking_id
|
24
|
+
end
|
25
|
+
|
26
|
+
params
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/lib/pesapal/merchant.rb
CHANGED
@@ -3,15 +3,6 @@ module Pesapal
|
|
3
3
|
class Merchant
|
4
4
|
|
5
5
|
attr_accessor :config, :order_details
|
6
|
-
attr_reader :api_domain, :api_endpoints
|
7
|
-
|
8
|
-
def api_domain
|
9
|
-
@api_domain
|
10
|
-
end
|
11
|
-
|
12
|
-
def api_endpoints
|
13
|
-
@api_endpoints
|
14
|
-
end
|
15
6
|
|
16
7
|
def config
|
17
8
|
@config
|
@@ -23,6 +14,14 @@ module Pesapal
|
|
23
14
|
|
24
15
|
private
|
25
16
|
|
17
|
+
def api_domain
|
18
|
+
@api_domain
|
19
|
+
end
|
20
|
+
|
21
|
+
def api_endpoints
|
22
|
+
@api_endpoints
|
23
|
+
end
|
24
|
+
|
26
25
|
def mode
|
27
26
|
@mode
|
28
27
|
end
|
@@ -49,8 +48,7 @@ module Pesapal
|
|
49
48
|
@post_xml = nil
|
50
49
|
@token_secret = nil
|
51
50
|
|
52
|
-
|
53
|
-
@mode = "#{mode.to_s.downcase}"
|
51
|
+
set_mode mode
|
54
52
|
|
55
53
|
# set the credentials if we have not set a custom path for the YAML config file
|
56
54
|
if path_to_file.nil?
|
@@ -61,8 +59,6 @@ module Pesapal
|
|
61
59
|
set_configuration_from_yaml path_to_file
|
62
60
|
end
|
63
61
|
|
64
|
-
# set api endpoints depending on the mode
|
65
|
-
set_endpoints
|
66
62
|
end
|
67
63
|
|
68
64
|
# generate pesapal order url (often iframed)
|
@@ -72,7 +68,7 @@ module Pesapal
|
|
72
68
|
# required
|
73
69
|
@post_xml = Pesapal::Post::generate_post_xml @order_details
|
74
70
|
|
75
|
-
# initialize setting of @params (oauth_signature left empty)
|
71
|
+
# initialize setting of @params (oauth_signature left empty)
|
76
72
|
@params = Pesapal::Post::set_parameters(@config[:callback_url], @config[:consumer_key], @post_xml)
|
77
73
|
|
78
74
|
# generate oauth signature and add signature to the request parameters
|
@@ -84,6 +80,59 @@ module Pesapal
|
|
84
80
|
"#{@api_endpoints[:postpesapaldirectorderv4]}?#{query_string}"
|
85
81
|
end
|
86
82
|
|
83
|
+
# query the details of the transaction
|
84
|
+
def query_payment_details(merchant_reference, transaction_tracking_id)
|
85
|
+
|
86
|
+
# initialize setting of @params (oauth_signature left empty)
|
87
|
+
@params = Pesapal::Details::set_parameters(@config[:consumer_key], merchant_reference, transaction_tracking_id)
|
88
|
+
|
89
|
+
# generate oauth signature and add signature to the request parameters
|
90
|
+
@params[:oauth_signature] = Pesapal::Oauth::generate_oauth_signature("GET", @api_endpoints[:querypaymentdetails], @params, @config[:consumer_secret], @token_secret)
|
91
|
+
|
92
|
+
# change params (with signature) to a query string
|
93
|
+
query_string = Pesapal::Oauth::generate_encoded_params_query_string @params
|
94
|
+
|
95
|
+
# get status response
|
96
|
+
response = Net::HTTP.get(URI("#{@api_endpoints[:querypaymentdetails]}?#{query_string}"))
|
97
|
+
response = CGI::parse(response)
|
98
|
+
response = response["pesapal_response_data"][0].split(',')
|
99
|
+
|
100
|
+
details = { :method => response[1],
|
101
|
+
:status => response[2],
|
102
|
+
:merchant_reference => response[3],
|
103
|
+
:transaction_tracking_id => response[0] }
|
104
|
+
end
|
105
|
+
|
106
|
+
# query the status of the transaction
|
107
|
+
def query_payment_status(merchant_reference, transaction_tracking_id = nil)
|
108
|
+
|
109
|
+
# initialize setting of @params (oauth_signature left empty)
|
110
|
+
@params = Pesapal::Status::set_parameters(@config[:consumer_key], merchant_reference, transaction_tracking_id)
|
111
|
+
|
112
|
+
# generate oauth signature and add signature to the request parameters
|
113
|
+
@params[:oauth_signature] = Pesapal::Oauth::generate_oauth_signature("GET", @api_endpoints[:querypaymentstatus], @params, @config[:consumer_secret], @token_secret)
|
114
|
+
|
115
|
+
# change params (with signature) to a query string
|
116
|
+
query_string = Pesapal::Oauth::generate_encoded_params_query_string @params
|
117
|
+
|
118
|
+
# get status response
|
119
|
+
response = Net::HTTP.get(URI("#{@api_endpoints[:querypaymentstatus]}?#{query_string}"))
|
120
|
+
response = CGI::parse(response)
|
121
|
+
|
122
|
+
# return the string result of what we want
|
123
|
+
response["pesapal_response_data"][0]
|
124
|
+
end
|
125
|
+
|
126
|
+
# set mode when called
|
127
|
+
def set_mode(mode = :development)
|
128
|
+
|
129
|
+
# convert symbol to string and downcase
|
130
|
+
@mode = "#{mode.to_s.downcase}"
|
131
|
+
|
132
|
+
# set api endpoints depending on the mode
|
133
|
+
set_endpoints
|
134
|
+
end
|
135
|
+
|
87
136
|
private
|
88
137
|
|
89
138
|
# set endpoints
|
@@ -98,7 +147,6 @@ module Pesapal
|
|
98
147
|
@api_endpoints = {}
|
99
148
|
@api_endpoints[:postpesapaldirectorderv4] = "#{@api_domain}/API/PostPesapalDirectOrderV4"
|
100
149
|
@api_endpoints[:querypaymentstatus] = "#{@api_domain}/API/QueryPaymentStatus"
|
101
|
-
@api_endpoints[:querypaymentstatusbymerchantref] = "#{@api_domain}/API/QueryPaymentStatus"
|
102
150
|
@api_endpoints[:querypaymentdetails] = "#{@api_domain}/API/QueryPaymentDetails"
|
103
151
|
end
|
104
152
|
|
data/lib/pesapal/version.rb
CHANGED
data/lib/pesapal.rb
CHANGED
data/pesapal.gemspec
CHANGED
@@ -5,7 +5,7 @@ require "pesapal/version"
|
|
5
5
|
Gem::Specification.new do |spec|
|
6
6
|
spec.name = "pesapal"
|
7
7
|
spec.version = Pesapal::VERSION
|
8
|
-
spec.date = "
|
8
|
+
spec.date = Time.new.getlocal("+03:00").strftime("%Y-%m-%d")
|
9
9
|
spec.authors = ["Job King'ori Maina"]
|
10
10
|
spec.email = ["j@kingori.co"]
|
11
11
|
spec.description = "Make authenticated Pesapal API calls without the fuss!"
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pesapal
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Job King'ori Maina
|
@@ -71,7 +71,9 @@ files:
|
|
71
71
|
- lib/generators/templates/pesapal.yml
|
72
72
|
- lib/pesapal.rb
|
73
73
|
- lib/pesapal/merchant.rb
|
74
|
+
- lib/pesapal/merchant/details.rb
|
74
75
|
- lib/pesapal/merchant/post.rb
|
76
|
+
- lib/pesapal/merchant/status.rb
|
75
77
|
- lib/pesapal/oauth.rb
|
76
78
|
- lib/pesapal/version.rb
|
77
79
|
- pesapal.gemspec
|