mpesa_stk 1.2.1.1 → 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 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: []