mpesa_stk 1.0.2 → 1.3
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 -5
- data/.github/workflows/cop.yml +22 -0
- data/.gitignore +5 -1
- data/.sample.env +3 -2
- data/Gemfile.lock +28 -24
- data/README.md +107 -29
- data/lib/mpesa_stk.rb +1 -0
- data/lib/mpesa_stk/access_token.rb +20 -19
- data/lib/mpesa_stk/push.rb +131 -0
- data/lib/mpesa_stk/push_payment.rb +40 -39
- data/lib/mpesa_stk/version.rb +1 -1
- data/mpesa_stk.gemspec +4 -4
- metadata +26 -20
- data/.travis.yml +0 -5
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
|
-
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 12e1c2a4f60b943357593f37099a3ef7e5a9f4c272a0aca0960452b504789fe0
|
|
4
|
+
data.tar.gz: 14c3633244b9867b275a1e10949f4b6880b62c04e42213c6b5b2f4ded24e4dc1
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 7fe982c6d29a14a7ab22e2acc16d97b9411666c47edf664c5f77a9e0b398d7b6cf3c031bdd9c9e55003f4fb31a21ecaef65e5eeadb4f7893721c3c466ba06e57
|
|
7
|
+
data.tar.gz: c2dbf612bd39861047a24cf0497a01893ec6b0018ec20ee6f33cc8a36d0964e87172566f0090bcf4e29f076d099192dab6b0e859951029db8d32b38feb04171a
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
name: Cop
|
|
2
|
+
on: [push]
|
|
3
|
+
|
|
4
|
+
jobs:
|
|
5
|
+
build:
|
|
6
|
+
runs-on: ubuntu-latest
|
|
7
|
+
steps:
|
|
8
|
+
- name: Rubocop checks
|
|
9
|
+
uses: gimenete/rubocop-action@1.0
|
|
10
|
+
env:
|
|
11
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
12
|
+
|
|
13
|
+
- uses: actions/checkout@v2
|
|
14
|
+
- name: Set up Ruby 2.6
|
|
15
|
+
uses: actions/setup-ruby@v1
|
|
16
|
+
with:
|
|
17
|
+
ruby-version: 2.6
|
|
18
|
+
- name: Rails Test
|
|
19
|
+
run: |
|
|
20
|
+
gem install bundler
|
|
21
|
+
bundle install
|
|
22
|
+
bundle exec rake test
|
data/.gitignore
CHANGED
data/.sample.env
CHANGED
data/Gemfile.lock
CHANGED
|
@@ -1,25 +1,29 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
mpesa_stk (1.
|
|
5
|
-
httparty (
|
|
4
|
+
mpesa_stk (1.3)
|
|
5
|
+
httparty (>= 0.15.6, < 0.19.0)
|
|
6
6
|
redis-namespace (~> 1.5, >= 1.5.3)
|
|
7
7
|
redis-rack (~> 2.0, >= 2.0.2)
|
|
8
8
|
|
|
9
9
|
GEM
|
|
10
10
|
remote: https://rubygems.org/
|
|
11
11
|
specs:
|
|
12
|
-
addressable (2.
|
|
13
|
-
public_suffix (>= 2.0.2, <
|
|
12
|
+
addressable (2.7.0)
|
|
13
|
+
public_suffix (>= 2.0.2, < 5.0)
|
|
14
14
|
coderay (1.1.2)
|
|
15
15
|
crack (0.4.3)
|
|
16
16
|
safe_yaml (~> 1.0.0)
|
|
17
|
-
dotenv (2.
|
|
18
|
-
hashdiff (0.
|
|
19
|
-
httparty (0.
|
|
17
|
+
dotenv (2.7.5)
|
|
18
|
+
hashdiff (1.0.1)
|
|
19
|
+
httparty (0.18.1)
|
|
20
|
+
mime-types (~> 3.0)
|
|
20
21
|
multi_xml (>= 0.5.2)
|
|
21
22
|
method_source (0.8.2)
|
|
22
|
-
|
|
23
|
+
mime-types (3.3.1)
|
|
24
|
+
mime-types-data (~> 3.2015)
|
|
25
|
+
mime-types-data (3.2020.0512)
|
|
26
|
+
minitest (5.14.0)
|
|
23
27
|
multi_xml (0.6.0)
|
|
24
28
|
pry (0.10.4)
|
|
25
29
|
coderay (~> 1.1.0)
|
|
@@ -27,36 +31,36 @@ GEM
|
|
|
27
31
|
slop (~> 3.4)
|
|
28
32
|
pry-nav (0.2.4)
|
|
29
33
|
pry (>= 0.9.10, < 0.11.0)
|
|
30
|
-
public_suffix (
|
|
31
|
-
rack (2.
|
|
32
|
-
rake (
|
|
33
|
-
redis (4.
|
|
34
|
-
redis-namespace (1.
|
|
34
|
+
public_suffix (4.0.4)
|
|
35
|
+
rack (2.2.2)
|
|
36
|
+
rake (13.0.1)
|
|
37
|
+
redis (4.2.1)
|
|
38
|
+
redis-namespace (1.7.0)
|
|
35
39
|
redis (>= 3.0.4)
|
|
36
|
-
redis-rack (2.
|
|
37
|
-
rack (>=
|
|
40
|
+
redis-rack (2.1.2)
|
|
41
|
+
rack (>= 2.0.8, < 3)
|
|
38
42
|
redis-store (>= 1.2, < 2)
|
|
39
|
-
redis-store (1.
|
|
40
|
-
redis (>=
|
|
41
|
-
safe_yaml (1.0.
|
|
43
|
+
redis-store (1.8.2)
|
|
44
|
+
redis (>= 4, < 5)
|
|
45
|
+
safe_yaml (1.0.5)
|
|
42
46
|
slop (3.6.0)
|
|
43
|
-
webmock (3.3
|
|
47
|
+
webmock (3.8.3)
|
|
44
48
|
addressable (>= 2.3.6)
|
|
45
49
|
crack (>= 0.3.2)
|
|
46
|
-
hashdiff
|
|
50
|
+
hashdiff (>= 0.4.0, < 2.0.0)
|
|
47
51
|
|
|
48
52
|
PLATFORMS
|
|
49
53
|
ruby
|
|
50
54
|
|
|
51
55
|
DEPENDENCIES
|
|
52
|
-
bundler
|
|
53
|
-
dotenv (= 2.
|
|
56
|
+
bundler
|
|
57
|
+
dotenv (= 2.7.5)
|
|
54
58
|
minitest (~> 5.0)
|
|
55
59
|
mpesa_stk!
|
|
56
60
|
pry (~> 0.10.4)
|
|
57
61
|
pry-nav (~> 0.2.4)
|
|
58
|
-
rake (
|
|
62
|
+
rake (>= 12.3.3)
|
|
59
63
|
webmock (~> 3.0, >= 3.0.1)
|
|
60
64
|
|
|
61
65
|
BUNDLED WITH
|
|
62
|
-
1.
|
|
66
|
+
2.1.4
|
data/README.md
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
# MpesaStk
|
|
2
2
|
Lipa na M-Pesa Online Payment API is used to initiate a M-Pesa transaction on behalf of a customer using STK Push. This is the same technique mySafaricom App uses whenever the app is used to make payments.
|
|
3
3
|
|
|
4
|
+
[](https://badge.fury.io/rb/mpesa_stk.svg)
|
|
5
|
+

|
|
6
|
+
|
|
4
7
|
## Installation
|
|
5
8
|
|
|
6
9
|
Add this line to your application's Gemfile:
|
|
@@ -8,55 +11,129 @@ Add this line to your application's Gemfile:
|
|
|
8
11
|
```ruby
|
|
9
12
|
gem 'mpesa_stk'
|
|
10
13
|
```
|
|
11
|
-
|
|
12
|
-
And then execute:
|
|
13
|
-
|
|
14
|
-
$ bundle or $ bundle install
|
|
14
|
+
and run the `bundle install` command
|
|
15
15
|
|
|
16
16
|
Or install it yourself as:
|
|
17
|
+
```ruby
|
|
18
|
+
gem install mpesa_stk
|
|
19
|
+
```
|
|
17
20
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
21
|
+
# Getting Started
|
|
22
|
+
This gem has a [Redis](https://redis.io/) dependency, so make sure it running
|
|
23
|
+
```ruby
|
|
24
|
+
$ redis-server
|
|
25
|
+
```
|
|
26
|
+
You can use command line to determine if redis is running:
|
|
27
|
+
```ruby
|
|
28
|
+
redis-cli ping
|
|
29
|
+
```
|
|
30
|
+
you should get back
|
|
31
|
+
```ruby
|
|
32
|
+
PONG
|
|
26
33
|
```
|
|
27
|
-
base_url="https://sandbox.safaricom.co.ke"
|
|
28
|
-
token_generator_url="/oauth/v1/generate?grant_type=client_credentials"
|
|
29
|
-
process_request_url="/mpesa/stkpush/v1/processrequest"
|
|
30
34
|
|
|
35
|
+
you need to setup your environment variables, checkout `.sample.env` for the values you need.
|
|
36
|
+
or run
|
|
37
|
+
```ruby
|
|
38
|
+
$ cp .sample.env .env
|
|
39
|
+
```
|
|
40
|
+
open `.env` on your editor and add the missing variable
|
|
41
|
+
```
|
|
31
42
|
key=""
|
|
32
43
|
secret=""
|
|
33
44
|
business_short_code=""
|
|
34
|
-
business_passkey="
|
|
35
|
-
callback_url="
|
|
45
|
+
business_passkey=""
|
|
46
|
+
callback_url=""
|
|
47
|
+
till_number=""
|
|
36
48
|
```
|
|
37
|
-
this can be found in [Test Credentials](https://developer.safaricom.co.ke/test_credentials)
|
|
38
|
-
* `key` and `secret` of your application key.
|
|
39
|
-
* `business_short_code` and `business_pass_key` from safaricom.
|
|
40
|
-
* `callback_url` the url of your application.
|
|
41
49
|
|
|
50
|
+
* `key` and `secret` of the app created on your [developer account](https://developer.safaricom.co.ke/user/me/apps).
|
|
51
|
+
* `business_short_code` and `business_pass_key` this can be found in [Test Credentials](https://developer.safaricom.co.ke/test_credentials).
|
|
52
|
+
* `callback_url` the url of your application where response will be sent. `make sure its a reachable/active url`
|
|
53
|
+
|
|
54
|
+
`Prod:`
|
|
55
|
+
|
|
56
|
+
when going live there information will be sent to your email.
|
|
42
57
|
|
|
43
|
-
|
|
58
|
+
for `buy_goods` push `business_short_code` will be equivalent to `store number` and `till_number` will remain as is.
|
|
44
59
|
|
|
45
|
-
|
|
46
|
-
|
|
60
|
+
### Testing out the gem in an actual Rails application
|
|
61
|
+
|
|
62
|
+
To test out the app on an actual rails application, do check out the following link:
|
|
63
|
+
|
|
64
|
+
https://github.com/mboya/stk
|
|
65
|
+
|
|
66
|
+
```shell
|
|
67
|
+
https://github.com/mboya/stk
|
|
47
68
|
```
|
|
48
|
-
|
|
69
|
+
#### Sample application
|
|
70
|
+
Check out a rails sample application [here](https://github.com/mboya/stk)
|
|
71
|
+
|
|
72
|
+
### Testing the gem on the console/app
|
|
73
|
+
When running the gem on a single safaricom app.
|
|
74
|
+
|
|
75
|
+
```ruby
|
|
76
|
+
$ irb
|
|
77
|
+
2.5.0 :001 > require 'mpesa_stk'
|
|
78
|
+
2.5.0 :002 > MpesaStk::PushPayment.call("500", "<YOUR PHONE NUMBER: 254711222333>")
|
|
49
79
|
```
|
|
50
80
|
|
|
81
|
+
When running the app on multiple safaricom apps, within the same project.
|
|
82
|
+
```ruby
|
|
83
|
+
$ irb
|
|
84
|
+
2.5.3 :001 > require 'mpesa_stk'
|
|
85
|
+
2.5.3 :002 > hash = Hash.new
|
|
86
|
+
2.5.3 :003 >
|
|
87
|
+
2.5.3 :004 > hash['key'] = key
|
|
88
|
+
2.5.3 :005 > hash['secret'] = secret
|
|
89
|
+
2.5.3 :006 > hash['business_short_code'] = business_short_code
|
|
90
|
+
2.5.3 :007 > hash['business_passkey'] = business_passkey
|
|
91
|
+
2.5.3 :008 > hash['callback_url'] = callback_url
|
|
92
|
+
2.5.3 :009 > hash['till_number'] = till_number
|
|
93
|
+
```
|
|
94
|
+
for STK push
|
|
95
|
+
```ruby
|
|
96
|
+
2.5.3 :010 > MpesaStk::Push.pay_bill('05', "<YOUR PHONE NUMBER: 254711222333>", hash)
|
|
51
97
|
```
|
|
52
|
-
|
|
98
|
+
for Till Number push
|
|
99
|
+
```ruby
|
|
100
|
+
2.5.3 :010 > MpesaStk::Push.buy_goods('05', "<YOUR PHONE NUMBER: 254711222333>", hash)
|
|
101
|
+
```
|
|
102
|
+
possible error format if the request is not successful
|
|
103
|
+
```hash
|
|
104
|
+
{"requestId"=>"13022-8633727-1", "errorCode"=>"500.001.1001", "errorMessage"=>"Error Message"}
|
|
53
105
|
```
|
|
54
106
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
107
|
+
expected irb output after the command
|
|
108
|
+
```hash
|
|
109
|
+
{
|
|
110
|
+
"MerchantRequestID"=>"7909-1302368-1",
|
|
111
|
+
"CheckoutRequestID"=>"ws_CO_DMZ_40472724_16062018092359957",
|
|
112
|
+
"ResponseCode"=>"0",
|
|
113
|
+
"ResponseDescription"=>"Success. Request accepted for processing",
|
|
114
|
+
"CustomerMessage"=>"Success. Request accepted for processing"
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
the above response means the response has been successfully sent to Safaricom for processing and you should be able to see the checkout/express prompt on the sender number.
|
|
119
|
+
|
|
120
|
+
### Mpesa Checkout/Express
|
|
121
|
+
This is the expected output on the mobile phone
|
|
58
122
|
|
|
123
|
+

|
|
59
124
|
|
|
125
|
+
### Callback url
|
|
126
|
+
|
|
127
|
+
After the pin code is entered on the checkout/express prompt. you will receive a request on the provided `callback_url` with the status of the action
|
|
128
|
+
|
|
129
|
+
sample payload that you will be getting on your callback
|
|
130
|
+
```hash
|
|
131
|
+
{"Body"=>{"stkCallback"=>{"MerchantRequestID"=>"3968-94214-1", "CheckoutRequestID"=>"ws_CO_160620191218268004", "ResultCode"=>0, "ResultDesc"=>"The service request is processed successfully.",
|
|
132
|
+
"CallbackMetadata"=>{"Item"=>[{"Name"=>"Amount", "Value"=>"05"}, {"Name"=>"MpesaReceiptNumber", "Value"=>"OFG4Z5EE9Y"}, {"Name"=>"TransactionDate", "Value"=>20190616121848},
|
|
133
|
+
{"Name"=>"PhoneNumber", "Value"=>254711222333}]}}}, "push"=>{"Body"=>{"stkCallback"=>{"MerchantRequestID"=>"3968-94214-1", "CheckoutRequestID"=>"ws_CO_160620191218268004", "ResultCode"=>0,
|
|
134
|
+
"ResultDesc"=>"The service request is processed successfully.", "CallbackMetadata"=>{"Item"=>[{"Name"=>"Amount", "Value"=>"05"}, {"Name"=>"MpesaReceiptNumber", "Value"=>"OFG4Z5EE9Y"}, {"Name"=>"TransactionDate",
|
|
135
|
+
"Value"=>20190616121848}, {"Name"=>"PhoneNumber", "Value"=>254711222333}]}}}}}
|
|
136
|
+
```
|
|
60
137
|
|
|
61
138
|
## Development
|
|
62
139
|
|
|
@@ -83,3 +160,4 @@ The gem is available as open source under the terms of the [MIT License](https:/
|
|
|
83
160
|
## Code of Conduct
|
|
84
161
|
|
|
85
162
|
Everyone interacting in the MpesaStk project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/mboya/mpesa_stk/blob/master/CODE_OF_CONDUCT.md).
|
|
163
|
+
|
data/lib/mpesa_stk.rb
CHANGED
|
@@ -4,14 +4,14 @@ require 'redis'
|
|
|
4
4
|
module MpesaStk
|
|
5
5
|
class AccessToken
|
|
6
6
|
class << self
|
|
7
|
-
def call
|
|
8
|
-
new.access_token
|
|
7
|
+
def call(key = nil, secret = nil)
|
|
8
|
+
new(key, secret).access_token
|
|
9
9
|
end
|
|
10
10
|
end
|
|
11
11
|
|
|
12
|
-
def initialize
|
|
13
|
-
@key = ENV['key']
|
|
14
|
-
@secret = ENV['secret']
|
|
12
|
+
def initialize(key = nil, secret = nil)
|
|
13
|
+
@key = key.nil? ? ENV['key'] : key
|
|
14
|
+
@secret = secret.nil? ? ENV['secret'] : secret
|
|
15
15
|
@redis = Redis.new
|
|
16
16
|
|
|
17
17
|
load_from_redis
|
|
@@ -61,25 +61,26 @@ module MpesaStk
|
|
|
61
61
|
def get_new_access_token
|
|
62
62
|
response = HTTParty.get(url, headers: headers)
|
|
63
63
|
|
|
64
|
-
hash = JSON.parse(response.body).merge(Hash['time_stamp',Time.now.to_i])
|
|
64
|
+
hash = JSON.parse(response.body).merge(Hash['time_stamp', Time.now.to_i])
|
|
65
65
|
@redis.set @key, hash.to_json
|
|
66
66
|
end
|
|
67
67
|
|
|
68
68
|
private
|
|
69
|
-
def url
|
|
70
|
-
"#{ENV['base_url']}#{ENV['token_generator_url']}"
|
|
71
|
-
end
|
|
72
69
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
"Authorization" => "Basic #{encode}"
|
|
77
|
-
}
|
|
78
|
-
end
|
|
70
|
+
def url
|
|
71
|
+
"#{ENV['base_url']}#{ENV['token_generator_url']}"
|
|
72
|
+
end
|
|
79
73
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
74
|
+
def headers
|
|
75
|
+
encode = encode_credentials @key, @secret
|
|
76
|
+
{
|
|
77
|
+
"Authorization" => "Basic #{encode}"
|
|
78
|
+
}
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def encode_credentials key, secret
|
|
82
|
+
credentials = "#{key}:#{secret}"
|
|
83
|
+
Base64.encode64(credentials).split("\n").join
|
|
84
|
+
end
|
|
84
85
|
end
|
|
85
86
|
end
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
require "mpesa_stk/access_token"
|
|
2
|
+
|
|
3
|
+
module MpesaStk
|
|
4
|
+
class Push
|
|
5
|
+
class << self
|
|
6
|
+
def pay_bill(amount, phone_number, hash = {})
|
|
7
|
+
new(amount, phone_number, "CustomerPayBillOnline", nil, hash["business_short_code"], hash["callback_url"], hash["business_passkey"], hash["key"], hash["secret"]).push_payment
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def buy_goods(amount, phone_number, hash = {})
|
|
11
|
+
new(amount, phone_number, "CustomerBuyGoodsOnline", hash["till_number"], hash["business_short_code"], hash["callback_url"], hash["business_passkey"], hash["key"], hash["secret"]).push_payment
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
attr_reader :token, :amount, :phone_number, :till_number, :business_short_code, :callback_url, :business_passkey, :transaction_type
|
|
16
|
+
|
|
17
|
+
def initialize(amount, phone_number, transaction_type, till_number = nil, business_short_code = nil, callback_url = nil, business_passkey = nil, key = nil, secret = nil)
|
|
18
|
+
@token = MpesaStk::AccessToken.call(key, secret)
|
|
19
|
+
@transaction_type = transaction_type
|
|
20
|
+
@till_number = till_number
|
|
21
|
+
@business_short_code = business_short_code
|
|
22
|
+
@callback_url = callback_url
|
|
23
|
+
@business_passkey = business_passkey
|
|
24
|
+
@amount = amount
|
|
25
|
+
@phone_number = phone_number
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def push_payment
|
|
29
|
+
response = HTTParty.post(url, headers: headers, body: body)
|
|
30
|
+
JSON.parse(response.body)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
private
|
|
34
|
+
|
|
35
|
+
def url
|
|
36
|
+
"#{ENV['base_url']}#{ENV['process_request_url']}"
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def headers
|
|
40
|
+
{
|
|
41
|
+
"Authorization" => "Bearer #{token}",
|
|
42
|
+
"Content-Type" => "application/json"
|
|
43
|
+
}
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def body
|
|
47
|
+
{
|
|
48
|
+
BusinessShortCode: get_business_short_code,
|
|
49
|
+
Password: generate_password,
|
|
50
|
+
Timestamp: "#{timestamp}",
|
|
51
|
+
TransactionType: transaction_type,
|
|
52
|
+
Amount: "#{amount}",
|
|
53
|
+
PartyA: "#{phone_number}",
|
|
54
|
+
PartyB: get_till_number,
|
|
55
|
+
PhoneNumber: "#{phone_number}",
|
|
56
|
+
CallBackURL: get_callback_url,
|
|
57
|
+
AccountReference: generate_bill_reference_number(5),
|
|
58
|
+
TransactionDesc: generate_bill_reference_number(5)
|
|
59
|
+
}.to_json
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def generate_bill_reference_number(number)
|
|
63
|
+
charset = Array('A'..'Z') + Array('a'..'z')
|
|
64
|
+
Array.new(number) { charset.sample }.join
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def timestamp
|
|
68
|
+
DateTime.now.strftime("%Y%m%d%H%M%S").to_i
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# shortcode
|
|
72
|
+
# passkey
|
|
73
|
+
# timestamp
|
|
74
|
+
def generate_password
|
|
75
|
+
key = "#{get_business_short_code}#{get_business_passkey}#{timestamp}"
|
|
76
|
+
Base64.encode64(key).split("\n").join
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def get_business_short_code
|
|
80
|
+
if business_short_code.nil? || business_short_code.eql?("")
|
|
81
|
+
if ENV['business_short_code'].nil? || ENV['business_short_code'].eql?("")
|
|
82
|
+
raise Exception.new "Business Short Code is not defined"
|
|
83
|
+
else
|
|
84
|
+
ENV['business_short_code']
|
|
85
|
+
end
|
|
86
|
+
else
|
|
87
|
+
business_short_code
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def get_business_passkey
|
|
92
|
+
if business_passkey.nil? || business_passkey.eql?("")
|
|
93
|
+
if ENV['business_passkey'].nil? || ENV['business_passkey'].eql?("")
|
|
94
|
+
raise Exception.new "Business Passkey is not defined"
|
|
95
|
+
else
|
|
96
|
+
ENV['business_passkey']
|
|
97
|
+
end
|
|
98
|
+
else
|
|
99
|
+
business_passkey
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def get_callback_url
|
|
104
|
+
if callback_url.nil? || callback_url.eql?("")
|
|
105
|
+
if ENV['callback_url'].nil? || ENV['callback_url'].eql?("")
|
|
106
|
+
raise Exception.new "Callback URL is not defined"
|
|
107
|
+
else
|
|
108
|
+
ENV['callback_url']
|
|
109
|
+
end
|
|
110
|
+
else
|
|
111
|
+
callback_url
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def get_till_number
|
|
116
|
+
if transaction_type.eql?("CustomerPayBillOnline")
|
|
117
|
+
get_business_short_code
|
|
118
|
+
else
|
|
119
|
+
if till_number.nil?
|
|
120
|
+
if ENV['till_number'].nil? || ENV['till_number'].eql?("")
|
|
121
|
+
raise Exception.new "Till number is not defined"
|
|
122
|
+
else
|
|
123
|
+
ENV['till_number']
|
|
124
|
+
end
|
|
125
|
+
else
|
|
126
|
+
till_number
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
end
|
|
@@ -10,7 +10,7 @@ module MpesaStk
|
|
|
10
10
|
|
|
11
11
|
attr_reader :token, :amount, :phone_number
|
|
12
12
|
|
|
13
|
-
def initialize
|
|
13
|
+
def initialize(amount, phone_number)
|
|
14
14
|
@token = MpesaStk::AccessToken.call
|
|
15
15
|
@amount = amount
|
|
16
16
|
@phone_number = phone_number
|
|
@@ -22,49 +22,50 @@ module MpesaStk
|
|
|
22
22
|
end
|
|
23
23
|
|
|
24
24
|
private
|
|
25
|
-
def url
|
|
26
|
-
"#{ENV['base_url']}#{ENV['process_request_url']}"
|
|
27
|
-
end
|
|
28
25
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
"Content-Type" => "application/json"
|
|
33
|
-
}
|
|
34
|
-
end
|
|
26
|
+
def url
|
|
27
|
+
"#{ENV['base_url']}#{ENV['process_request_url']}"
|
|
28
|
+
end
|
|
35
29
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
Amount: "#{amount}",
|
|
43
|
-
PartyA: "#{phone_number}",
|
|
44
|
-
PartyB: "#{ENV['business_short_code']}",
|
|
45
|
-
PhoneNumber: "#{phone_number}",
|
|
46
|
-
CallBackURL: "#{ENV['callback_url']}",
|
|
47
|
-
AccountReference: generate_bill_reference_number(20),
|
|
48
|
-
TransactionDesc: generate_bill_reference_number(20)
|
|
49
|
-
}.to_json
|
|
50
|
-
end
|
|
30
|
+
def headers
|
|
31
|
+
{
|
|
32
|
+
"Authorization" => "Bearer #{token}",
|
|
33
|
+
"Content-Type" => "application/json"
|
|
34
|
+
}
|
|
35
|
+
end
|
|
51
36
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
37
|
+
def body
|
|
38
|
+
{
|
|
39
|
+
BusinessShortCode: "#{ENV['business_short_code']}",
|
|
40
|
+
Password: generate_password,
|
|
41
|
+
Timestamp: "#{timestamp}",
|
|
42
|
+
TransactionType: "CustomerPayBillOnline",
|
|
43
|
+
Amount: "#{amount}",
|
|
44
|
+
PartyA: "#{phone_number}",
|
|
45
|
+
PartyB: "#{ENV['business_short_code']}",
|
|
46
|
+
PhoneNumber: "#{phone_number}",
|
|
47
|
+
CallBackURL: "#{ENV['callback_url']}",
|
|
48
|
+
AccountReference: generate_bill_reference_number(5),
|
|
49
|
+
TransactionDesc: generate_bill_reference_number(5)
|
|
50
|
+
}.to_json
|
|
51
|
+
end
|
|
56
52
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
53
|
+
def generate_bill_reference_number(number)
|
|
54
|
+
charset = Array('A'..'Z') + Array('a'..'z')
|
|
55
|
+
Array.new(number) { charset.sample }.join
|
|
56
|
+
end
|
|
60
57
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
58
|
+
def timestamp
|
|
59
|
+
DateTime.now.strftime("%Y%m%d%H%M%S").to_i
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# shortcode
|
|
63
|
+
# passkey
|
|
64
|
+
# timestamp
|
|
65
|
+
def generate_password
|
|
66
|
+
key = "#{ENV['business_short_code']}#{ENV['business_passkey']}#{timestamp}"
|
|
67
|
+
Base64.encode64(key).split("\n").join
|
|
68
|
+
end
|
|
68
69
|
|
|
69
70
|
end
|
|
70
71
|
end
|
data/lib/mpesa_stk/version.rb
CHANGED
data/mpesa_stk.gemspec
CHANGED
|
@@ -21,16 +21,16 @@ Gem::Specification.new do |spec|
|
|
|
21
21
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
|
22
22
|
spec.require_paths = ["lib"]
|
|
23
23
|
|
|
24
|
-
spec.add_dependency 'httparty', '
|
|
24
|
+
spec.add_dependency 'httparty', '>= 0.15.6', '< 0.19.0'
|
|
25
25
|
spec.add_dependency 'redis-rack', '~> 2.0', '>= 2.0.2'
|
|
26
26
|
spec.add_dependency 'redis-namespace', '~> 1.5', '>= 1.5.3'
|
|
27
27
|
|
|
28
|
-
spec.add_development_dependency "bundler"
|
|
29
|
-
spec.add_development_dependency "rake", "
|
|
28
|
+
spec.add_development_dependency "bundler"
|
|
29
|
+
spec.add_development_dependency "rake", ">= 12.3.3"
|
|
30
30
|
spec.add_development_dependency "minitest", "~> 5.0"
|
|
31
31
|
|
|
32
32
|
spec.add_development_dependency 'pry', '~> 0.10.4'
|
|
33
33
|
spec.add_development_dependency 'pry-nav', '~> 0.2.4'
|
|
34
34
|
spec.add_development_dependency 'webmock', '~> 3.0', '>= 3.0.1'
|
|
35
|
-
spec.add_development_dependency "dotenv", "2.
|
|
35
|
+
spec.add_development_dependency "dotenv", "2.7.5"
|
|
36
36
|
end
|
metadata
CHANGED
|
@@ -1,30 +1,36 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: mpesa_stk
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: '1.3'
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- mboya
|
|
8
8
|
- cess
|
|
9
|
-
autorequire:
|
|
9
|
+
autorequire:
|
|
10
10
|
bindir: exe
|
|
11
11
|
cert_chain: []
|
|
12
|
-
date:
|
|
12
|
+
date: 2020-06-17 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
|
14
14
|
- !ruby/object:Gem::Dependency
|
|
15
15
|
name: httparty
|
|
16
16
|
requirement: !ruby/object:Gem::Requirement
|
|
17
17
|
requirements:
|
|
18
|
-
- - "
|
|
18
|
+
- - ">="
|
|
19
19
|
- !ruby/object:Gem::Version
|
|
20
20
|
version: 0.15.6
|
|
21
|
+
- - "<"
|
|
22
|
+
- !ruby/object:Gem::Version
|
|
23
|
+
version: 0.19.0
|
|
21
24
|
type: :runtime
|
|
22
25
|
prerelease: false
|
|
23
26
|
version_requirements: !ruby/object:Gem::Requirement
|
|
24
27
|
requirements:
|
|
25
|
-
- - "
|
|
28
|
+
- - ">="
|
|
26
29
|
- !ruby/object:Gem::Version
|
|
27
30
|
version: 0.15.6
|
|
31
|
+
- - "<"
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: 0.19.0
|
|
28
34
|
- !ruby/object:Gem::Dependency
|
|
29
35
|
name: redis-rack
|
|
30
36
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -69,30 +75,30 @@ dependencies:
|
|
|
69
75
|
name: bundler
|
|
70
76
|
requirement: !ruby/object:Gem::Requirement
|
|
71
77
|
requirements:
|
|
72
|
-
- - "
|
|
78
|
+
- - ">="
|
|
73
79
|
- !ruby/object:Gem::Version
|
|
74
|
-
version: '
|
|
80
|
+
version: '0'
|
|
75
81
|
type: :development
|
|
76
82
|
prerelease: false
|
|
77
83
|
version_requirements: !ruby/object:Gem::Requirement
|
|
78
84
|
requirements:
|
|
79
|
-
- - "
|
|
85
|
+
- - ">="
|
|
80
86
|
- !ruby/object:Gem::Version
|
|
81
|
-
version: '
|
|
87
|
+
version: '0'
|
|
82
88
|
- !ruby/object:Gem::Dependency
|
|
83
89
|
name: rake
|
|
84
90
|
requirement: !ruby/object:Gem::Requirement
|
|
85
91
|
requirements:
|
|
86
|
-
- - "
|
|
92
|
+
- - ">="
|
|
87
93
|
- !ruby/object:Gem::Version
|
|
88
|
-
version:
|
|
94
|
+
version: 12.3.3
|
|
89
95
|
type: :development
|
|
90
96
|
prerelease: false
|
|
91
97
|
version_requirements: !ruby/object:Gem::Requirement
|
|
92
98
|
requirements:
|
|
93
|
-
- - "
|
|
99
|
+
- - ">="
|
|
94
100
|
- !ruby/object:Gem::Version
|
|
95
|
-
version:
|
|
101
|
+
version: 12.3.3
|
|
96
102
|
- !ruby/object:Gem::Dependency
|
|
97
103
|
name: minitest
|
|
98
104
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -161,14 +167,14 @@ dependencies:
|
|
|
161
167
|
requirements:
|
|
162
168
|
- - '='
|
|
163
169
|
- !ruby/object:Gem::Version
|
|
164
|
-
version: 2.
|
|
170
|
+
version: 2.7.5
|
|
165
171
|
type: :development
|
|
166
172
|
prerelease: false
|
|
167
173
|
version_requirements: !ruby/object:Gem::Requirement
|
|
168
174
|
requirements:
|
|
169
175
|
- - '='
|
|
170
176
|
- !ruby/object:Gem::Version
|
|
171
|
-
version: 2.
|
|
177
|
+
version: 2.7.5
|
|
172
178
|
description: initiate a M-Pesa transaction on behalf of a customer using STK Push.
|
|
173
179
|
email:
|
|
174
180
|
- mboyaberry@gmail.com
|
|
@@ -177,9 +183,9 @@ executables: []
|
|
|
177
183
|
extensions: []
|
|
178
184
|
extra_rdoc_files: []
|
|
179
185
|
files:
|
|
186
|
+
- ".github/workflows/cop.yml"
|
|
180
187
|
- ".gitignore"
|
|
181
188
|
- ".sample.env"
|
|
182
|
-
- ".travis.yml"
|
|
183
189
|
- CODE_OF_CONDUCT.md
|
|
184
190
|
- Gemfile
|
|
185
191
|
- Gemfile.lock
|
|
@@ -191,6 +197,7 @@ files:
|
|
|
191
197
|
- bin/setup
|
|
192
198
|
- lib/mpesa_stk.rb
|
|
193
199
|
- lib/mpesa_stk/access_token.rb
|
|
200
|
+
- lib/mpesa_stk/push.rb
|
|
194
201
|
- lib/mpesa_stk/push_payment.rb
|
|
195
202
|
- lib/mpesa_stk/version.rb
|
|
196
203
|
- mpesa_stk.gemspec
|
|
@@ -198,7 +205,7 @@ homepage: https://github.com/mboya/mpesa_stk
|
|
|
198
205
|
licenses:
|
|
199
206
|
- MIT
|
|
200
207
|
metadata: {}
|
|
201
|
-
post_install_message:
|
|
208
|
+
post_install_message:
|
|
202
209
|
rdoc_options: []
|
|
203
210
|
require_paths:
|
|
204
211
|
- lib
|
|
@@ -213,9 +220,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
213
220
|
- !ruby/object:Gem::Version
|
|
214
221
|
version: '0'
|
|
215
222
|
requirements: []
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
signing_key:
|
|
223
|
+
rubygems_version: 3.0.8
|
|
224
|
+
signing_key:
|
|
219
225
|
specification_version: 4
|
|
220
226
|
summary: Lipa na M-Pesa Online Payment.
|
|
221
227
|
test_files: []
|