mpesa_stk 2.0.0 → 3.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.
@@ -1,160 +1,69 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Copyright (c) 2018 mboya
4
- #
5
- # MIT License
6
- #
7
- # Permission is hereby granted, free of charge, to any person obtaining a copy
8
- # of this software and associated documentation files (the "Software"), to deal
9
- # in the Software without restriction, including without limitation the rights
10
- # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
- # copies of the Software, and to permit persons to whom the Software is
12
- # furnished to do so, subject to the following conditions:
13
- #
14
- # The above copyright notice and this permission notice shall be included in
15
- # all copies or substantial portions of the Software.
16
- #
17
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23
- # THE SOFTWARE.
24
-
25
- require 'date'
26
- require 'mpesa_stk/access_token'
3
+ require 'mpesa_stk/client'
27
4
 
28
5
  module MpesaStk
29
- # Initiates STK Push payment for multiple applications with custom credentials
30
- class Push
31
- class << self
32
- def pay_bill(amount, phone_number, hash = {})
33
- new(amount, phone_number, 'CustomerPayBillOnline', nil, hash['business_short_code'], hash['callback_url'],
34
- hash['business_passkey'], hash['key'], hash['secret']).push_payment
35
- end
6
+ # STK Push (Lipa na M-Pesa): PayBill and Buy Goods.
7
+ #
8
+ # MpesaStk::Push.call(amount, phone) # PayBill, ENV only
9
+ # MpesaStk::Push.call(amount, phone, type: :buy_goods) # Buy Goods
10
+ # MpesaStk::Push.call(amount, phone, key: '...', ...) # per-request overrides
11
+ class Push < Client
12
+ TRANSACTION_TYPES = {
13
+ pay_bill: 'CustomerPayBillOnline',
14
+ buy_goods: 'CustomerBuyGoodsOnline'
15
+ }.freeze
36
16
 
37
- def buy_goods(amount, phone_number, hash = {})
38
- new(amount, phone_number, 'CustomerBuyGoodsOnline', hash['till_number'], hash['business_short_code'],
39
- hash['callback_url'], hash['business_passkey'], hash['key'], hash['secret']).push_payment
17
+ class << self
18
+ def call(amount, phone_number, type: :pay_bill, **options)
19
+ new(amount, phone_number, type: type, **options).push_payment
40
20
  end
41
21
  end
42
22
 
43
- attr_reader :token, :amount, :phone_number, :till_number, :business_short_code, :callback_url, :business_passkey,
44
- :transaction_type
23
+ attr_reader :amount, :phone_number, :transaction_type
45
24
 
46
- def initialize(amount, phone_number, transaction_type, till_number = nil, business_short_code = nil,
47
- callback_url = nil, business_passkey = nil, key = nil, secret = nil)
48
- @token = MpesaStk::AccessToken.call(key, secret)
49
- @transaction_type = transaction_type
50
- @till_number = till_number
51
- @business_short_code = business_short_code
52
- @callback_url = callback_url
53
- @business_passkey = business_passkey
25
+ def initialize(amount, phone_number, type: :pay_bill, **options)
26
+ @transaction_type = TRANSACTION_TYPES.fetch(type) do
27
+ raise ArgumentError, "Unknown STK type: #{type}. Use :pay_bill or :buy_goods"
28
+ end
29
+
30
+ super(**options)
54
31
  @amount = amount
55
32
  @phone_number = phone_number
56
33
  end
57
34
 
58
35
  def push_payment
59
- response = HTTParty.post(url, headers: headers, body: body)
60
-
61
- raise StandardError, "Failed to push payment: #{response.code} - #{response.body}" unless response.success?
62
-
63
- JSON.parse(response.body)
36
+ post('process_request_url', stk_push_payload, error_message: 'Failed to push payment')
64
37
  end
65
38
 
66
39
  private
67
40
 
68
- def url
69
- "#{ENV.fetch('base_url', nil)}#{ENV.fetch('process_request_url', nil)}"
70
- end
71
-
72
- def headers
73
- {
74
- 'Authorization' => "Bearer #{token}",
75
- 'Content-Type' => 'application/json'
76
- }
77
- end
41
+ def stk_push_payload
42
+ short_code, passkey, timestamp = stk_credentials
78
43
 
79
- def body
80
44
  {
81
- BusinessShortCode: get_business_short_code,
82
- Password: generate_password,
45
+ BusinessShortCode: short_code,
46
+ Password: stk_password(short_code, passkey, timestamp),
83
47
  Timestamp: timestamp.to_s,
84
48
  TransactionType: transaction_type,
85
49
  Amount: amount.to_s,
86
50
  PartyA: phone_number.to_s,
87
- PartyB: get_till_number,
51
+ PartyB: party_b(short_code),
88
52
  PhoneNumber: phone_number.to_s,
89
- CallBackURL: get_callback_url,
90
- AccountReference: generate_bill_reference_number(5),
91
- TransactionDesc: generate_bill_reference_number(5)
92
- }.to_json
93
- end
94
-
95
- def generate_bill_reference_number(number)
96
- charset = Array('A'..'Z') + Array('a'..'z')
97
- Array.new(number) { charset.sample }.join
98
- end
99
-
100
- def timestamp
101
- DateTime.now.strftime('%Y%m%d%H%M%S').to_i
102
- end
103
-
104
- # shortcode
105
- # passkey
106
- # timestamp
107
- def generate_password
108
- key = "#{get_business_short_code}#{get_business_passkey}#{timestamp}"
109
- Base64.encode64(key).split("\n").join
110
- end
111
-
112
- def get_business_short_code
113
- if business_short_code.nil? || business_short_code.eql?('')
114
- if ENV['business_short_code'].nil? || ENV['business_short_code'].eql?('')
115
- raise ArgumentError, 'Business Short Code is not defined'
116
- end
117
-
118
- ENV.fetch('business_short_code', nil)
119
-
120
- else
121
- business_short_code
122
- end
123
- end
124
-
125
- def get_business_passkey
126
- if business_passkey.nil? || business_passkey.eql?('')
127
- raise ArgumentError, 'Business Passkey is not defined' if ENV['business_passkey'].nil? || ENV['business_passkey'].eql?('')
128
-
129
- ENV.fetch('business_passkey', nil)
130
-
131
- else
132
- business_passkey
133
- end
53
+ CallBackURL: option('callback_url'),
54
+ AccountReference: random_reference,
55
+ TransactionDesc: random_reference
56
+ }
134
57
  end
135
58
 
136
- def get_callback_url
137
- if callback_url.nil? || callback_url.eql?('')
138
- raise ArgumentError, 'Callback URL is not defined' if ENV['callback_url'].nil? || ENV['callback_url'].eql?('')
139
-
140
- ENV.fetch('callback_url', nil)
141
-
142
- else
143
- callback_url
144
- end
59
+ def stk_credentials
60
+ [option('business_short_code'), option('business_passkey'), stk_timestamp]
145
61
  end
146
62
 
147
- def get_till_number
148
- if transaction_type.eql?('CustomerPayBillOnline')
149
- get_business_short_code
150
- elsif till_number.nil?
151
- raise ArgumentError, 'Till number is not defined' if ENV['till_number'].nil? || ENV['till_number'].eql?('')
63
+ def party_b(short_code)
64
+ return short_code if transaction_type == 'CustomerPayBillOnline'
152
65
 
153
- ENV.fetch('till_number', nil)
154
-
155
- else
156
- till_number
157
- end
66
+ option('till_number')
158
67
  end
159
68
  end
160
69
  end
@@ -1,118 +1,37 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Copyright (c) 2018 mboya
4
- #
5
- # MIT License
6
- #
7
- # Permission is hereby granted, free of charge, to any person obtaining a copy
8
- # of this software and associated documentation files (the "Software"), to deal
9
- # in the Software without restriction, including without limitation the rights
10
- # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
- # copies of the Software, and to permit persons to whom the Software is
12
- # furnished to do so, subject to the following conditions:
13
- #
14
- # The above copyright notice and this permission notice shall be included in
15
- # all copies or substantial portions of the Software.
16
- #
17
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23
- # THE SOFTWARE.
24
-
25
- require 'mpesa_stk/access_token'
3
+ require 'mpesa_stk/client'
26
4
 
27
5
  module MpesaStk
28
- # M-Pesa Ratiba (Standing Orders) - create recurring payments
29
- class Ratiba
6
+ # Create M-Pesa Ratiba standing orders (recurring payments).
7
+ class Ratiba < Client
30
8
  class << self
31
- def create_standing_order(hash = {})
32
- new(hash).create
9
+ def call(amount:, party_a:, start_date:, end_date:, **options)
10
+ new(**options, amount: amount, party_a: party_a, start_date: start_date, end_date: end_date).create
33
11
  end
34
12
  end
35
13
 
36
- attr_reader :token, :standing_order_name, :business_short_code, :transaction_type, :amount, :party_a,
37
- :receiver_party_identifier_type, :callback_url, :account_reference, :transaction_desc,
38
- :frequency, :start_date, :end_date
39
-
40
- def initialize(hash = {})
41
- @token = MpesaStk::AccessToken.call(hash['key'], hash['secret'])
42
- @standing_order_name = hash['standing_order_name'] || 'Standing Order'
43
- @business_short_code = hash['business_short_code'] || ENV.fetch('business_short_code', nil)
44
- @transaction_type = hash['transaction_type'] || 'Standing Order Customer Pay Bill'
45
- @amount = hash['amount']
46
- @party_a = hash['party_a']
47
- @receiver_party_identifier_type = hash['receiver_party_identifier_type'] || '4'
48
- @callback_url = hash['callback_url'] || ENV.fetch('callback_url', nil)
49
- @account_reference = hash['account_reference'] || ''
50
- @transaction_desc = hash['transaction_desc'] || ''
51
- @frequency = hash['frequency'] || '3'
52
- @start_date = hash['start_date']
53
- @end_date = hash['end_date']
54
- end
55
-
56
14
  def create
57
- response = HTTParty.post(url, headers: headers, body: body)
58
-
59
- raise StandardError, "Failed to create standing order: #{response.code} - #{response.body}" unless response.success?
60
-
61
- JSON.parse(response.body)
15
+ post('ratiba_url', ratiba_payload, error_message: 'Failed to create standing order')
62
16
  end
63
17
 
64
18
  private
65
19
 
66
- def url
67
- "#{ENV.fetch('base_url', nil)}#{ENV.fetch('ratiba_url', nil)}"
68
- end
69
-
70
- def headers
20
+ def ratiba_payload
71
21
  {
72
- 'Authorization' => "Bearer #{token}",
73
- 'Content-Type' => 'application/json'
22
+ StandingOrderName: @options.fetch(:standing_order_name, 'Standing Order'),
23
+ BusinessShortCode: option('business_short_code'),
24
+ TransactionType: @options.fetch(:transaction_type, 'Standing Order Customer Pay Bill'),
25
+ Amount: @options.fetch(:amount).to_s,
26
+ PartyA: @options.fetch(:party_a),
27
+ ReceiverPartyIdentifierType: @options.fetch(:receiver_party_identifier_type, '4'),
28
+ CallBackURL: option('callback_url'),
29
+ AccountReference: @options.fetch(:account_reference, ''),
30
+ TransactionDesc: @options.fetch(:transaction_desc, ''),
31
+ Frequency: @options.fetch(:frequency, '3'),
32
+ StartDate: @options.fetch(:start_date),
33
+ EndDate: @options.fetch(:end_date)
74
34
  }
75
35
  end
76
-
77
- def body
78
- {
79
- StandingOrderName: standing_order_name,
80
- BusinessShortCode: get_business_short_code,
81
- TransactionType: transaction_type,
82
- Amount: amount.to_s,
83
- PartyA: party_a,
84
- ReceiverPartyIdentifierType: receiver_party_identifier_type,
85
- CallBackURL: get_callback_url,
86
- AccountReference: account_reference,
87
- TransactionDesc: transaction_desc,
88
- Frequency: frequency,
89
- StartDate: start_date,
90
- EndDate: end_date
91
- }.to_json
92
- end
93
-
94
- def get_business_short_code
95
- if business_short_code.nil? || business_short_code.eql?('')
96
- if ENV['business_short_code'].nil? || ENV['business_short_code'].eql?('')
97
- raise ArgumentError, 'Business Short Code is not defined'
98
- end
99
-
100
- ENV.fetch('business_short_code', nil)
101
-
102
- else
103
- business_short_code
104
- end
105
- end
106
-
107
- def get_callback_url
108
- if callback_url.nil? || callback_url.eql?('')
109
- raise ArgumentError, 'Callback URL is not defined' if ENV['callback_url'].nil? || ENV['callback_url'].eql?('')
110
-
111
- ENV.fetch('callback_url', nil)
112
-
113
- else
114
- callback_url
115
- end
116
- end
117
36
  end
118
37
  end
@@ -1,147 +1,40 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Copyright (c) 2018 mboya
4
- #
5
- # MIT License
6
- #
7
- # Permission is hereby granted, free of charge, to any person obtaining a copy
8
- # of this software and associated documentation files (the "Software"), to deal
9
- # in the Software without restriction, including without limitation the rights
10
- # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
- # copies of the Software, and to permit persons to whom the Software is
12
- # furnished to do so, subject to the following conditions:
13
- #
14
- # The above copyright notice and this permission notice shall be included in
15
- # all copies or substantial portions of the Software.
16
- #
17
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23
- # THE SOFTWARE.
24
-
25
- require 'mpesa_stk/access_token'
3
+ require 'mpesa_stk/client'
26
4
 
27
5
  module MpesaStk
28
- # Reverse M-Pesa transactions (full or partial)
29
- class Reversal
6
+ # Reverse a completed M-Pesa transaction.
7
+ class Reversal < Client
30
8
  class << self
31
- def reverse(transaction_id, amount, hash = {})
32
- new(transaction_id, amount, hash).reverse_transaction
9
+ def call(transaction_id, amount, **options)
10
+ new(transaction_id, amount, **options).reverse_transaction
33
11
  end
34
12
  end
35
13
 
36
- attr_reader :token, :transaction_id, :amount, :initiator, :security_credential, :receiver_party,
37
- :receiver_identifier_type, :result_url, :queue_timeout_url
14
+ attr_reader :transaction_id, :amount
38
15
 
39
- def initialize(transaction_id, amount, hash = {})
40
- @token = MpesaStk::AccessToken.call(hash['key'], hash['secret'])
16
+ def initialize(transaction_id, amount, **options)
17
+ super(**options)
41
18
  @transaction_id = transaction_id
42
19
  @amount = amount
43
- @initiator = hash['initiator'] || ENV.fetch('initiator', nil)
44
- @security_credential = hash['security_credential'] || ENV.fetch('security_credential', nil)
45
- @receiver_party = hash['receiver_party'] || ENV.fetch('business_short_code', nil)
46
- @receiver_identifier_type = hash['receiver_identifier_type'] || '4'
47
- @result_url = hash['result_url'] || ENV.fetch('result_url', nil)
48
- @queue_timeout_url = hash['queue_timeout_url'] || ENV.fetch('queue_timeout_url', nil)
49
20
  end
50
21
 
51
22
  def reverse_transaction
52
- response = HTTParty.post(url, headers: headers, body: body)
53
-
54
- raise StandardError, "Failed to reverse transaction: #{response.code} - #{response.body}" unless response.success?
55
-
56
- JSON.parse(response.body)
57
- end
58
-
59
- private
60
-
61
- def url
62
- "#{ENV.fetch('base_url', nil)}#{ENV.fetch('reversal_url', nil)}"
63
- end
64
-
65
- def headers
66
- {
67
- 'Authorization' => "Bearer #{token}",
68
- 'Content-Type' => 'application/json'
69
- }
70
- end
71
-
72
- def body
73
- {
74
- Initiator: get_initiator,
75
- SecurityCredential: get_security_credential,
76
- CommandID: 'TransactionReversal',
77
- TransactionID: transaction_id,
78
- Amount: amount.to_s,
79
- ReceiverParty: get_receiver_party,
80
- RecieverIdentifierType: receiver_identifier_type,
81
- ResultURL: get_result_url,
82
- QueueTimeOutURL: get_queue_timeout_url
83
- }.to_json
84
- end
85
-
86
- def get_initiator
87
- if initiator.nil? || initiator.eql?('')
88
- raise ArgumentError, 'Initiator is not defined' if ENV['initiator'].nil? || ENV['initiator'].eql?('')
89
-
90
- ENV.fetch('initiator', nil)
91
-
92
- else
93
- initiator
94
- end
95
- end
96
-
97
- def get_security_credential
98
- if security_credential.nil? || security_credential.eql?('')
99
- if ENV['security_credential'].nil? || ENV['security_credential'].eql?('')
100
- raise ArgumentError, 'Security Credential is not defined'
101
- end
102
-
103
- ENV.fetch('security_credential', nil)
104
-
105
- else
106
- security_credential
107
- end
108
- end
109
-
110
- def get_receiver_party
111
- if receiver_party.nil? || receiver_party.eql?('')
112
- if ENV['business_short_code'].nil? || ENV['business_short_code'].eql?('')
113
- raise ArgumentError, 'Receiver Party (Business Short Code) is not defined'
114
- end
115
-
116
- ENV.fetch('business_short_code', nil)
117
-
118
- else
119
- receiver_party
120
- end
121
- end
122
-
123
- def get_result_url
124
- if result_url.nil? || result_url.eql?('')
125
- raise ArgumentError, 'Result URL is not defined' if ENV['result_url'].nil? || ENV['result_url'].eql?('')
126
-
127
- ENV.fetch('result_url', nil)
128
-
129
- else
130
- result_url
131
- end
132
- end
133
-
134
- def get_queue_timeout_url
135
- if queue_timeout_url.nil? || queue_timeout_url.eql?('')
136
- if ENV['queue_timeout_url'].nil? || ENV['queue_timeout_url'].eql?('')
137
- raise ArgumentError, 'Queue Timeout URL is not defined'
138
- end
139
-
140
- ENV.fetch('queue_timeout_url', nil)
141
-
142
- else
143
- queue_timeout_url
144
- end
23
+ post(
24
+ 'reversal_url',
25
+ {
26
+ Initiator: option('initiator'),
27
+ SecurityCredential: option('security_credential'),
28
+ CommandID: 'TransactionReversal',
29
+ TransactionID: transaction_id,
30
+ Amount: amount.to_s,
31
+ ReceiverParty: option('business_short_code', :receiver_party),
32
+ RecieverIdentifierType: @options.fetch(:receiver_identifier_type, '4'),
33
+ ResultURL: option('result_url'),
34
+ QueueTimeOutURL: option('queue_timeout_url')
35
+ },
36
+ error_message: 'Failed to reverse transaction'
37
+ )
145
38
  end
146
39
  end
147
40
  end
@@ -1,109 +1,38 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Copyright (c) 2018 mboya
4
- #
5
- # MIT License
6
- #
7
- # Permission is hereby granted, free of charge, to any person obtaining a copy
8
- # of this software and associated documentation files (the "Software"), to deal
9
- # in the Software without restriction, including without limitation the rights
10
- # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
- # copies of the Software, and to permit persons to whom the Software is
12
- # furnished to do so, subject to the following conditions:
13
- #
14
- # The above copyright notice and this permission notice shall be included in
15
- # all copies or substantial portions of the Software.
16
- #
17
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23
- # THE SOFTWARE.
24
-
25
- require 'date'
26
- require 'mpesa_stk/access_token'
3
+ require 'mpesa_stk/client'
27
4
 
28
5
  module MpesaStk
29
- # Query STK Push transaction status using CheckoutRequestID
30
- class StkPushQuery
6
+ # Query the status of an STK Push checkout request.
7
+ class StkPushQuery < Client
31
8
  class << self
32
- def query(checkout_request_id, hash = {})
33
- new(checkout_request_id, hash).query_status
9
+ def call(checkout_request_id, **options)
10
+ new(checkout_request_id, **options).query_status
34
11
  end
35
12
  end
36
13
 
37
- attr_reader :token, :checkout_request_id, :business_short_code, :business_passkey
14
+ attr_reader :checkout_request_id
38
15
 
39
- def initialize(checkout_request_id, hash = {})
40
- @token = MpesaStk::AccessToken.call(hash['key'], hash['secret'])
16
+ def initialize(checkout_request_id, **options)
17
+ super(**options)
41
18
  @checkout_request_id = checkout_request_id
42
- @business_short_code = hash['business_short_code'] || ENV.fetch('business_short_code', nil)
43
- @business_passkey = hash['business_passkey'] || ENV.fetch('business_passkey', nil)
44
19
  end
45
20
 
46
21
  def query_status
47
- response = HTTParty.post(url, headers: headers, body: body)
48
-
49
- raise StandardError, "Failed to query STK push status: #{response.code} - #{response.body}" unless response.success?
50
-
51
- JSON.parse(response.body)
52
- end
53
-
54
- private
55
-
56
- def url
57
- "#{ENV.fetch('base_url', nil)}#{ENV.fetch('stk_push_query_url', nil)}"
58
- end
59
-
60
- def headers
61
- {
62
- 'Authorization' => "Bearer #{token}",
63
- 'Content-Type' => 'application/json'
64
- }
65
- end
66
-
67
- def body
68
- {
69
- BusinessShortCode: get_business_short_code,
70
- Password: generate_password,
71
- Timestamp: timestamp.to_s,
72
- CheckoutRequestID: checkout_request_id
73
- }.to_json
74
- end
75
-
76
- def timestamp
77
- DateTime.now.strftime('%Y%m%d%H%M%S').to_i
78
- end
79
-
80
- def generate_password
81
- key = "#{get_business_short_code}#{get_business_passkey}#{timestamp}"
82
- Base64.encode64(key).split("\n").join
83
- end
84
-
85
- def get_business_short_code
86
- if business_short_code.nil? || business_short_code.eql?('')
87
- if ENV['business_short_code'].nil? || ENV['business_short_code'].eql?('')
88
- raise ArgumentError, 'Business Short Code is not defined'
89
- end
90
-
91
- ENV.fetch('business_short_code', nil)
92
-
93
- else
94
- business_short_code
95
- end
96
- end
97
-
98
- def get_business_passkey
99
- if business_passkey.nil? || business_passkey.eql?('')
100
- raise ArgumentError, 'Business Passkey is not defined' if ENV['business_passkey'].nil? || ENV['business_passkey'].eql?('')
101
-
102
- ENV.fetch('business_passkey', nil)
103
-
104
- else
105
- business_passkey
106
- end
22
+ short_code = option('business_short_code')
23
+ passkey = option('business_passkey')
24
+ timestamp = stk_timestamp
25
+
26
+ post(
27
+ 'stk_push_query_url',
28
+ {
29
+ BusinessShortCode: short_code,
30
+ Password: stk_password(short_code, passkey, timestamp),
31
+ Timestamp: timestamp.to_s,
32
+ CheckoutRequestID: checkout_request_id
33
+ },
34
+ error_message: 'Failed to query STK push status'
35
+ )
107
36
  end
108
37
  end
109
38
  end