pesapal 0.2.1 → 1.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 +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
|