mpesa_stk 1.0.2 → 1.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
[![Gem Version](https://badge.fury.io/rb/mpesa_stk.svg)](https://badge.fury.io/rb/mpesa_stk.svg)
|
5
|
+
![Cop](https://github.com/mboya/mpesa_stk/workflows/Cop/badge.svg?branch=master)
|
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
|
+
![alt tag](./bin/index.jpeg)
|
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: []
|