mpesa_stk 1.2.1.1 → 1.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: aac00cb985abf7274869098214e1736ba90c0b26803d4bb0a37537b740ae6b7b
4
- data.tar.gz: 5969725cfc65d13c3a969773fd33da9d040b84a50a9e01aefc95a3be2a8ca71c
3
+ metadata.gz: 12e1c2a4f60b943357593f37099a3ef7e5a9f4c272a0aca0960452b504789fe0
4
+ data.tar.gz: 14c3633244b9867b275a1e10949f4b6880b62c04e42213c6b5b2f4ded24e4dc1
5
5
  SHA512:
6
- metadata.gz: 34f7c15f99680ef3f3f916b06bb03a85e880b6fe598a6d0997816739f108ac6f5c32086cb7d60c53389a539a0811f1d1ee68b0a2c98e9baf47e035b17b52cf4d
7
- data.tar.gz: 9ff781d747187f656c97cc33921a0fb55e31692e8fa264b0be9f99a22c5caaa162489d1bf67c9c61d5b28ce2b3efb1d69114911271f99a5ff15d380fc4a5981b
6
+ metadata.gz: 7fe982c6d29a14a7ab22e2acc16d97b9411666c47edf664c5f77a9e0b398d7b6cf3c031bdd9c9e55003f4fb31a21ecaef65e5eeadb4f7893721c3c466ba06e57
7
+ data.tar.gz: c2dbf612bd39861047a24cf0497a01893ec6b0018ec20ee6f33cc8a36d0964e87172566f0090bcf4e29f076d099192dab6b0e859951029db8d32b38feb04171a
@@ -6,4 +6,5 @@ key=""
6
6
  secret=""
7
7
  business_short_code=""
8
8
  business_passkey=""
9
- callback_url=""
9
+ callback_url="https://api.endpoint/callback"
10
+ till_number=""
@@ -1,8 +1,8 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- mpesa_stk (1.2.1)
5
- httparty (~> 0.15.6)
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
 
@@ -14,11 +14,15 @@ GEM
14
14
  coderay (1.1.2)
15
15
  crack (0.4.3)
16
16
  safe_yaml (~> 1.0.0)
17
- dotenv (2.2.1)
17
+ dotenv (2.7.5)
18
18
  hashdiff (1.0.1)
19
- httparty (0.15.7)
19
+ httparty (0.18.1)
20
+ mime-types (~> 3.0)
20
21
  multi_xml (>= 0.5.2)
21
22
  method_source (0.8.2)
23
+ mime-types (3.3.1)
24
+ mime-types-data (~> 3.2015)
25
+ mime-types-data (3.2020.0512)
22
26
  minitest (5.14.0)
23
27
  multi_xml (0.6.0)
24
28
  pry (0.10.4)
@@ -29,8 +33,8 @@ GEM
29
33
  pry (>= 0.9.10, < 0.11.0)
30
34
  public_suffix (4.0.4)
31
35
  rack (2.2.2)
32
- rake (12.3.3)
33
- redis (4.1.3)
36
+ rake (13.0.1)
37
+ redis (4.2.1)
34
38
  redis-namespace (1.7.0)
35
39
  redis (>= 3.0.4)
36
40
  redis-rack (2.1.2)
@@ -50,7 +54,7 @@ PLATFORMS
50
54
 
51
55
  DEPENDENCIES
52
56
  bundler
53
- dotenv (= 2.2.1)
57
+ dotenv (= 2.7.5)
54
58
  minitest (~> 5.0)
55
59
  mpesa_stk!
56
60
  pry (~> 0.10.4)
data/README.md CHANGED
@@ -1,7 +1,8 @@
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) -->
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)
5
6
 
6
7
  ## Installation
7
8
 
@@ -22,6 +23,14 @@ This gem has a [Redis](https://redis.io/) dependency, so make sure it running
22
23
  ```ruby
23
24
  $ redis-server
24
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
33
+ ```
25
34
 
26
35
  you need to setup your environment variables, checkout `.sample.env` for the values you need.
27
36
  or run
@@ -35,12 +44,19 @@ secret=""
35
44
  business_short_code=""
36
45
  business_passkey=""
37
46
  callback_url=""
47
+ till_number=""
38
48
  ```
39
49
 
40
50
  * `key` and `secret` of the app created on your [developer account](https://developer.safaricom.co.ke/user/me/apps).
41
51
  * `business_short_code` and `business_pass_key` this can be found in [Test Credentials](https://developer.safaricom.co.ke/test_credentials).
42
52
  * `callback_url` the url of your application where response will be sent. `make sure its a reachable/active url`
43
53
 
54
+ `Prod:`
55
+
56
+ when going live there information will be sent to your email.
57
+
58
+ for `buy_goods` push `business_short_code` will be equivalent to `store number` and `till_number` will remain as is.
59
+
44
60
  ### Testing out the gem in an actual Rails application
45
61
 
46
62
  To test out the app on an actual rails application, do check out the following link:
@@ -53,18 +69,39 @@ https://github.com/mboya/stk
53
69
  #### Sample application
54
70
  Check out a rails sample application [here](https://github.com/mboya/stk)
55
71
 
56
- ### Testing the gem on the console
72
+ ### Testing the gem on the console/app
73
+ When running the gem on a single safaricom app.
57
74
 
58
75
  ```ruby
59
76
  $ irb
77
+ 2.5.0 :001 > require 'mpesa_stk'
78
+ 2.5.0 :002 > MpesaStk::PushPayment.call("500", "<YOUR PHONE NUMBER: 254711222333>")
60
79
  ```
61
80
 
81
+ When running the app on multiple safaricom apps, within the same project.
62
82
  ```ruby
63
- 2.5.0 :001 > require 'mpesa_stk'
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
64
93
  ```
65
-
94
+ for STK push
66
95
  ```ruby
67
- 2.5.0 :002 > MpesaStk::PushPayment.call("500", "<YOUR PHONE NUMBER: 254711222333>")
96
+ 2.5.3 :010 > MpesaStk::Push.pay_bill('05', "<YOUR PHONE NUMBER: 254711222333>", hash)
97
+ ```
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"}
68
105
  ```
69
106
 
70
107
  expected irb output after the command
@@ -82,12 +119,21 @@ the above response means the response has been successfully sent to Safaricom fo
82
119
 
83
120
  ### Mpesa Checkout/Express
84
121
  This is the expected output on the mobile phone
122
+
85
123
  ![alt tag](./bin/index.jpeg)
86
124
 
87
125
  ### Callback url
88
126
 
89
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
90
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
+ ```
91
137
 
92
138
  ## Development
93
139
 
@@ -1,4 +1,5 @@
1
1
  require "mpesa_stk/version"
2
2
  require 'mpesa_stk/push_payment'
3
+ require 'mpesa_stk/push'
3
4
  require 'dotenv/load'
4
5
  require 'httparty'
@@ -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
@@ -73,14 +73,14 @@ module MpesaStk
73
73
 
74
74
  def headers
75
75
  encode = encode_credentials @key, @secret
76
- headers = {
77
- "Authorization" => "Basic #{encode}"
76
+ {
77
+ "Authorization" => "Basic #{encode}"
78
78
  }
79
79
  end
80
80
 
81
81
  def encode_credentials key, secret
82
82
  credentials = "#{key}:#{secret}"
83
- encoded_credentials = Base64.encode64(credentials).split("\n").join
83
+ Base64.encode64(credentials).split("\n").join
84
84
  end
85
85
  end
86
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 amount, phone_number
13
+ def initialize(amount, phone_number)
14
14
  @token = MpesaStk::AccessToken.call
15
15
  @amount = amount
16
16
  @phone_number = phone_number
@@ -28,25 +28,25 @@ module MpesaStk
28
28
  end
29
29
 
30
30
  def headers
31
- headers = {
32
- "Authorization" => "Bearer #{token}",
33
- "Content-Type" => "application/json"
31
+ {
32
+ "Authorization" => "Bearer #{token}",
33
+ "Content-Type" => "application/json"
34
34
  }
35
35
  end
36
36
 
37
37
  def body
38
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)
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
50
  }.to_json
51
51
  end
52
52
 
@@ -1,3 +1,3 @@
1
1
  module MpesaStk
2
- VERSION = "1.2.1.1"
2
+ VERSION = "1.3"
3
3
  end
@@ -21,7 +21,7 @@ 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', '~> 0.15.6'
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
 
@@ -32,5 +32,5 @@ Gem::Specification.new do |spec|
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.2.1"
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.2.1.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: 2020-04-10 00:00:00.000000000 Z
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
@@ -161,14 +167,14 @@ dependencies:
161
167
  requirements:
162
168
  - - '='
163
169
  - !ruby/object:Gem::Version
164
- version: 2.2.1
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.2.1
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
@@ -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,8 +220,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
213
220
  - !ruby/object:Gem::Version
214
221
  version: '0'
215
222
  requirements: []
216
- rubygems_version: 3.1.2
217
- signing_key:
223
+ rubygems_version: 3.0.8
224
+ signing_key:
218
225
  specification_version: 4
219
226
  summary: Lipa na M-Pesa Online Payment.
220
227
  test_files: []