From c773f442ca1a906983cd2a1b138cf3aa811e68bc Mon Sep 17 00:00:00 2001 From: NLSanyu Date: Tue, 18 Feb 2020 17:10:20 +0300 Subject: [PATCH 01/16] Add remittance and disbursement classes --- lib/momoapi-ruby/disbursement.rb | 9 +++++++++ lib/momoapi-ruby/remittance.rb | 7 +++++++ 2 files changed, 16 insertions(+) create mode 100644 lib/momoapi-ruby/disbursement.rb create mode 100644 lib/momoapi-ruby/remittance.rb diff --git a/lib/momoapi-ruby/disbursement.rb b/lib/momoapi-ruby/disbursement.rb new file mode 100644 index 0000000..4be2688 --- /dev/null +++ b/lib/momoapi-ruby/disbursement.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +require 'momoapi-ruby/config' +require 'momoapi-ruby/client' + +module Momoapi + class Disbursement < Client + end +end \ No newline at end of file diff --git a/lib/momoapi-ruby/remittance.rb b/lib/momoapi-ruby/remittance.rb new file mode 100644 index 0000000..081f0ff --- /dev/null +++ b/lib/momoapi-ruby/remittance.rb @@ -0,0 +1,7 @@ +require 'momoapi-ruby/config' +require 'momoapi-ruby/client' + +module Momoapi + class Remittance < Client + end +end \ No newline at end of file From 4437b7e69bc25f53d4bb9068a1d6e33d5af39952 Mon Sep 17 00:00:00 2001 From: NLSanyu Date: Thu, 20 Feb 2020 13:34:39 +0300 Subject: [PATCH 02/16] Add auth token to requests --- lib/momoapi-ruby/client.rb | 48 +++++++++++++++++++++++++++----- lib/momoapi-ruby/collection.rb | 2 +- lib/momoapi-ruby/disbursement.rb | 2 +- lib/momoapi-ruby/errors.rb | 2 +- lib/momoapi-ruby/remittance.rb | 4 ++- lib/momoapi-ruby/request.rb | 31 --------------------- spec/features/collection_spec.rb | 23 +++++++++++++++ 7 files changed, 70 insertions(+), 42 deletions(-) create mode 100644 spec/features/collection_spec.rb diff --git a/lib/momoapi-ruby/client.rb b/lib/momoapi-ruby/client.rb index 0c82d4a..c8258f3 100644 --- a/lib/momoapi-ruby/client.rb +++ b/lib/momoapi-ruby/client.rb @@ -1,19 +1,54 @@ # frozen_string_literal: true +require 'faraday' +require 'pry' + require 'momoapi-ruby/config' require 'momoapi-ruby/request' module Momoapi class Client - def initialize; end + def send_request(method, path, headers, _body) + auth_token = get_auth_token['access_token'] + conn = Faraday.new(url: Momoapi.config.base_url) + conn.headers = headers + conn.authorization(:Bearer, auth_token) + + case method + when 'get' + response = conn.get(path) + when 'post' + response = conn.post(path) + end + # puts interpret_response(resp) + puts response.inspect + end + + def interpret_response(response) + response_code = response.status + response_body = response.body + { + body: response_body, + code: response_code + } + end + + def handle_error_response + # TO DO: Add error handling + end def get_auth_token(path, subscription_key) headers = { "Ocp-Apim-Subscription-Key": subscription_key } - body = {} - r = Request.new('post', path, headers, body) - r.send_request + username = Momoapi.config.collection_user_id + password = Momoapi.config.collection_api_secret + url = Momoapi.config.base_url + conn = Faraday.new(url: url) + conn.headers = headers + conn.basic_auth(username, password) + response = conn.post(path) + JSON.parse(response.body) end def get_balance(path, subscription_key) @@ -23,8 +58,7 @@ def get_balance(path, subscription_key) "Ocp-Apim-Subscription-Key": subscription_key } body = {} - r = Request.new('get', path, headers, body) - r.send_request + send_request('get', path, headers, body) end def get_transaction_status(_transaction_id, path, subscription_key) @@ -34,7 +68,7 @@ def get_transaction_status(_transaction_id, path, subscription_key) "Ocp-Apim-Subscription-Key": subscription_key } body = {} - Request.new('get', path, headers, body).send_request + send_request('get', path, headers, body).send_request end end end diff --git a/lib/momoapi-ruby/collection.rb b/lib/momoapi-ruby/collection.rb index 94e7f03..dff6846 100644 --- a/lib/momoapi-ruby/collection.rb +++ b/lib/momoapi-ruby/collection.rb @@ -11,7 +11,7 @@ def get_auth_token end def get_balance - path = '/collection/v1_0/account/balance/' + path = '/collection/v1_0/account/balance' super(path, Momoapi.config.collection_primary_key) end diff --git a/lib/momoapi-ruby/disbursement.rb b/lib/momoapi-ruby/disbursement.rb index 4be2688..99696a6 100644 --- a/lib/momoapi-ruby/disbursement.rb +++ b/lib/momoapi-ruby/disbursement.rb @@ -6,4 +6,4 @@ module Momoapi class Disbursement < Client end -end \ No newline at end of file +end diff --git a/lib/momoapi-ruby/errors.rb b/lib/momoapi-ruby/errors.rb index 9d535c3..9922db4 100644 --- a/lib/momoapi-ruby/errors.rb +++ b/lib/momoapi-ruby/errors.rb @@ -1,4 +1,4 @@ # frozen_string_literal: true -class APIError +class APIError < StandardError end diff --git a/lib/momoapi-ruby/remittance.rb b/lib/momoapi-ruby/remittance.rb index 081f0ff..d689798 100644 --- a/lib/momoapi-ruby/remittance.rb +++ b/lib/momoapi-ruby/remittance.rb @@ -1,7 +1,9 @@ +# frozen_string_literal: true + require 'momoapi-ruby/config' require 'momoapi-ruby/client' module Momoapi class Remittance < Client end -end \ No newline at end of file +end diff --git a/lib/momoapi-ruby/request.rb b/lib/momoapi-ruby/request.rb index 90434af..2b55d19 100644 --- a/lib/momoapi-ruby/request.rb +++ b/lib/momoapi-ruby/request.rb @@ -10,35 +10,4 @@ def initialize(method, path, headers, body) @headers = headers @body = body end - - def send_request - username = Momoapi.config.collection_user_id - password = Momoapi.config.collection_api_secret - conn = Faraday.new(url: @url) - conn.headers = @headers - conn.basic_auth(username, password) - - case @method - when 'get' - @resp = conn.get(@path) - when 'post' - @resp = conn.post(@path) - end - puts @resp - puts @resp.inspect - puts interpret_response(@resp) - end - - def interpret_response(response) - response_code = response.status - response_body = response.body - { - body: response_body, - code: response_code - } - end - - def handle_error_response - # TO DO: Add error handling - end end diff --git a/spec/features/collection_spec.rb b/spec/features/collection_spec.rb new file mode 100644 index 0000000..d79e610 --- /dev/null +++ b/spec/features/collection_spec.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Momoapi::Collection do + before do + Momoapi.configure do |config| + config.base_url = 'https://sandbox.momodeveloper.mtn.com' + config.callback_host = 'https://webhook.site/8e412414-2154-4d06-90c4-5e141c9f2910' + config.collection_primary_key = 'b5e0f061fa5a4cbbbd2192530b7cedfb' + config.collection_user_id = '783a8f21-3fc6-4e39-aa76-da8e562fba7e' + config.collection_api_secret = '313cfaf9a40b4029b7139f4c9d8afb23' + end + end + + # context 'valid credentials' do + # it 'generates an auth token' do + # @collection = Momoapi::Collection.new + # @collection.get_auth_token + # # expect(token).to have_http_status 200 + # end + # end +end From ced6859e3769fe7ed69b4ee29941181b087808a8 Mon Sep 17 00:00:00 2001 From: NLSanyu Date: Thu, 20 Feb 2020 14:51:11 +0300 Subject: [PATCH 03/16] Fix ci reference error --- .travis.yml | 3 +++ lib/momoapi-ruby/client.rb | 4 ++-- lib/momoapi-ruby/collection.rb | 3 +-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 2103175..4a81fce 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,3 +5,6 @@ cache: bundler rvm: - 2.5.3 before_install: gem install bundler -v 2.0.2 +git: + depth: 25 + quiet: true diff --git a/lib/momoapi-ruby/client.rb b/lib/momoapi-ruby/client.rb index c8258f3..d701900 100644 --- a/lib/momoapi-ruby/client.rb +++ b/lib/momoapi-ruby/client.rb @@ -61,14 +61,14 @@ def get_balance(path, subscription_key) send_request('get', path, headers, body) end - def get_transaction_status(_transaction_id, path, subscription_key) + def get_transaction_status(path, subscription_key) headers = { "X-Target-Environment": 'sandbox', "Content-Type": 'application/json', "Ocp-Apim-Subscription-Key": subscription_key } body = {} - send_request('get', path, headers, body).send_request + send_request('get', path, headers, body) end end end diff --git a/lib/momoapi-ruby/collection.rb b/lib/momoapi-ruby/collection.rb index dff6846..1df7347 100644 --- a/lib/momoapi-ruby/collection.rb +++ b/lib/momoapi-ruby/collection.rb @@ -41,8 +41,7 @@ def request_to_pay(phone_number, amount, external_id, "amount": amount.to_s } path = '/collection/v1_0/requesttopay/' - r = Request.new('post', path, headers, body) - r.send_request + send_request('post', path, headers, body) end end end From 808d710b19ca7afc25b899ff11b1c478ff559751 Mon Sep 17 00:00:00 2001 From: NLSanyu Date: Fri, 21 Feb 2020 11:00:55 +0300 Subject: [PATCH 04/16] Refactor client to handle non-error response --- lib/momoapi-ruby/client.rb | 34 ++++++++++++++++------------------ lib/momoapi-ruby/collection.rb | 2 +- lib/momoapi-ruby/request.rb | 13 ------------- 3 files changed, 17 insertions(+), 32 deletions(-) delete mode 100644 lib/momoapi-ruby/request.rb diff --git a/lib/momoapi-ruby/client.rb b/lib/momoapi-ruby/client.rb index d701900..a938433 100644 --- a/lib/momoapi-ruby/client.rb +++ b/lib/momoapi-ruby/client.rb @@ -1,14 +1,13 @@ # frozen_string_literal: true require 'faraday' -require 'pry' require 'momoapi-ruby/config' -require 'momoapi-ruby/request' +require 'momoapi-ruby/errors' module Momoapi class Client - def send_request(method, path, headers, _body) + def send_request(method, path, headers, *_body) auth_token = get_auth_token['access_token'] conn = Faraday.new(url: Momoapi.config.base_url) conn.headers = headers @@ -20,22 +19,23 @@ def send_request(method, path, headers, _body) when 'post' response = conn.post(path) end - # puts interpret_response(resp) - puts response.inspect + interpret_response(response) end - def interpret_response(response) - response_code = response.status - response_body = response.body - { - body: response_body, - code: response_code + def interpret_response(resp) + response = { + body: JSON.parse(resp.body), + code: resp.status } + # unless 200 <= resp.status && resp.status < 300 + # handle_error(response[:code], response[:body]) + # end + response end - def handle_error_response - # TO DO: Add error handling - end + # def handle_error(response_code, response_body) + # raise APIError(response_code, response_body) + # end def get_auth_token(path, subscription_key) headers = { @@ -57,8 +57,7 @@ def get_balance(path, subscription_key) "Content-Type": 'application/json', "Ocp-Apim-Subscription-Key": subscription_key } - body = {} - send_request('get', path, headers, body) + send_request('get', path, headers) end def get_transaction_status(path, subscription_key) @@ -67,8 +66,7 @@ def get_transaction_status(path, subscription_key) "Content-Type": 'application/json', "Ocp-Apim-Subscription-Key": subscription_key } - body = {} - send_request('get', path, headers, body) + send_request('get', path, headers) end end end diff --git a/lib/momoapi-ruby/collection.rb b/lib/momoapi-ruby/collection.rb index 1df7347..235e7f9 100644 --- a/lib/momoapi-ruby/collection.rb +++ b/lib/momoapi-ruby/collection.rb @@ -40,7 +40,7 @@ def request_to_pay(phone_number, amount, external_id, "currency": currency, "amount": amount.to_s } - path = '/collection/v1_0/requesttopay/' + path = '/collection/v1_0/requesttopay' send_request('post', path, headers, body) end end diff --git a/lib/momoapi-ruby/request.rb b/lib/momoapi-ruby/request.rb deleted file mode 100644 index 2b55d19..0000000 --- a/lib/momoapi-ruby/request.rb +++ /dev/null @@ -1,13 +0,0 @@ -# frozen_string_literal: true - -require 'faraday' - -class Request - def initialize(method, path, headers, body) - @method = method.downcase - @url = 'https://sandbox.momodeveloper.mtn.com' - @path = path - @headers = headers - @body = body - end -end From 432a5bd5c78792bb4a7193c90ba451265c995c27 Mon Sep 17 00:00:00 2001 From: NLSanyu Date: Fri, 21 Feb 2020 11:16:35 +0300 Subject: [PATCH 05/16] Add common functionality to all products --- lib/momoapi-ruby/config.rb | 11 ++++++++++- lib/momoapi-ruby/disbursement.rb | 16 ++++++++++++++++ lib/momoapi-ruby/remittance.rb | 16 ++++++++++++++++ 3 files changed, 42 insertions(+), 1 deletion(-) diff --git a/lib/momoapi-ruby/config.rb b/lib/momoapi-ruby/config.rb index 6ae8a65..c38362b 100644 --- a/lib/momoapi-ruby/config.rb +++ b/lib/momoapi-ruby/config.rb @@ -4,7 +4,10 @@ module Momoapi class Config attr_accessor :environment, :base_url, :callback_host, :collection_primary_key, - :collection_user_id, :collection_api_secret + :collection_user_id, :collection_api_secret, + :disbursement_primary_key, :disbursement_user_id, + :disbursement_api_secret, :remittance_primary_key, + :remittance_user_id, :remittance_api_secret def initialize @environment = nil @@ -13,6 +16,12 @@ def initialize @collection_primary_key = nil @collection_user_id = nil @collection_api_secret = nil + @disbursement_primary_key = nil + @disbursement_user_id = nil + @disbursement_api_secret = nil + @remittance_primary_key = nil + @remittance_user_id = nil + @remittance_api_secret = nil end end end diff --git a/lib/momoapi-ruby/disbursement.rb b/lib/momoapi-ruby/disbursement.rb index 99696a6..ac6e56f 100644 --- a/lib/momoapi-ruby/disbursement.rb +++ b/lib/momoapi-ruby/disbursement.rb @@ -5,5 +5,21 @@ module Momoapi class Disbursement < Client + def get_auth_token + path = 'disbursement/token' + super(path, Momoapi.config.disbursement_primary_key) + end + + def get_balance + path = '/disbursement/v1_0/account/balance' + super(path, Momoapi.config.disbursement_primary_key) + end + + def get_transaction_status(transaction_id) + path = "/disbursement/v1_0/transfer/#{transaction_id}" + super(path, Momoapi.config.disbursement_primary_key) + end + + def transfer; end end end diff --git a/lib/momoapi-ruby/remittance.rb b/lib/momoapi-ruby/remittance.rb index d689798..e86c46a 100644 --- a/lib/momoapi-ruby/remittance.rb +++ b/lib/momoapi-ruby/remittance.rb @@ -5,5 +5,21 @@ module Momoapi class Remittance < Client + def get_auth_token + path = 'remittance/token' + super(path, Momoapi.config.remittance_primary_key) + end + + def get_balance + path = '/remittance/v1_0/account/balance' + super(path, Momoapi.config.remittance_primary_key) + end + + def get_transaction_status(transaction_id) + path = "/remittance/v1_0/transfer/#{transaction_id}" + super(path, Momoapi.config.remittance_primary_key) + end + + def transfer; end end end From a55e7ac9a19e7d1e806b42a2d6cda14315fa7c81 Mon Sep 17 00:00:00 2001 From: NLSanyu Date: Fri, 21 Feb 2020 11:32:00 +0300 Subject: [PATCH 06/16] Add error handling --- lib/momoapi-ruby/errors.rb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/momoapi-ruby/errors.rb b/lib/momoapi-ruby/errors.rb index 9922db4..75d6492 100644 --- a/lib/momoapi-ruby/errors.rb +++ b/lib/momoapi-ruby/errors.rb @@ -1,4 +1,7 @@ # frozen_string_literal: true class APIError < StandardError + def initialize(_title, code, message) + super(title: title, status: code, detail: message) + end end From 5ba00799ce2afe4dd17aa879b2994e3b0a755b5b Mon Sep 17 00:00:00 2001 From: NLSanyu Date: Mon, 24 Feb 2020 14:33:53 +0300 Subject: [PATCH 07/16] Add target environment --- lib/momoapi-ruby/cli.rb | 3 ++- lib/momoapi-ruby/client.rb | 4 ++-- lib/momoapi-ruby/collection.rb | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/momoapi-ruby/cli.rb b/lib/momoapi-ruby/cli.rb index 0d58696..2a367a5 100644 --- a/lib/momoapi-ruby/cli.rb +++ b/lib/momoapi-ruby/cli.rb @@ -38,7 +38,8 @@ def generate_api_key req.headers['Ocp-Apim-Subscription-Key'] = @key end if response.status == 201 - puts " User ID: #{@uuid} \n API key: #{response.body}" + key = JSON.parse(response.body) + puts " User ID: #{@uuid} \n API key: #{key["apiKey"]}" else # TO DO: Add error handling here puts 'Error creating API key' diff --git a/lib/momoapi-ruby/client.rb b/lib/momoapi-ruby/client.rb index a938433..ff7169b 100644 --- a/lib/momoapi-ruby/client.rb +++ b/lib/momoapi-ruby/client.rb @@ -53,7 +53,7 @@ def get_auth_token(path, subscription_key) def get_balance(path, subscription_key) headers = { - "X-Target-Environment": 'sandbox', + "X-Target-Environment": Momoapi.config.environment || 'sandbox', "Content-Type": 'application/json', "Ocp-Apim-Subscription-Key": subscription_key } @@ -62,7 +62,7 @@ def get_balance(path, subscription_key) def get_transaction_status(path, subscription_key) headers = { - "X-Target-Environment": 'sandbox', + "X-Target-Environment": Momoapi.config.environment || 'sandbox', "Content-Type": 'application/json', "Ocp-Apim-Subscription-Key": subscription_key } diff --git a/lib/momoapi-ruby/collection.rb b/lib/momoapi-ruby/collection.rb index 235e7f9..7d24e2d 100644 --- a/lib/momoapi-ruby/collection.rb +++ b/lib/momoapi-ruby/collection.rb @@ -24,7 +24,7 @@ def request_to_pay(phone_number, amount, external_id, payee_note = '', payer_message = '', currency = 'EUR') uuid = Faraday.get('https://www.uuidgenerator.net/api/version4').body.chomp headers = { - "X-Target-Environment": 'sandbox', + "X-Target-Environment": Momoapi.config.environment || 'sandbox', "Content-Type": 'application/json', "X-Reference-Id": uuid, "Ocp-Apim-Subscription-Key": Momoapi.config.collection_primary_key From 796ea23ef0cc40f54bd5d02235534c8e86df03f0 Mon Sep 17 00:00:00 2001 From: NLSanyu Date: Tue, 25 Feb 2020 16:12:57 +0300 Subject: [PATCH 08/16] Add error handling --- lib/momoapi-ruby/cli.rb | 31 +++++++++++++++++-------------- lib/momoapi-ruby/client.rb | 14 +++++++------- lib/momoapi-ruby/collection.rb | 5 ++++- lib/momoapi-ruby/errors.rb | 9 ++++++--- 4 files changed, 34 insertions(+), 25 deletions(-) diff --git a/lib/momoapi-ruby/cli.rb b/lib/momoapi-ruby/cli.rb index 2a367a5..5b31b1f 100644 --- a/lib/momoapi-ruby/cli.rb +++ b/lib/momoapi-ruby/cli.rb @@ -1,13 +1,17 @@ # frozen_string_literal: true -require 'momoapi-ruby' require 'faraday' require 'json' +require 'securerandom' + +require 'momoapi-ruby/config' +require 'momoapi-ruby/errors' +require 'momoapi-ruby' module Momoapi class CLI def initialize(option) - @uuid = Faraday.get('https://www.uuidgenerator.net/api/version4').body.chomp + @uuid = SecureRandom.uuid @host = option[:host] @key = option[:key] create_sandbox_user @@ -22,28 +26,27 @@ def create_sandbox_user req.headers['Ocp-Apim-Subscription-Key'] = @key req.body = body.to_json end - if response.status == 201 - generate_api_key - else - # TO DO: Add error handling here - puts response.body + + unless response.status == 201 + raise Error::APIError.new(response.body, response.status) end + + generate_api_key end def generate_api_key @url = 'https://sandbox.momodeveloper.mtn.com/v1_0/apiuser/' + @uuid + '/apikey' - puts @url response = Faraday.post(@url) do |req| req.headers['Ocp-Apim-Subscription-Key'] = @key end - if response.status == 201 - key = JSON.parse(response.body) - puts " User ID: #{@uuid} \n API key: #{key["apiKey"]}" - else - # TO DO: Add error handling here - puts 'Error creating API key' + + unless response.status == 201 + raise Error::APIError.new(response.body, response.status) end + + key = JSON.parse(response.body) + puts "\n User ID: #{@uuid} \n API key: #{key['apiKey']} \n\n" end end end diff --git a/lib/momoapi-ruby/client.rb b/lib/momoapi-ruby/client.rb index ff7169b..9b7df84 100644 --- a/lib/momoapi-ruby/client.rb +++ b/lib/momoapi-ruby/client.rb @@ -24,18 +24,18 @@ def send_request(method, path, headers, *_body) def interpret_response(resp) response = { - body: JSON.parse(resp.body), + body: resp.body, code: resp.status } - # unless 200 <= resp.status && resp.status < 300 - # handle_error(response[:code], response[:body]) - # end + unless resp.status >= 200 && resp.status < 300 + handle_error(response[:body], response[:status]) + end response end - # def handle_error(response_code, response_body) - # raise APIError(response_code, response_body) - # end + def handle_error(response_body, response_code) + raise Error::APIError.new(response_body, response_code) + end def get_auth_token(path, subscription_key) headers = { diff --git a/lib/momoapi-ruby/collection.rb b/lib/momoapi-ruby/collection.rb index 7d24e2d..b0e2ef2 100644 --- a/lib/momoapi-ruby/collection.rb +++ b/lib/momoapi-ruby/collection.rb @@ -1,5 +1,7 @@ # frozen_string_literal: true +require 'securerandom' + require 'momoapi-ruby/config' require 'momoapi-ruby/client' @@ -22,7 +24,7 @@ def get_transaction_status(transaction_id) def request_to_pay(phone_number, amount, external_id, payee_note = '', payer_message = '', currency = 'EUR') - uuid = Faraday.get('https://www.uuidgenerator.net/api/version4').body.chomp + uuid = SecureRandom.uuid headers = { "X-Target-Environment": Momoapi.config.environment || 'sandbox', "Content-Type": 'application/json', @@ -42,6 +44,7 @@ def request_to_pay(phone_number, amount, external_id, } path = '/collection/v1_0/requesttopay' send_request('post', path, headers, body) + uuid end end end diff --git a/lib/momoapi-ruby/errors.rb b/lib/momoapi-ruby/errors.rb index 75d6492..15f7c87 100644 --- a/lib/momoapi-ruby/errors.rb +++ b/lib/momoapi-ruby/errors.rb @@ -1,7 +1,10 @@ # frozen_string_literal: true -class APIError < StandardError - def initialize(_title, code, message) - super(title: title, status: code, detail: message) +module Error + class APIError < StandardError + def initialize(message, code) + @code = code + super(message) + end end end From fed3a5f355fba0d96f14238a7d9f68175dd40ca5 Mon Sep 17 00:00:00 2001 From: NLSanyu Date: Wed, 26 Feb 2020 19:17:43 +0300 Subject: [PATCH 09/16] Document collections --- README.md | 35 +++++++++++++++++++++++++++++++++-- bin/setup | 2 -- 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 6160629..97647c6 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ Or install it yourself as: Type this command into your terminal: ``` -momoapi --host Your-Provider-Callback-Host --key Your-Ocp-Apim-Subscription-Key +momoapi-ruby --host Your-Provider-Callback-Host --key Your-Ocp-Apim-Subscription-Key ``` A User ID and API Key will be generated: @@ -37,7 +37,6 @@ API key: Generated API key ``` ## Using live credentials - Add the following configurations in an initializer file (for example, `config/initializers/momoapi-ruby.rb` in a Rails app): ``` @@ -50,6 +49,38 @@ Momoapi.configure do |config| end ``` +## Collections +The collections client can be created with the following paramaters. Note that the `COLLECTION_USER_ID` and `COLLECTION_API_SECRET` for production are provided on the MTN OVA dashboard; + +* `collection_primary_key`: Primary Key for the `Collection` product on the developer portal. +* `collection_user_id`: For sandbox, use the one generated with the `momoapi-ruby` command. +* `collection_api_secret`: For sandbox, use the one generated with the `momoapi-ruby` command. + +You can create a collection client with the following: + +```ruby +require 'momoapi-ruby' + +collection = Momoapi::Collection.new +``` + +### Methods +1. `request_to_pay`: This operation is used to request a payment from a consumer (Payer). The payer will be asked to authorize the payment. The transaction is executed once the payer has authorized the payment. The transaction will be in status PENDING until it is authorized or declined by the payer or it is timed out by the system. Status of the transaction can be validated by using `get_transaction_status`. + +2. `get_transaction_status`: Retrieve transaction information using the `transaction_id` returned by `request_to_pay`. You can invoke it at intervals until the transaction fails or succeeds. If the transaction has failed, it will throw an appropriate error. + +3. `get_balance`: Get the balance of the account. + +### Sample Code + +```ruby +require 'momoapi-ruby' + +collection = Momoapi::Collection.new +collection.requestToPay( + mobile="256772123456", amount="600", external_id="123456789", payee_note="dd", payer_message="dd", currency="EUR") +``` + ## Contributing Bug reports and pull requests are welcome on GitHub at https://github.com/sparkplug/momoapi-ruby. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct. diff --git a/bin/setup b/bin/setup index dce67d8..cf4ad25 100755 --- a/bin/setup +++ b/bin/setup @@ -4,5 +4,3 @@ IFS=$'\n\t' set -vx bundle install - -# Do any other automated setup that you need to do here From db4fa874dd3584d03804a3127fd8d10a9bc75756 Mon Sep 17 00:00:00 2001 From: NLSanyu Date: Thu, 27 Feb 2020 16:03:39 +0300 Subject: [PATCH 10/16] Implement disbursements --- lib/momoapi-ruby.rb | 1 + lib/momoapi-ruby/client.rb | 8 +- lib/momoapi-ruby/disbursement.rb | 27 ++- .../collections/gets_balance.yml | 43 +++++ .../collections/gets_transaction_status.yml | 43 +++++ .../collections/makes_request_to_pay.yml | 43 +++++ .../disbursements/gets_balance.yml | 120 +++++++++++++ .../disbursements/gets_transaction_status.yml | 158 ++++++++++++++++++ .../disbursements/makes_transfer.yml | 122 ++++++++++++++ spec/features/disbursement_spec.rb | 38 +++++ 10 files changed, 599 insertions(+), 4 deletions(-) create mode 100644 spec/cassettes/Momoapi_Disbursement/collections/gets_balance.yml create mode 100644 spec/cassettes/Momoapi_Disbursement/collections/gets_transaction_status.yml create mode 100644 spec/cassettes/Momoapi_Disbursement/collections/makes_request_to_pay.yml create mode 100644 spec/cassettes/Momoapi_Disbursement/disbursements/gets_balance.yml create mode 100644 spec/cassettes/Momoapi_Disbursement/disbursements/gets_transaction_status.yml create mode 100644 spec/cassettes/Momoapi_Disbursement/disbursements/makes_transfer.yml create mode 100644 spec/features/disbursement_spec.rb diff --git a/lib/momoapi-ruby.rb b/lib/momoapi-ruby.rb index f33fb1e..f6ad45a 100644 --- a/lib/momoapi-ruby.rb +++ b/lib/momoapi-ruby.rb @@ -4,6 +4,7 @@ require 'momoapi-ruby/version' require 'momoapi-ruby/cli' require 'momoapi-ruby/collection' +require 'momoapi-ruby/disbursement' module Momoapi class << self diff --git a/lib/momoapi-ruby/client.rb b/lib/momoapi-ruby/client.rb index 9b7df84..0f6c570 100644 --- a/lib/momoapi-ruby/client.rb +++ b/lib/momoapi-ruby/client.rb @@ -28,7 +28,7 @@ def interpret_response(resp) code: resp.status } unless resp.status >= 200 && resp.status < 300 - handle_error(response[:body], response[:status]) + handle_error(response[:body], response[:code]) end response end @@ -48,7 +48,11 @@ def get_auth_token(path, subscription_key) conn.headers = headers conn.basic_auth(username, password) response = conn.post(path) - JSON.parse(response.body) + begin + JSON.parse(response.body) + rescue JSON::ParserError + response.body.to_s + end end def get_balance(path, subscription_key) diff --git a/lib/momoapi-ruby/disbursement.rb b/lib/momoapi-ruby/disbursement.rb index ac6e56f..c1a5537 100644 --- a/lib/momoapi-ruby/disbursement.rb +++ b/lib/momoapi-ruby/disbursement.rb @@ -6,7 +6,7 @@ module Momoapi class Disbursement < Client def get_auth_token - path = 'disbursement/token' + path = 'disbursement/token/' super(path, Momoapi.config.disbursement_primary_key) end @@ -20,6 +20,29 @@ def get_transaction_status(transaction_id) super(path, Momoapi.config.disbursement_primary_key) end - def transfer; end + def transfer(phone_number, amount, external_id, + payee_note = '', payer_message = '', currency = 'EUR') + uuid = SecureRandom.uuid + headers = { + "X-Target-Environment": Momoapi.config.environment || 'sandbox', + "Content-Type": 'application/json', + "X-Reference-Id": uuid, + "Ocp-Apim-Subscription-Key": Momoapi.config.disbursement_primary_key + } + body = { + "payer": { + "partyIdType": 'MSISDN', + "partyId": phone_number + }, + "payeeNote": payee_note, + "payerMessage": payer_message, + "externalId": external_id, + "currency": currency, + "amount": amount.to_s + } + path = '/disbursement/v1_0/transfer' + send_request('post', path, headers, body) + { transaction_reference: uuid } + end end end diff --git a/spec/cassettes/Momoapi_Disbursement/collections/gets_balance.yml b/spec/cassettes/Momoapi_Disbursement/collections/gets_balance.yml new file mode 100644 index 0000000..46f9dba --- /dev/null +++ b/spec/cassettes/Momoapi_Disbursement/collections/gets_balance.yml @@ -0,0 +1,43 @@ +--- +http_interactions: +- request: + method: post + uri: https://sandbox.momodeveloper.mtn.com/disbursement/token + body: + encoding: UTF-8 + string: '' + headers: + Ocp-Apim-Subscription-Key: + - b5e0f061fa5a4cbbbd2192530b7cedfb + Authorization: + - Basic NzgzYThmMjEtM2ZjNi00ZTM5LWFhNzYtZGE4ZTU2MmZiYTdlOjMxM2NmYWY5YTQwYjQwMjliNzEzOWY0YzlkOGFmYjIz + Content-Length: + - '0' + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + response: + status: + code: 401 + message: Access Denied + headers: + Content-Length: + - '143' + Content-Type: + - application/json + Request-Context: + - appId=cid-v1:e996501c-e721-4ac1-97ff-dc6887b85e8c + Www-Authenticate: + - AzureApiManagementKey realm="https://sandbox.momodeveloper.mtn.com/disbursement",name="Ocp-Apim-Subscription-Key",type="header" + Date: + - Thu, 27 Feb 2020 10:08:03 GMT + body: + encoding: UTF-8 + string: '{ "statusCode": 401, "message": "Access denied due to invalid subscription + key. Make sure to provide a valid key for an active subscription." }' + http_version: null + recorded_at: Thu, 27 Feb 2020 10:08:03 GMT +recorded_with: VCR 5.1.0 diff --git a/spec/cassettes/Momoapi_Disbursement/collections/gets_transaction_status.yml b/spec/cassettes/Momoapi_Disbursement/collections/gets_transaction_status.yml new file mode 100644 index 0000000..fa26988 --- /dev/null +++ b/spec/cassettes/Momoapi_Disbursement/collections/gets_transaction_status.yml @@ -0,0 +1,43 @@ +--- +http_interactions: +- request: + method: post + uri: https://sandbox.momodeveloper.mtn.com/disbursement/token + body: + encoding: UTF-8 + string: '' + headers: + Ocp-Apim-Subscription-Key: + - b5e0f061fa5a4cbbbd2192530b7cedfb + Authorization: + - Basic NzgzYThmMjEtM2ZjNi00ZTM5LWFhNzYtZGE4ZTU2MmZiYTdlOjMxM2NmYWY5YTQwYjQwMjliNzEzOWY0YzlkOGFmYjIz + Content-Length: + - '0' + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + response: + status: + code: 401 + message: Access Denied + headers: + Content-Length: + - '143' + Content-Type: + - application/json + Request-Context: + - appId=cid-v1:e996501c-e721-4ac1-97ff-dc6887b85e8c + Www-Authenticate: + - AzureApiManagementKey realm="https://sandbox.momodeveloper.mtn.com/disbursement",name="Ocp-Apim-Subscription-Key",type="header" + Date: + - Thu, 27 Feb 2020 10:08:04 GMT + body: + encoding: UTF-8 + string: '{ "statusCode": 401, "message": "Access denied due to invalid subscription + key. Make sure to provide a valid key for an active subscription." }' + http_version: null + recorded_at: Thu, 27 Feb 2020 10:08:04 GMT +recorded_with: VCR 5.1.0 diff --git a/spec/cassettes/Momoapi_Disbursement/collections/makes_request_to_pay.yml b/spec/cassettes/Momoapi_Disbursement/collections/makes_request_to_pay.yml new file mode 100644 index 0000000..9fedfe1 --- /dev/null +++ b/spec/cassettes/Momoapi_Disbursement/collections/makes_request_to_pay.yml @@ -0,0 +1,43 @@ +--- +http_interactions: +- request: + method: post + uri: https://sandbox.momodeveloper.mtn.com/disbursement/token + body: + encoding: UTF-8 + string: '' + headers: + Ocp-Apim-Subscription-Key: + - b5e0f061fa5a4cbbbd2192530b7cedfb + Authorization: + - Basic NzgzYThmMjEtM2ZjNi00ZTM5LWFhNzYtZGE4ZTU2MmZiYTdlOjMxM2NmYWY5YTQwYjQwMjliNzEzOWY0YzlkOGFmYjIz + Content-Length: + - '0' + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + response: + status: + code: 401 + message: Access Denied + headers: + Content-Length: + - '143' + Content-Type: + - application/json + Request-Context: + - appId=cid-v1:e996501c-e721-4ac1-97ff-dc6887b85e8c + Www-Authenticate: + - AzureApiManagementKey realm="https://sandbox.momodeveloper.mtn.com/disbursement",name="Ocp-Apim-Subscription-Key",type="header" + Date: + - Thu, 27 Feb 2020 10:08:04 GMT + body: + encoding: UTF-8 + string: '{ "statusCode": 401, "message": "Access denied due to invalid subscription + key. Make sure to provide a valid key for an active subscription." }' + http_version: null + recorded_at: Thu, 27 Feb 2020 10:08:05 GMT +recorded_with: VCR 5.1.0 diff --git a/spec/cassettes/Momoapi_Disbursement/disbursements/gets_balance.yml b/spec/cassettes/Momoapi_Disbursement/disbursements/gets_balance.yml new file mode 100644 index 0000000..812788f --- /dev/null +++ b/spec/cassettes/Momoapi_Disbursement/disbursements/gets_balance.yml @@ -0,0 +1,120 @@ +--- +http_interactions: +- request: + method: post + uri: https://sandbox.momodeveloper.mtn.com/disbursement/token + body: + encoding: UTF-8 + string: '' + headers: + Ocp-Apim-Subscription-Key: + - 0e041b269b3746c9ad43db4aed203684 + Authorization: + - Basic NzgzYThmMjEtM2ZjNi00ZTM5LWFhNzYtZGE4ZTU2MmZiYTdlOjMxM2NmYWY5YTQwYjQwMjliNzEzOWY0YzlkOGFmYjIz + Content-Length: + - '0' + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + response: + status: + code: 302 + message: Found + headers: + Content-Length: + - '0' + Location: + - https://52.236.59.28:8080/token/ + Request-Context: + - appId=cid-v1:e996501c-e721-4ac1-97ff-dc6887b85e8c + Date: + - Thu, 27 Feb 2020 10:16:15 GMT + body: + encoding: UTF-8 + string: '' + http_version: null + recorded_at: Thu, 27 Feb 2020 10:16:16 GMT +- request: + method: post + uri: https://sandbox.momodeveloper.mtn.com/disbursement/token/ + body: + encoding: UTF-8 + string: '' + headers: + Ocp-Apim-Subscription-Key: + - 0c74e0a1cf344d45a3d02b1da52c12f5 + Authorization: + - Basic NzgzYThmMjEtM2ZjNi00ZTM5LWFhNzYtZGE4ZTU2MmZiYTdlOjMxM2NmYWY5YTQwYjQwMjliNzEzOWY0YzlkOGFmYjIz + Content-Length: + - '0' + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + response: + status: + code: 200 + message: OK + headers: + Cache-Control: + - no-store + Pragma: + - no-cache + Content-Length: + - '628' + Content-Type: + - application/json;charset=utf-8 + Request-Context: + - appId=cid-v1:e996501c-e721-4ac1-97ff-dc6887b85e8c + Date: + - Thu, 27 Feb 2020 13:02:07 GMT + body: + encoding: UTF-8 + string: '{"access_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJSMjU2In0.eyJjbGllbnRJZCI6Ijc4M2E4ZjIxLTNmYzYtNGUzOS1hYTc2LWRhOGU1NjJmYmE3ZSIsImV4cGlyZXMiOiIyMDIwLTAyLTI3VDE0OjAyOjA3LjM5MyIsInNlc3Npb25JZCI6ImU3ZWFkOTAyLWIyNzAtNDBiMS1hY2NhLTQyYTA4NWYxMDdhMSJ9.VrYt02bGbONeRT2VQiY3HPYkFqTek0FjUgNQxa0jYTy7wYoqgb8JP4_FTqY50rXRR7dlceujfYnUNsn8CLQFM6sL-He-2lmIf4jRhMkujEA9Ah-x6zxax3X0Tc6WkLMh4DB6x5nxUv4WimnBZFK3W0A38jxvlmpEcXNDlfMUBhF1Ahqvl3pBe_Ax_E1wIuQ9hsRtGB0oY-Qq5qLN43AjnY7Tln99hHMm2ykyVXORHwJlxGBWr9qeGI6rBpdmfwv_EqtIcU2tyvjuNg78Mt217oQ--ukfNAB6b5lIrfv79d4VCMLjbBovfaU0WqEPWcZR8yzSyKii9NbzGgaiafWhfw","token_type":"access_token","expires_in":3600}' + http_version: null + recorded_at: Thu, 27 Feb 2020 13:02:07 GMT +- request: + method: get + uri: https://sandbox.momodeveloper.mtn.com/disbursement/v1_0/account/balance + body: + encoding: US-ASCII + string: '' + headers: + X-Target-Environment: + - sandbox + Content-Type: + - application/json + Ocp-Apim-Subscription-Key: + - 0c74e0a1cf344d45a3d02b1da52c12f5 + Authorization: + - Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSMjU2In0.eyJjbGllbnRJZCI6Ijc4M2E4ZjIxLTNmYzYtNGUzOS1hYTc2LWRhOGU1NjJmYmE3ZSIsImV4cGlyZXMiOiIyMDIwLTAyLTI3VDE0OjAyOjA3LjM5MyIsInNlc3Npb25JZCI6ImU3ZWFkOTAyLWIyNzAtNDBiMS1hY2NhLTQyYTA4NWYxMDdhMSJ9.VrYt02bGbONeRT2VQiY3HPYkFqTek0FjUgNQxa0jYTy7wYoqgb8JP4_FTqY50rXRR7dlceujfYnUNsn8CLQFM6sL-He-2lmIf4jRhMkujEA9Ah-x6zxax3X0Tc6WkLMh4DB6x5nxUv4WimnBZFK3W0A38jxvlmpEcXNDlfMUBhF1Ahqvl3pBe_Ax_E1wIuQ9hsRtGB0oY-Qq5qLN43AjnY7Tln99hHMm2ykyVXORHwJlxGBWr9qeGI6rBpdmfwv_EqtIcU2tyvjuNg78Mt217oQ--ukfNAB6b5lIrfv79d4VCMLjbBovfaU0WqEPWcZR8yzSyKii9NbzGgaiafWhfw + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + response: + status: + code: 500 + message: Server Error + headers: + Content-Length: + - '96' + Content-Type: + - application/json;charset=utf-8 + Request-Context: + - appId=cid-v1:e996501c-e721-4ac1-97ff-dc6887b85e8c + Date: + - Thu, 27 Feb 2020 13:02:08 GMT + body: + encoding: UTF-8 + string: '{"message":"Access to target environment is forbidden.","code":"NOT_ALLOWED_TARGET_ENVIRONMENT"}' + http_version: null + recorded_at: Thu, 27 Feb 2020 13:02:08 GMT +recorded_with: VCR 5.1.0 diff --git a/spec/cassettes/Momoapi_Disbursement/disbursements/gets_transaction_status.yml b/spec/cassettes/Momoapi_Disbursement/disbursements/gets_transaction_status.yml new file mode 100644 index 0000000..d2cf922 --- /dev/null +++ b/spec/cassettes/Momoapi_Disbursement/disbursements/gets_transaction_status.yml @@ -0,0 +1,158 @@ +--- +http_interactions: +- request: + method: post + uri: https://sandbox.momodeveloper.mtn.com/disbursement/token + body: + encoding: UTF-8 + string: '' + headers: + Ocp-Apim-Subscription-Key: + - 0e041b269b3746c9ad43db4aed203684 + Authorization: + - Basic NzgzYThmMjEtM2ZjNi00ZTM5LWFhNzYtZGE4ZTU2MmZiYTdlOjMxM2NmYWY5YTQwYjQwMjliNzEzOWY0YzlkOGFmYjIz + Content-Length: + - '0' + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + response: + status: + code: 302 + message: Found + headers: + Content-Length: + - '0' + Location: + - https://52.236.59.28:8080/token/ + Request-Context: + - appId=cid-v1:e996501c-e721-4ac1-97ff-dc6887b85e8c + Date: + - Thu, 27 Feb 2020 10:16:17 GMT + body: + encoding: UTF-8 + string: '' + http_version: null + recorded_at: Thu, 27 Feb 2020 10:16:17 GMT +- request: + method: post + uri: https://sandbox.momodeveloper.mtn.com/disbursement/token/ + body: + encoding: UTF-8 + string: '' + headers: + Ocp-Apim-Subscription-Key: + - 0c74e0a1cf344d45a3d02b1da52c12f5 + Authorization: + - Basic NzgzYThmMjEtM2ZjNi00ZTM5LWFhNzYtZGE4ZTU2MmZiYTdlOjMxM2NmYWY5YTQwYjQwMjliNzEzOWY0YzlkOGFmYjIz + Content-Length: + - '0' + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + response: + status: + code: 200 + message: OK + headers: + Cache-Control: + - no-store + Pragma: + - no-cache + Content-Length: + - '628' + Content-Type: + - application/json;charset=utf-8 + Request-Context: + - appId=cid-v1:e996501c-e721-4ac1-97ff-dc6887b85e8c + Date: + - Thu, 27 Feb 2020 13:02:08 GMT + body: + encoding: UTF-8 + string: '{"access_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJSMjU2In0.eyJjbGllbnRJZCI6Ijc4M2E4ZjIxLTNmYzYtNGUzOS1hYTc2LWRhOGU1NjJmYmE3ZSIsImV4cGlyZXMiOiIyMDIwLTAyLTI3VDE0OjAyOjA5LjIxNyIsInNlc3Npb25JZCI6IjVmYzZkNmQxLWY5OWItNDYxYy05NmI5LTJmNjljZjE1NWJkYiJ9.LYRJPc0yGZ8EbAiCky2M_Ri8yElq7GaCCnedERXmESv4VD5gQ82tU27F-oKcp6abUjkYDp5CQIupiOGwF2372g0ifrdY0oLlD0eMd0Gw-vNJulptwK_eTr_1TrLirHL7ImhmqPnqV8WtIGkFl5fRvvW0lsYfaC7MZLkcwM_rgHzUqRqA0_98ZOVj_a3iborrzErHut6Zk8_DGR6v685rszV1gmttymRCIwT-puU9WqIJqSML64RdqB_kgNCxMiuaaCcbjn2yMj7hFvS8ZTiMyjGh1Z91VOe-L742v_C0HhGLCnp74ADDUQYBcEpQYVCBunlcnF-eC0Xfpw64AsDe3g","token_type":"access_token","expires_in":3600}' + http_version: null + recorded_at: Thu, 27 Feb 2020 13:02:09 GMT +- request: + method: get + uri: https://sandbox.momodeveloper.mtn.com/disbursement/v1_0/transfer/888a79ff-0535-4a9f-8a66-457f7903bd8a + body: + encoding: US-ASCII + string: '' + headers: + X-Target-Environment: + - sandbox + Content-Type: + - application/json + Ocp-Apim-Subscription-Key: + - 0c74e0a1cf344d45a3d02b1da52c12f5 + Authorization: + - Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSMjU2In0.eyJjbGllbnRJZCI6Ijc4M2E4ZjIxLTNmYzYtNGUzOS1hYTc2LWRhOGU1NjJmYmE3ZSIsImV4cGlyZXMiOiIyMDIwLTAyLTI3VDE0OjAyOjA5LjIxNyIsInNlc3Npb25JZCI6IjVmYzZkNmQxLWY5OWItNDYxYy05NmI5LTJmNjljZjE1NWJkYiJ9.LYRJPc0yGZ8EbAiCky2M_Ri8yElq7GaCCnedERXmESv4VD5gQ82tU27F-oKcp6abUjkYDp5CQIupiOGwF2372g0ifrdY0oLlD0eMd0Gw-vNJulptwK_eTr_1TrLirHL7ImhmqPnqV8WtIGkFl5fRvvW0lsYfaC7MZLkcwM_rgHzUqRqA0_98ZOVj_a3iborrzErHut6Zk8_DGR6v685rszV1gmttymRCIwT-puU9WqIJqSML64RdqB_kgNCxMiuaaCcbjn2yMj7hFvS8ZTiMyjGh1Z91VOe-L742v_C0HhGLCnp74ADDUQYBcEpQYVCBunlcnF-eC0Xfpw64AsDe3g + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + response: + status: + code: 200 + message: OK + headers: + Content-Length: + - '259' + Content-Type: + - application/json;charset=utf-8 + Request-Context: + - appId=cid-v1:e996501c-e721-4ac1-97ff-dc6887b85e8c + Date: + - Thu, 27 Feb 2020 13:02:09 GMT + body: + encoding: UTF-8 + string: '{"amount":"5","currency":"EUR","financialTransactionId":"386380485","externalId":"6353636","payee":{"partyIdType":"PARTY_CODE","partyId":"783a8f21-3fc6-4e39-aa76-da8e562fba7e"},"payerMessage":"Pay + for product a","payeeNote":"payer note","status":"SUCCESSFUL"}' + http_version: null + recorded_at: Thu, 27 Feb 2020 13:02:10 GMT +- request: + method: get + uri: https://sandbox.momodeveloper.mtn.com/disbursement/v1_0/transfer/888a79ff-0535-4a9f-8a66-457f7903bd8ab + body: + encoding: US-ASCII + string: '' + headers: + X-Target-Environment: + - sandbox + Content-Type: + - application/json + Ocp-Apim-Subscription-Key: + - 0c74e0a1cf344d45a3d02b1da52c12f5 + Authorization: + - Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSMjU2In0.eyJjbGllbnRJZCI6Ijc4M2E4ZjIxLTNmYzYtNGUzOS1hYTc2LWRhOGU1NjJmYmE3ZSIsImV4cGlyZXMiOiIyMDIwLTAyLTI3VDE0OjAyOjA5LjIxNyIsInNlc3Npb25JZCI6IjVmYzZkNmQxLWY5OWItNDYxYy05NmI5LTJmNjljZjE1NWJkYiJ9.LYRJPc0yGZ8EbAiCky2M_Ri8yElq7GaCCnedERXmESv4VD5gQ82tU27F-oKcp6abUjkYDp5CQIupiOGwF2372g0ifrdY0oLlD0eMd0Gw-vNJulptwK_eTr_1TrLirHL7ImhmqPnqV8WtIGkFl5fRvvW0lsYfaC7MZLkcwM_rgHzUqRqA0_98ZOVj_a3iborrzErHut6Zk8_DGR6v685rszV1gmttymRCIwT-puU9WqIJqSML64RdqB_kgNCxMiuaaCcbjn2yMj7hFvS8ZTiMyjGh1Z91VOe-L742v_C0HhGLCnp74ADDUQYBcEpQYVCBunlcnF-eC0Xfpw64AsDe3g + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + response: + status: + code: 400 + message: Bad Request + headers: + Content-Length: + - '0' + Request-Context: + - appId=cid-v1:e996501c-e721-4ac1-97ff-dc6887b85e8c + Date: + - Thu, 27 Feb 2020 13:03:03 GMT + body: + encoding: UTF-8 + string: '' + http_version: null + recorded_at: Thu, 27 Feb 2020 13:03:03 GMT +recorded_with: VCR 5.1.0 diff --git a/spec/cassettes/Momoapi_Disbursement/disbursements/makes_transfer.yml b/spec/cassettes/Momoapi_Disbursement/disbursements/makes_transfer.yml new file mode 100644 index 0000000..85a478d --- /dev/null +++ b/spec/cassettes/Momoapi_Disbursement/disbursements/makes_transfer.yml @@ -0,0 +1,122 @@ +--- +http_interactions: +- request: + method: post + uri: https://sandbox.momodeveloper.mtn.com/disbursement/token + body: + encoding: UTF-8 + string: '' + headers: + Ocp-Apim-Subscription-Key: + - 0e041b269b3746c9ad43db4aed203684 + Authorization: + - Basic NzgzYThmMjEtM2ZjNi00ZTM5LWFhNzYtZGE4ZTU2MmZiYTdlOjMxM2NmYWY5YTQwYjQwMjliNzEzOWY0YzlkOGFmYjIz + Content-Length: + - '0' + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + response: + status: + code: 302 + message: Found + headers: + Content-Length: + - '0' + Location: + - https://52.236.59.28:8080/token/ + Request-Context: + - appId=cid-v1:e996501c-e721-4ac1-97ff-dc6887b85e8c + Date: + - Thu, 27 Feb 2020 10:16:17 GMT + body: + encoding: UTF-8 + string: '' + http_version: null + recorded_at: Thu, 27 Feb 2020 10:16:18 GMT +- request: + method: post + uri: https://sandbox.momodeveloper.mtn.com/disbursement/token/ + body: + encoding: UTF-8 + string: '' + headers: + Ocp-Apim-Subscription-Key: + - 0c74e0a1cf344d45a3d02b1da52c12f5 + Authorization: + - Basic NzgzYThmMjEtM2ZjNi00ZTM5LWFhNzYtZGE4ZTU2MmZiYTdlOjMxM2NmYWY5YTQwYjQwMjliNzEzOWY0YzlkOGFmYjIz + Content-Length: + - '0' + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + response: + status: + code: 200 + message: OK + headers: + Cache-Control: + - no-store + Pragma: + - no-cache + Content-Length: + - '628' + Content-Type: + - application/json;charset=utf-8 + Request-Context: + - appId=cid-v1:e996501c-e721-4ac1-97ff-dc6887b85e8c + Date: + - Thu, 27 Feb 2020 13:02:11 GMT + body: + encoding: UTF-8 + string: '{"access_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJSMjU2In0.eyJjbGllbnRJZCI6Ijc4M2E4ZjIxLTNmYzYtNGUzOS1hYTc2LWRhOGU1NjJmYmE3ZSIsImV4cGlyZXMiOiIyMDIwLTAyLTI3VDE0OjAyOjExLjE5NyIsInNlc3Npb25JZCI6IjA3MmQ1ZGQyLTE2MzMtNGMyYy1hMDMxLTFjMTE0MDZlMGYxNiJ9.aIXtRCsJt4usxOhJoYrFOGIJlKv6rZm6W8NUGp9euCrsO6yAfSncSPF60CFvOOLub3OZnb0GiFLhtNVb_KMG3CjSTHMC9gmjZF2pMhdgmpbWWyalWwkkARCIPhKcG1AF3X6VWQ8Qq80_O76zNBU1Rk3S_VFo1BcQw2pRuPdDm52uwbpENJfVEYb-VbCrsGt5f6flg-ceCUgKc3snokINorUB9hsefwVp7oI49Y4VlgoSt326qpydYJwzEiE8hDK9YEiuxQh8LVkiV8_eKbXsjmpI3wX1dgBzFEOec2yKp-FokxHW_8Xr4_V9rT1nUq6UVdtJ_RDS8EMAOiP2WkwByA","token_type":"access_token","expires_in":3600}' + http_version: null + recorded_at: Thu, 27 Feb 2020 13:02:11 GMT +- request: + method: post + uri: https://sandbox.momodeveloper.mtn.com/disbursement/v1_0/transfer + body: + encoding: UTF-8 + string: '' + headers: + X-Target-Environment: + - sandbox + Content-Type: + - application/json + X-Reference-Id: + - 18151159-f38d-4a51-83f3-42445e24daf7 + Ocp-Apim-Subscription-Key: + - 0c74e0a1cf344d45a3d02b1da52c12f5 + Authorization: + - Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSMjU2In0.eyJjbGllbnRJZCI6Ijc4M2E4ZjIxLTNmYzYtNGUzOS1hYTc2LWRhOGU1NjJmYmE3ZSIsImV4cGlyZXMiOiIyMDIwLTAyLTI3VDE0OjAyOjExLjE5NyIsInNlc3Npb25JZCI6IjA3MmQ1ZGQyLTE2MzMtNGMyYy1hMDMxLTFjMTE0MDZlMGYxNiJ9.aIXtRCsJt4usxOhJoYrFOGIJlKv6rZm6W8NUGp9euCrsO6yAfSncSPF60CFvOOLub3OZnb0GiFLhtNVb_KMG3CjSTHMC9gmjZF2pMhdgmpbWWyalWwkkARCIPhKcG1AF3X6VWQ8Qq80_O76zNBU1Rk3S_VFo1BcQw2pRuPdDm52uwbpENJfVEYb-VbCrsGt5f6flg-ceCUgKc3snokINorUB9hsefwVp7oI49Y4VlgoSt326qpydYJwzEiE8hDK9YEiuxQh8LVkiV8_eKbXsjmpI3wX1dgBzFEOec2yKp-FokxHW_8Xr4_V9rT1nUq6UVdtJ_RDS8EMAOiP2WkwByA + Content-Length: + - '0' + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + response: + status: + code: 500 + message: Server Error + headers: + Content-Length: + - '0' + Request-Context: + - appId=cid-v1:e996501c-e721-4ac1-97ff-dc6887b85e8c + Date: + - Thu, 27 Feb 2020 13:02:11 GMT + body: + encoding: UTF-8 + string: '' + http_version: null + recorded_at: Thu, 27 Feb 2020 13:02:12 GMT +recorded_with: VCR 5.1.0 diff --git a/spec/features/disbursement_spec.rb b/spec/features/disbursement_spec.rb new file mode 100644 index 0000000..531d25e --- /dev/null +++ b/spec/features/disbursement_spec.rb @@ -0,0 +1,38 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Momoapi::Disbursement do + before(:all) do + Momoapi.configure do |config| + config.base_url = 'https://sandbox.momodeveloper.mtn.com' + config.callback_host = 'https://webhook.site/8e412414-2154-4d06-90c4-5e141c9f2910' + config.disbursement_primary_key = '0c74e0a1cf344d45a3d02b1da52c12f5' + config.disbursement_user_id = 'ede69da6-eec7-4b48-86c4-faf65cd05726' + config.disbursement_api_secret = '066eec5710404d78a0b0923058014ce7' + end + end + + describe 'disbursements', vcr: { record: :new_episodes } do + it 'gets balance' do + expect { Momoapi::Disbursement.new.get_balance } + .to raise_error(Error::APIError) + end + + it 'gets transaction status' do + ref = '888a79ff-0535-4a9f-8a66-457f7903bd8ab' + expect { Momoapi::Disbursement.new.get_transaction_status(ref) } + .to raise_error(Error::APIError) + end + + it 'makes transfer' do + expect do + Momoapi::Disbursement.new.transfer( + '0775671360', + '5.0', '6353636', + 'testing', 'testing', 'EUR' + ) + end .to raise_error(Error::APIError) + end + end +end From e3d85df0a354eec3fe082e76ccde8d81291a0516 Mon Sep 17 00:00:00 2001 From: NLSanyu Date: Thu, 27 Feb 2020 16:33:48 +0300 Subject: [PATCH 11/16] Implement remittances --- lib/momoapi-ruby.rb | 1 + lib/momoapi-ruby/remittance.rb | 27 +++- .../remittances/gets_balance.yml | 120 +++++++++++++++++ .../remittances/gets_transaction_status.yml | 118 ++++++++++++++++ .../remittances/makes_transfer.yml | 127 ++++++++++++++++++ spec/features/remittance_spec.rb | 38 ++++++ 6 files changed, 429 insertions(+), 2 deletions(-) create mode 100644 spec/cassettes/Momoapi_Disbursement/remittances/gets_balance.yml create mode 100644 spec/cassettes/Momoapi_Disbursement/remittances/gets_transaction_status.yml create mode 100644 spec/cassettes/Momoapi_Disbursement/remittances/makes_transfer.yml create mode 100644 spec/features/remittance_spec.rb diff --git a/lib/momoapi-ruby.rb b/lib/momoapi-ruby.rb index f6ad45a..4387225 100644 --- a/lib/momoapi-ruby.rb +++ b/lib/momoapi-ruby.rb @@ -5,6 +5,7 @@ require 'momoapi-ruby/cli' require 'momoapi-ruby/collection' require 'momoapi-ruby/disbursement' +require 'momoapi-ruby/remittance' module Momoapi class << self diff --git a/lib/momoapi-ruby/remittance.rb b/lib/momoapi-ruby/remittance.rb index e86c46a..f564375 100644 --- a/lib/momoapi-ruby/remittance.rb +++ b/lib/momoapi-ruby/remittance.rb @@ -6,7 +6,7 @@ module Momoapi class Remittance < Client def get_auth_token - path = 'remittance/token' + path = 'remittance/token/' super(path, Momoapi.config.remittance_primary_key) end @@ -20,6 +20,29 @@ def get_transaction_status(transaction_id) super(path, Momoapi.config.remittance_primary_key) end - def transfer; end + def transfer(phone_number, amount, external_id, + payee_note = '', payer_message = '', currency = 'EUR') + uuid = SecureRandom.uuid + headers = { + "X-Target-Environment": Momoapi.config.environment || 'sandbox', + "Content-Type": 'application/json', + "X-Reference-Id": uuid, + "Ocp-Apim-Subscription-Key": Momoapi.config.disbursement_primary_key + } + body = { + "payer": { + "partyIdType": 'MSISDN', + "partyId": phone_number + }, + "payeeNote": payee_note, + "payerMessage": payer_message, + "externalId": external_id, + "currency": currency, + "amount": amount.to_s + } + path = '/remittance/v1_0/transfer' + send_request('post', path, headers, body) + { transaction_reference: uuid } + end end end diff --git a/spec/cassettes/Momoapi_Disbursement/remittances/gets_balance.yml b/spec/cassettes/Momoapi_Disbursement/remittances/gets_balance.yml new file mode 100644 index 0000000..82fcdf0 --- /dev/null +++ b/spec/cassettes/Momoapi_Disbursement/remittances/gets_balance.yml @@ -0,0 +1,120 @@ +--- +http_interactions: +- request: + method: post + uri: https://sandbox.momodeveloper.mtn.com/remittance/token + body: + encoding: UTF-8 + string: '' + headers: + Ocp-Apim-Subscription-Key: + - d314b91c889340b682a9a3144a9ffd1b + Authorization: + - Basic NzgzYThmMjEtM2ZjNi00ZTM5LWFhNzYtZGE4ZTU2MmZiYTdlOjMxM2NmYWY5YTQwYjQwMjliNzEzOWY0YzlkOGFmYjIz + Content-Length: + - '0' + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + response: + status: + code: 302 + message: Found + headers: + Content-Length: + - '0' + Location: + - https://52.236.59.28:8080/token/ + Request-Context: + - appId=cid-v1:e996501c-e721-4ac1-97ff-dc6887b85e8c + Date: + - Thu, 27 Feb 2020 13:23:45 GMT + body: + encoding: UTF-8 + string: '' + http_version: null + recorded_at: Thu, 27 Feb 2020 13:23:45 GMT +- request: + method: post + uri: https://sandbox.momodeveloper.mtn.com/remittance/token/ + body: + encoding: UTF-8 + string: '' + headers: + Ocp-Apim-Subscription-Key: + - d314b91c889340b682a9a3144a9ffd1b + Authorization: + - Basic NzgzYThmMjEtM2ZjNi00ZTM5LWFhNzYtZGE4ZTU2MmZiYTdlOjMxM2NmYWY5YTQwYjQwMjliNzEzOWY0YzlkOGFmYjIz + Content-Length: + - '0' + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + response: + status: + code: 200 + message: OK + headers: + Cache-Control: + - no-store + Pragma: + - no-cache + Content-Length: + - '628' + Content-Type: + - application/json;charset=utf-8 + Request-Context: + - appId=cid-v1:e996501c-e721-4ac1-97ff-dc6887b85e8c + Date: + - Thu, 27 Feb 2020 13:29:36 GMT + body: + encoding: UTF-8 + string: '{"access_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJSMjU2In0.eyJjbGllbnRJZCI6Ijc4M2E4ZjIxLTNmYzYtNGUzOS1hYTc2LWRhOGU1NjJmYmE3ZSIsImV4cGlyZXMiOiIyMDIwLTAyLTI3VDE0OjI5OjM2LjM1MyIsInNlc3Npb25JZCI6IjZkNTY0ZDM0LTk4YjAtNDYwOC05NGJkLTkyM2JlYzM1MmRjYyJ9.e2lvLTU5Oi2KjoVp7BggMNurcLC4DtqjrEaCGWRpLQCpPbnDFHI_FHFS1tvOLTxNWSb3gAzH5KvxTmmqFkDatph4EpnubmkcuFRcXzyrpAz1IxOQlZ7zYK0ufI-k4KUCMYwxHb9g5s48YtdQJdUXtspbSVVfuTomGaWUHiheAMPDp7Nz83FVGD5TcGJxnprotXs0kfNoZofX-aqhKFHfnBxPiGOcmA1EceNNsHR_r30La3PqfpSGp5EWtr96VGyG6chjYLldMZi_ENhT5qIrDkMjd-Hr7orrJ7f5_yVlSL5ssEsk1GSTxCQWcyiK6uIwo_eAPn8P5-si0Cw0nPN85Q","token_type":"access_token","expires_in":3600}' + http_version: null + recorded_at: Thu, 27 Feb 2020 13:29:36 GMT +- request: + method: get + uri: https://sandbox.momodeveloper.mtn.com/remittance/v1_0/account/balance + body: + encoding: US-ASCII + string: '' + headers: + X-Target-Environment: + - sandbox + Content-Type: + - application/json + Ocp-Apim-Subscription-Key: + - d314b91c889340b682a9a3144a9ffd1b + Authorization: + - Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSMjU2In0.eyJjbGllbnRJZCI6Ijc4M2E4ZjIxLTNmYzYtNGUzOS1hYTc2LWRhOGU1NjJmYmE3ZSIsImV4cGlyZXMiOiIyMDIwLTAyLTI3VDE0OjI5OjM2LjM1MyIsInNlc3Npb25JZCI6IjZkNTY0ZDM0LTk4YjAtNDYwOC05NGJkLTkyM2JlYzM1MmRjYyJ9.e2lvLTU5Oi2KjoVp7BggMNurcLC4DtqjrEaCGWRpLQCpPbnDFHI_FHFS1tvOLTxNWSb3gAzH5KvxTmmqFkDatph4EpnubmkcuFRcXzyrpAz1IxOQlZ7zYK0ufI-k4KUCMYwxHb9g5s48YtdQJdUXtspbSVVfuTomGaWUHiheAMPDp7Nz83FVGD5TcGJxnprotXs0kfNoZofX-aqhKFHfnBxPiGOcmA1EceNNsHR_r30La3PqfpSGp5EWtr96VGyG6chjYLldMZi_ENhT5qIrDkMjd-Hr7orrJ7f5_yVlSL5ssEsk1GSTxCQWcyiK6uIwo_eAPn8P5-si0Cw0nPN85Q + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + response: + status: + code: 500 + message: Server Error + headers: + Content-Length: + - '96' + Content-Type: + - application/json;charset=utf-8 + Request-Context: + - appId=cid-v1:e996501c-e721-4ac1-97ff-dc6887b85e8c + Date: + - Thu, 27 Feb 2020 13:29:36 GMT + body: + encoding: UTF-8 + string: '{"message":"Access to target environment is forbidden.","code":"NOT_ALLOWED_TARGET_ENVIRONMENT"}' + http_version: null + recorded_at: Thu, 27 Feb 2020 13:29:37 GMT +recorded_with: VCR 5.1.0 diff --git a/spec/cassettes/Momoapi_Disbursement/remittances/gets_transaction_status.yml b/spec/cassettes/Momoapi_Disbursement/remittances/gets_transaction_status.yml new file mode 100644 index 0000000..739a6f4 --- /dev/null +++ b/spec/cassettes/Momoapi_Disbursement/remittances/gets_transaction_status.yml @@ -0,0 +1,118 @@ +--- +http_interactions: +- request: + method: post + uri: https://sandbox.momodeveloper.mtn.com/remittance/token + body: + encoding: UTF-8 + string: '' + headers: + Ocp-Apim-Subscription-Key: + - d314b91c889340b682a9a3144a9ffd1b + Authorization: + - Basic NzgzYThmMjEtM2ZjNi00ZTM5LWFhNzYtZGE4ZTU2MmZiYTdlOjMxM2NmYWY5YTQwYjQwMjliNzEzOWY0YzlkOGFmYjIz + Content-Length: + - '0' + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + response: + status: + code: 302 + message: Found + headers: + Content-Length: + - '0' + Location: + - https://52.236.59.28:8080/token/ + Request-Context: + - appId=cid-v1:e996501c-e721-4ac1-97ff-dc6887b85e8c + Date: + - Thu, 27 Feb 2020 13:23:46 GMT + body: + encoding: UTF-8 + string: '' + http_version: null + recorded_at: Thu, 27 Feb 2020 13:23:46 GMT +- request: + method: post + uri: https://sandbox.momodeveloper.mtn.com/remittance/token/ + body: + encoding: UTF-8 + string: '' + headers: + Ocp-Apim-Subscription-Key: + - d314b91c889340b682a9a3144a9ffd1b + Authorization: + - Basic NzgzYThmMjEtM2ZjNi00ZTM5LWFhNzYtZGE4ZTU2MmZiYTdlOjMxM2NmYWY5YTQwYjQwMjliNzEzOWY0YzlkOGFmYjIz + Content-Length: + - '0' + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + response: + status: + code: 200 + message: OK + headers: + Cache-Control: + - no-store + Pragma: + - no-cache + Content-Length: + - '628' + Content-Type: + - application/json;charset=utf-8 + Request-Context: + - appId=cid-v1:e996501c-e721-4ac1-97ff-dc6887b85e8c + Date: + - Thu, 27 Feb 2020 13:29:38 GMT + body: + encoding: UTF-8 + string: '{"access_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJSMjU2In0.eyJjbGllbnRJZCI6Ijc4M2E4ZjIxLTNmYzYtNGUzOS1hYTc2LWRhOGU1NjJmYmE3ZSIsImV4cGlyZXMiOiIyMDIwLTAyLTI3VDE0OjI5OjM4LjA5NSIsInNlc3Npb25JZCI6IjlmMTBiOTI5LTFhZGUtNDE2ZS1iNjQzLWZjOTM1NTc3NDQ0ZiJ9.k8yj-7UX13bwyySxNyrZzN7R3iu2FbDJlsFJl0JqxB79dMlWWQGvwB6Gxin7KmGFXYw87XZNzuFsAKe3s5SThrjIsKtlBIQ_CVcjnWcxxtXOH43VxH4E0A3UPyVEpTt6xeQJ-Xloe0x7mjYtFUaEIg32Nihqfv781Xqq9zuaeNfzBuHA2vHIv-wvmAsr5dnrOwmzEujXV58_rya_ZE5rkkb15ZDwOJ2WzTlrjbUow13vuVKwdT3s7_kwoxV_ObnZHVOsB-e32AHR56Aa_8C99lNFvRIF913xSsDXF-H18B-PoBDLcNz4xNoMLZb2GWz5wLsNLGWGkW2k4DiWCYMfEQ","token_type":"access_token","expires_in":3600}' + http_version: null + recorded_at: Thu, 27 Feb 2020 13:29:38 GMT +- request: + method: get + uri: https://sandbox.momodeveloper.mtn.com/remittance/v1_0/transfer/888a79ff-0535-4a9f-8a66-457f7903bd8ab + body: + encoding: US-ASCII + string: '' + headers: + X-Target-Environment: + - sandbox + Content-Type: + - application/json + Ocp-Apim-Subscription-Key: + - d314b91c889340b682a9a3144a9ffd1b + Authorization: + - Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSMjU2In0.eyJjbGllbnRJZCI6Ijc4M2E4ZjIxLTNmYzYtNGUzOS1hYTc2LWRhOGU1NjJmYmE3ZSIsImV4cGlyZXMiOiIyMDIwLTAyLTI3VDE0OjI5OjM4LjA5NSIsInNlc3Npb25JZCI6IjlmMTBiOTI5LTFhZGUtNDE2ZS1iNjQzLWZjOTM1NTc3NDQ0ZiJ9.k8yj-7UX13bwyySxNyrZzN7R3iu2FbDJlsFJl0JqxB79dMlWWQGvwB6Gxin7KmGFXYw87XZNzuFsAKe3s5SThrjIsKtlBIQ_CVcjnWcxxtXOH43VxH4E0A3UPyVEpTt6xeQJ-Xloe0x7mjYtFUaEIg32Nihqfv781Xqq9zuaeNfzBuHA2vHIv-wvmAsr5dnrOwmzEujXV58_rya_ZE5rkkb15ZDwOJ2WzTlrjbUow13vuVKwdT3s7_kwoxV_ObnZHVOsB-e32AHR56Aa_8C99lNFvRIF913xSsDXF-H18B-PoBDLcNz4xNoMLZb2GWz5wLsNLGWGkW2k4DiWCYMfEQ + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + response: + status: + code: 400 + message: Bad Request + headers: + Content-Length: + - '0' + Request-Context: + - appId=cid-v1:e996501c-e721-4ac1-97ff-dc6887b85e8c + Date: + - Thu, 27 Feb 2020 13:29:38 GMT + body: + encoding: UTF-8 + string: '' + http_version: null + recorded_at: Thu, 27 Feb 2020 13:29:39 GMT +recorded_with: VCR 5.1.0 diff --git a/spec/cassettes/Momoapi_Disbursement/remittances/makes_transfer.yml b/spec/cassettes/Momoapi_Disbursement/remittances/makes_transfer.yml new file mode 100644 index 0000000..241c467 --- /dev/null +++ b/spec/cassettes/Momoapi_Disbursement/remittances/makes_transfer.yml @@ -0,0 +1,127 @@ +--- +http_interactions: +- request: + method: post + uri: https://sandbox.momodeveloper.mtn.com/remittance/token + body: + encoding: UTF-8 + string: '' + headers: + Ocp-Apim-Subscription-Key: + - d314b91c889340b682a9a3144a9ffd1b + Authorization: + - Basic NzgzYThmMjEtM2ZjNi00ZTM5LWFhNzYtZGE4ZTU2MmZiYTdlOjMxM2NmYWY5YTQwYjQwMjliNzEzOWY0YzlkOGFmYjIz + Content-Length: + - '0' + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + response: + status: + code: 302 + message: Found + headers: + Content-Length: + - '0' + Location: + - https://52.236.59.28:8080/token/ + Request-Context: + - appId=cid-v1:e996501c-e721-4ac1-97ff-dc6887b85e8c + Date: + - Thu, 27 Feb 2020 13:23:46 GMT + body: + encoding: UTF-8 + string: '' + http_version: null + recorded_at: Thu, 27 Feb 2020 13:23:47 GMT +- request: + method: post + uri: https://sandbox.momodeveloper.mtn.com/remittance/token/ + body: + encoding: UTF-8 + string: '' + headers: + Ocp-Apim-Subscription-Key: + - d314b91c889340b682a9a3144a9ffd1b + Authorization: + - Basic NzgzYThmMjEtM2ZjNi00ZTM5LWFhNzYtZGE4ZTU2MmZiYTdlOjMxM2NmYWY5YTQwYjQwMjliNzEzOWY0YzlkOGFmYjIz + Content-Length: + - '0' + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + response: + status: + code: 200 + message: OK + headers: + Cache-Control: + - no-store + Pragma: + - no-cache + Content-Length: + - '628' + Content-Type: + - application/json;charset=utf-8 + Request-Context: + - appId=cid-v1:e996501c-e721-4ac1-97ff-dc6887b85e8c + Date: + - Thu, 27 Feb 2020 13:29:40 GMT + body: + encoding: UTF-8 + string: '{"access_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJSMjU2In0.eyJjbGllbnRJZCI6Ijc4M2E4ZjIxLTNmYzYtNGUzOS1hYTc2LWRhOGU1NjJmYmE3ZSIsImV4cGlyZXMiOiIyMDIwLTAyLTI3VDE0OjI5OjQwLjAzOSIsInNlc3Npb25JZCI6IjVmMjVkNGQ1LWI1ZWItNDU3My05YjIyLTc2MDRiNDk2MTg5ZCJ9.d8yxHi3XfB5Zm0CjfZmBoyYlvInE6xmHnGjAm2n8Dr-G8JPBGCWuZvD_VkPOZJW23RdbyqRVjYzsTK5GaWukraXVoT4Sgym4cxGEJbHbe9qH_PwhQY8KQIlr1ae6HufE53-lMELn-nuCMzfK8YCX18gf84DIBSZFsNDuCy3nZUMbQgrrg0VrmAevX4Zr_M86D4weluhxc7c_LS27qnIH9PjJzOcANSSs8nWuaJ-5l3rc9WK4zEcVe08yViZYgFHoyQ70F5OFEhWzb3b5zdD15PbFVJgvphB05aavqEujLeZPVHDMat3gexVCyS_dKvyPNFabuaMnBuk3yShmpn6F5A","token_type":"access_token","expires_in":3600}' + http_version: null + recorded_at: Thu, 27 Feb 2020 13:29:40 GMT +- request: + method: post + uri: https://sandbox.momodeveloper.mtn.com/remittance/v1_0/transfer + body: + encoding: UTF-8 + string: '' + headers: + X-Target-Environment: + - sandbox + Content-Type: + - application/json + X-Reference-Id: + - 80f458da-fd56-4a76-90f2-df65cfcdaef3 + Ocp-Apim-Subscription-Key: + - 0c74e0a1cf344d45a3d02b1da52c12f5 + Authorization: + - Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSMjU2In0.eyJjbGllbnRJZCI6Ijc4M2E4ZjIxLTNmYzYtNGUzOS1hYTc2LWRhOGU1NjJmYmE3ZSIsImV4cGlyZXMiOiIyMDIwLTAyLTI3VDE0OjI5OjQwLjAzOSIsInNlc3Npb25JZCI6IjVmMjVkNGQ1LWI1ZWItNDU3My05YjIyLTc2MDRiNDk2MTg5ZCJ9.d8yxHi3XfB5Zm0CjfZmBoyYlvInE6xmHnGjAm2n8Dr-G8JPBGCWuZvD_VkPOZJW23RdbyqRVjYzsTK5GaWukraXVoT4Sgym4cxGEJbHbe9qH_PwhQY8KQIlr1ae6HufE53-lMELn-nuCMzfK8YCX18gf84DIBSZFsNDuCy3nZUMbQgrrg0VrmAevX4Zr_M86D4weluhxc7c_LS27qnIH9PjJzOcANSSs8nWuaJ-5l3rc9WK4zEcVe08yViZYgFHoyQ70F5OFEhWzb3b5zdD15PbFVJgvphB05aavqEujLeZPVHDMat3gexVCyS_dKvyPNFabuaMnBuk3yShmpn6F5A + Content-Length: + - '0' + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + response: + status: + code: 401 + message: Access Denied + headers: + Content-Length: + - '143' + Content-Type: + - application/json + Request-Context: + - appId=cid-v1:e996501c-e721-4ac1-97ff-dc6887b85e8c + Www-Authenticate: + - AzureApiManagementKey realm="https://sandbox.momodeveloper.mtn.com/remittance",name="Ocp-Apim-Subscription-Key",type="header" + Date: + - Thu, 27 Feb 2020 13:29:41 GMT + body: + encoding: UTF-8 + string: '{ "statusCode": 401, "message": "Access denied due to invalid subscription + key. Make sure to provide a valid key for an active subscription." }' + http_version: null + recorded_at: Thu, 27 Feb 2020 13:29:41 GMT +recorded_with: VCR 5.1.0 diff --git a/spec/features/remittance_spec.rb b/spec/features/remittance_spec.rb new file mode 100644 index 0000000..8c966b6 --- /dev/null +++ b/spec/features/remittance_spec.rb @@ -0,0 +1,38 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Momoapi::Disbursement do + before(:all) do + Momoapi.configure do |config| + config.base_url = 'https://sandbox.momodeveloper.mtn.com' + config.callback_host = 'https://webhook.site/8e412414-2154-4d06-90c4-5e141c9f2910' + config.remittance_primary_key = 'd314b91c889340b682a9a3144a9ffd1b' + config.remittance_user_id = 'cf028de4-7341-41c0-b4ff-3fa190b77236' + config.remittance_api_secret = 'dcacc115e6fd4669b1db622d4b949947' + end + end + + describe 'remittances', vcr: { record: :new_episodes } do + it 'gets balance' do + expect { Momoapi::Remittance.new.get_balance } + .to raise_error(Error::APIError) + end + + it 'gets transaction status' do + ref = '888a79ff-0535-4a9f-8a66-457f7903bd8ab' + expect { Momoapi::Remittance.new.get_transaction_status(ref) } + .to raise_error(Error::APIError) + end + + it 'makes transfer' do + expect do + Momoapi::Remittance.new.transfer( + '0775671360', + '5.0', '6353636', + 'testing', 'testing', 'EUR' + ) + end .to raise_error(Error::APIError) + end + end +end From 56055578510edcd6e3da4d9a21d79463293986d1 Mon Sep 17 00:00:00 2001 From: NLSanyu Date: Fri, 28 Feb 2020 18:21:57 +0300 Subject: [PATCH 12/16] Add callback_url to transfer --- .rubocop.yml | 2 ++ lib/momoapi-ruby/client.rb | 12 +++++++++++- lib/momoapi-ruby/collection.rb | 11 ++++++++++- lib/momoapi-ruby/disbursement.rb | 11 ++++++++++- lib/momoapi-ruby/remittance.rb | 11 ++++++++++- 5 files changed, 43 insertions(+), 4 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index dc4c4b0..f87c66e 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -11,4 +11,6 @@ Metrics/ParameterLists: Lint/DuplicateMethods: Enabled: false Naming/AccessorMethodName: + Enabled: false +Naming/PredicateName: Enabled: false \ No newline at end of file diff --git a/lib/momoapi-ruby/client.rb b/lib/momoapi-ruby/client.rb index 0f6c570..1aeef84 100644 --- a/lib/momoapi-ruby/client.rb +++ b/lib/momoapi-ruby/client.rb @@ -23,8 +23,9 @@ def send_request(method, path, headers, *_body) end def interpret_response(resp) + body = resp.body.empty? ? '' : JSON.parse(resp.body) response = { - body: resp.body, + body: body, code: resp.status } unless resp.status >= 200 && resp.status < 300 @@ -72,5 +73,14 @@ def get_transaction_status(path, subscription_key) } send_request('get', path, headers) end + + def is_user_active(path, subscription_key) + headers = { + "X-Target-Environment": Momoapi.config.environment || 'sandbox', + "Content-Type": 'application/json', + "Ocp-Apim-Subscription-Key": subscription_key + } + send_request('get', path, headers) + end end end diff --git a/lib/momoapi-ruby/collection.rb b/lib/momoapi-ruby/collection.rb index 71c8450..d0b475d 100644 --- a/lib/momoapi-ruby/collection.rb +++ b/lib/momoapi-ruby/collection.rb @@ -23,7 +23,8 @@ def get_transaction_status(transaction_id) end def request_to_pay(phone_number, amount, external_id, - payee_note = '', payer_message = '', currency = 'EUR') + payee_note = '', payer_message = '', + currency = 'EUR', **options) uuid = SecureRandom.uuid headers = { "X-Target-Environment": Momoapi.config.environment || 'sandbox', @@ -31,6 +32,9 @@ def request_to_pay(phone_number, amount, external_id, "X-Reference-Id": uuid, "Ocp-Apim-Subscription-Key": Momoapi.config.collection_primary_key } + if options[:callback_url] + headers['X-Callback-Url'] = options[:callback_url] + end body = { "payer": { "partyIdType": 'MSISDN', @@ -46,5 +50,10 @@ def request_to_pay(phone_number, amount, external_id, send_request('post', path, headers, body) { transaction_reference: uuid } end + + def is_user_active(phone_number) + path = "/collection/v1_0/accountholder/msisdn/#{phone_number}/active" + super(path, Momoapi.config.collection_primary_key) + end end end diff --git a/lib/momoapi-ruby/disbursement.rb b/lib/momoapi-ruby/disbursement.rb index c1a5537..5b34cfb 100644 --- a/lib/momoapi-ruby/disbursement.rb +++ b/lib/momoapi-ruby/disbursement.rb @@ -21,7 +21,8 @@ def get_transaction_status(transaction_id) end def transfer(phone_number, amount, external_id, - payee_note = '', payer_message = '', currency = 'EUR') + payee_note = '', payer_message = '', + currency = 'EUR', **options) uuid = SecureRandom.uuid headers = { "X-Target-Environment": Momoapi.config.environment || 'sandbox', @@ -29,6 +30,9 @@ def transfer(phone_number, amount, external_id, "X-Reference-Id": uuid, "Ocp-Apim-Subscription-Key": Momoapi.config.disbursement_primary_key } + if options[:callback_url] + headers['X-Callback-Url'] = options[:callback_url] + end body = { "payer": { "partyIdType": 'MSISDN', @@ -44,5 +48,10 @@ def transfer(phone_number, amount, external_id, send_request('post', path, headers, body) { transaction_reference: uuid } end + + def is_user_active(phone_number) + path = "/disbursement/v1_0/accountholder/msisdn/#{phone_number}/active" + super(path, Momoapi.config.disbursement_primary_key) + end end end diff --git a/lib/momoapi-ruby/remittance.rb b/lib/momoapi-ruby/remittance.rb index f564375..3117ee3 100644 --- a/lib/momoapi-ruby/remittance.rb +++ b/lib/momoapi-ruby/remittance.rb @@ -21,7 +21,8 @@ def get_transaction_status(transaction_id) end def transfer(phone_number, amount, external_id, - payee_note = '', payer_message = '', currency = 'EUR') + payee_note = '', payer_message = '', + currency = 'EUR', **options) uuid = SecureRandom.uuid headers = { "X-Target-Environment": Momoapi.config.environment || 'sandbox', @@ -29,6 +30,9 @@ def transfer(phone_number, amount, external_id, "X-Reference-Id": uuid, "Ocp-Apim-Subscription-Key": Momoapi.config.disbursement_primary_key } + if options[:callback_url] + headers['X-Callback-Url'] = options[:callback_url] + end body = { "payer": { "partyIdType": 'MSISDN', @@ -44,5 +48,10 @@ def transfer(phone_number, amount, external_id, send_request('post', path, headers, body) { transaction_reference: uuid } end + + def is_user_active(phone_number) + path = "/remittance/v1_0/accountholder/msisdn/#{phone_number}/active" + super(path, Momoapi.config.remittance_primary_key) + end end end From 78225e397c164a1eff8a899a15bfcc3c196ce180 Mon Sep 17 00:00:00 2001 From: NLSanyu Date: Fri, 28 Feb 2020 18:43:12 +0300 Subject: [PATCH 13/16] Add documentation for all products --- README.md | 96 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 91 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 97647c6..691ac53 100644 --- a/README.md +++ b/README.md @@ -43,14 +43,18 @@ Add the following configurations in an initializer file (for example, `config/in Momoapi.configure do |config| config.base_url = 'Your MoMo account base URL' config.callback_host = 'Your Provider Callback Host' - config.collection_primary_key = 'Your Collection Subscription Key' - config.collection_user_id = 'Your Collection User ID' - config.collection_api_secret = 'Your Collection API Key' end ``` ## Collections -The collections client can be created with the following paramaters. Note that the `COLLECTION_USER_ID` and `COLLECTION_API_SECRET` for production are provided on the MTN OVA dashboard; +The collections client can be created with the following paramaters. Note that the `COLLECTION_USER_ID` and `COLLECTION_API_SECRET` for production are provided on the MTN OVA dashboard. + +Add the following to your configuration block: +``` + config.collection_primary_key = 'Your Collection Subscription Key' + config.collection_user_id = 'Your Collection User ID' + config.collection_api_secret = 'Your Collection API Key' +``` * `collection_primary_key`: Primary Key for the `Collection` product on the developer portal. * `collection_user_id`: For sandbox, use the one generated with the `momoapi-ruby` command. @@ -77,9 +81,91 @@ collection = Momoapi::Collection.new require 'momoapi-ruby' collection = Momoapi::Collection.new -collection.requestToPay( +collection.request_to_pay( + mobile="256772123456", amount="600", external_id="123456789", payee_note="dd", payer_message="dd", currency="EUR") +``` +An extra argument, `callback_url`, can be passed to this method, denoting the URL to the server where the callback should be sent. + +## Disbursements +The disbursements client can be created with the following paramaters. The `DISBURSEMENT_USER_ID` and `DISBURSEMENT_API_SECRET` for production are provided on the MTN OVA dashboard. + +Add the following to your configuration block: +``` + config.disbursement_primary_key = 'Your Disbursement Subscription Key' + config.disbursement_user_id = 'Your Disbursement User ID' + config.disbursement_api_secret = 'Your Disbursement API Key' +``` + +* `disbursement_primary_key`: Primary Key for the `Disbursement` product on the developer portal. +* `disbursement_user_id`: For sandbox, use the one generated with the `momoapi-ruby` command. +* `disbursement_api_secret`: For sandbox, use the one generated with the `momoapi-ruby` command. + +You can create a disbursement client with the following: + +```ruby +require 'momoapi-ruby' + +disbursement = Momoapi::Disbursement.new +``` + +### Methods +1. `transfer`: Used to transfer an amount from the owner’s account to a payee account. Status of the transaction can be validated by using the `get_transaction_status` method. + +2. `get_transaction_status`: Retrieve transaction information using the `transaction_id` returned by `transfer`. You can invoke it at intervals until the transaction fails or succeeds. If the transaction has failed, it will throw an appropriate error. + +3. `get_balance`: Get the balance of the account. + +### Sample Code + +```ruby +require 'momoapi-ruby' + +disbursement = Momoapi::Disbursement.new +disbursement.transfer( mobile="256772123456", amount="600", external_id="123456789", payee_note="dd", payer_message="dd", currency="EUR") ``` +An extra argument, `callback_url`, can be passed to this method, denoting the URL to the server where the callback should be sent. + +## Remittances +The remittances client can be created with the following paramaters. The `REMITTANCES_USER_ID` and `REMITTANCES_API_SECRET` for production are provided on the MTN OVA dashboard. + +Add the following to your configuration block: +``` + config.remittance_primary_key = 'Your Remittance Subscription Key' + config.remittance_user_id = 'Your Remittance User ID' + config.remittance_api_secret = 'Your Remittance API Key' +``` + +* `remittance_primary_key`: Primary Key for the `Remittance` product on the developer portal. +* `remittance_user_id`: For sandbox, use the one generated with the `momoapi-ruby` command. +* `remittance_api_secret`: For sandbox, use the one generated with the `momoapi-ruby` command. + +You can create a remittance client with the following: + +```ruby +require 'momoapi-ruby' + +remittance = Momoapi::Remittance.new +``` + +### Methods +1. `transfer`: Used to transfer an amount from the owner’s account to a payee account. Status of the transaction can be validated by using the `get_transaction_status` method. + +2. `get_transaction_status`: Retrieve transaction information using the `transaction_id` returned by `transfer`. You can invoke it at intervals until the transaction fails or succeeds. If the transaction has failed, it will throw an appropriate error. + +3. `get_balance`: Get the balance of the account. + +### Sample Code + +```ruby +require 'momoapi-ruby' + +remittance = Momoapi::Remittance.new +remittance.transfer( + mobile="256772123456", amount="600", external_id="123456789", payee_note="dd", payer_message="dd", currency="EUR") +``` +An extra argument, `callback_url`, can be passed to this method, denoting the URL to the server where the callback should be sent. + ## Contributing From 68063ac16b325de43b902c44dad90dd28866fb72 Mon Sep 17 00:00:00 2001 From: NLSanyu Date: Mon, 2 Mar 2020 09:16:24 +0300 Subject: [PATCH 14/16] Refactor client - remove redundant code --- lib/momoapi-ruby/client.rb | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/lib/momoapi-ruby/client.rb b/lib/momoapi-ruby/client.rb index 1aeef84..390b0f1 100644 --- a/lib/momoapi-ruby/client.rb +++ b/lib/momoapi-ruby/client.rb @@ -56,7 +56,7 @@ def get_auth_token(path, subscription_key) end end - def get_balance(path, subscription_key) + def prepare_get_request(path, subscription_key) headers = { "X-Target-Environment": Momoapi.config.environment || 'sandbox', "Content-Type": 'application/json', @@ -65,22 +65,16 @@ def get_balance(path, subscription_key) send_request('get', path, headers) end + def get_balance(path, subscription_key) + prepare_get_request(path, subscription_key) + end + def get_transaction_status(path, subscription_key) - headers = { - "X-Target-Environment": Momoapi.config.environment || 'sandbox', - "Content-Type": 'application/json', - "Ocp-Apim-Subscription-Key": subscription_key - } - send_request('get', path, headers) + prepare_get_request(path, subscription_key) end def is_user_active(path, subscription_key) - headers = { - "X-Target-Environment": Momoapi.config.environment || 'sandbox', - "Content-Type": 'application/json', - "Ocp-Apim-Subscription-Key": subscription_key - } - send_request('get', path, headers) + prepare_get_request(path, subscription_key) end end end From 521bf13df3cd0e51296b56ef69ea7bacab1f7024 Mon Sep 17 00:00:00 2001 From: NLSanyu Date: Mon, 2 Mar 2020 14:11:51 +0300 Subject: [PATCH 15/16] Document methods --- .rubocop.yml | 2 ++ lib/momoapi-ruby/cli.rb | 4 ++++ lib/momoapi-ruby/client.rb | 9 +++++++++ lib/momoapi-ruby/collection.rb | 9 +++++++++ lib/momoapi-ruby/config.rb | 3 +++ lib/momoapi-ruby/disbursement.rb | 6 ++++++ lib/momoapi-ruby/errors.rb | 2 ++ lib/momoapi-ruby/remittance.rb | 6 ++++++ 8 files changed, 41 insertions(+) diff --git a/.rubocop.yml b/.rubocop.yml index f87c66e..0323ea3 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -13,4 +13,6 @@ Lint/DuplicateMethods: Naming/AccessorMethodName: Enabled: false Naming/PredicateName: + Enabled: false +Style/AsciiComments: Enabled: false \ No newline at end of file diff --git a/lib/momoapi-ruby/cli.rb b/lib/momoapi-ruby/cli.rb index 5b31b1f..1fe2f15 100644 --- a/lib/momoapi-ruby/cli.rb +++ b/lib/momoapi-ruby/cli.rb @@ -1,5 +1,9 @@ # frozen_string_literal: true +# This is an executable file allowing a user to use the command line interface +# to pass in a callback host url and a subscription key +# and get back a generated user id and API key + require 'faraday' require 'json' require 'securerandom' diff --git a/lib/momoapi-ruby/client.rb b/lib/momoapi-ruby/client.rb index 390b0f1..6ecefae 100644 --- a/lib/momoapi-ruby/client.rb +++ b/lib/momoapi-ruby/client.rb @@ -1,5 +1,9 @@ # frozen_string_literal: true +# Base implementation of the MTN API client + +# Includes methods common to collections, disbursements and remittances + require 'faraday' require 'momoapi-ruby/config' @@ -38,6 +42,8 @@ def handle_error(response_body, response_code) raise Error::APIError.new(response_body, response_code) end + # Create an access token which can then be used to + # authorize and authenticate towards the other end-points of the API def get_auth_token(path, subscription_key) headers = { "Ocp-Apim-Subscription-Key": subscription_key @@ -65,14 +71,17 @@ def prepare_get_request(path, subscription_key) send_request('get', path, headers) end + # get the balance on an account def get_balance(path, subscription_key) prepare_get_request(path, subscription_key) end + # retrieve transaction information, for transfer and payments def get_transaction_status(path, subscription_key) prepare_get_request(path, subscription_key) end + # check if an account holder is registered and active in the system def is_user_active(path, subscription_key) prepare_get_request(path, subscription_key) end diff --git a/lib/momoapi-ruby/collection.rb b/lib/momoapi-ruby/collection.rb index d0b475d..0240164 100644 --- a/lib/momoapi-ruby/collection.rb +++ b/lib/momoapi-ruby/collection.rb @@ -1,5 +1,7 @@ # frozen_string_literal: true +# Implementation of the MTN API collections client + require 'securerandom' require 'momoapi-ruby/config' @@ -22,6 +24,13 @@ def get_transaction_status(transaction_id) super(path, Momoapi.config.collection_primary_key) end + # This method is used to request a payment from a consumer (Payer). + # The payer will be asked to authorize the payment. The transaction will + # be executed once the payer has authorized the payment. + # The requesttopay will be in status PENDING until the transaction + # is authorized or declined by the payer or it is timed out by the system. + # The status of the transaction can be validated + # by using `get_transation_status` def request_to_pay(phone_number, amount, external_id, payee_note = '', payer_message = '', currency = 'EUR', **options) diff --git a/lib/momoapi-ruby/config.rb b/lib/momoapi-ruby/config.rb index c38362b..53c07b8 100644 --- a/lib/momoapi-ruby/config.rb +++ b/lib/momoapi-ruby/config.rb @@ -1,5 +1,8 @@ # frozen_string_literal: true +# Configurations are set up in this file +# for a user's MTN MoMo API user credentials + module Momoapi class Config attr_accessor :environment, :base_url, diff --git a/lib/momoapi-ruby/disbursement.rb b/lib/momoapi-ruby/disbursement.rb index 5b34cfb..0e7ee62 100644 --- a/lib/momoapi-ruby/disbursement.rb +++ b/lib/momoapi-ruby/disbursement.rb @@ -1,5 +1,7 @@ # frozen_string_literal: true +# Implementation of the MTN API disbursements client + require 'momoapi-ruby/config' require 'momoapi-ruby/client' @@ -20,6 +22,10 @@ def get_transaction_status(transaction_id) super(path, Momoapi.config.disbursement_primary_key) end + # The transfer operation is used to transfer an amount from the owner’s + # account to a payee account. + # The status of the transaction can be validated + # by using `get_transation_status` def transfer(phone_number, amount, external_id, payee_note = '', payer_message = '', currency = 'EUR', **options) diff --git a/lib/momoapi-ruby/errors.rb b/lib/momoapi-ruby/errors.rb index debc076..f229521 100644 --- a/lib/momoapi-ruby/errors.rb +++ b/lib/momoapi-ruby/errors.rb @@ -1,5 +1,7 @@ # frozen_string_literal: true +# Error handling for unsuccessful responses from the MTN Momo API + module Error class APIError < StandardError def initialize(message, code) diff --git a/lib/momoapi-ruby/remittance.rb b/lib/momoapi-ruby/remittance.rb index 3117ee3..2a008ca 100644 --- a/lib/momoapi-ruby/remittance.rb +++ b/lib/momoapi-ruby/remittance.rb @@ -1,5 +1,7 @@ # frozen_string_literal: true +# Implementation of the MTN API remittances client + require 'momoapi-ruby/config' require 'momoapi-ruby/client' @@ -20,6 +22,10 @@ def get_transaction_status(transaction_id) super(path, Momoapi.config.remittance_primary_key) end + # The transfer operation is used to transfer an amount from the owner’s + # account to a payee account. + # The status of the transaction can be validated + # by using `get_transation_status` def transfer(phone_number, amount, external_id, payee_note = '', payer_message = '', currency = 'EUR', **options) From e176cfe761fab8f2a5c46f9b9e9bdce9dbf46961 Mon Sep 17 00:00:00 2001 From: NLSanyu Date: Mon, 2 Mar 2020 16:04:19 +0300 Subject: [PATCH 16/16] Add test coverage badge --- .coveralls.yml | 1 + .rubocop.yml | 2 +- Gemfile.lock | 20 +++++ README.md | 3 +- momoapi-ruby.gemspec | 15 +--- .../collections/checks_is_user_is_active.yml | 83 +++++++++++++++++ .../remittances/gets_balance.yml | 83 +++++++++++++++++ .../remittances/gets_transaction_status.yml | 81 +++++++++++++++++ .../remittances/makes_transfer.yml | 90 +++++++++++++++++++ spec/features/collection_spec.rb | 7 +- spec/features/remittance_spec.rb | 2 +- spec/spec_helper.rb | 3 + 12 files changed, 374 insertions(+), 16 deletions(-) create mode 100644 .coveralls.yml create mode 100644 spec/cassettes/Momoapi_Collection/collections/checks_is_user_is_active.yml create mode 100644 spec/cassettes/Momoapi_Remittance/remittances/gets_balance.yml create mode 100644 spec/cassettes/Momoapi_Remittance/remittances/gets_transaction_status.yml create mode 100644 spec/cassettes/Momoapi_Remittance/remittances/makes_transfer.yml diff --git a/.coveralls.yml b/.coveralls.yml new file mode 100644 index 0000000..3571887 --- /dev/null +++ b/.coveralls.yml @@ -0,0 +1 @@ +repo_token: bYVvifY6POXhFwOja3SZIX1nUxtWrUxKj diff --git a/.rubocop.yml b/.rubocop.yml index 0323ea3..2b681be 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -5,7 +5,7 @@ Naming/FileName: Metrics/MethodLength: Max: 25 Metrics/BlockLength: - Max: 30 + Max: 35 Metrics/ParameterLists: Max: 8 Lint/DuplicateMethods: diff --git a/Gemfile.lock b/Gemfile.lock index 8cebab8..98defcd 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -9,12 +9,20 @@ GEM addressable (2.7.0) public_suffix (>= 2.0.2, < 5.0) coderay (1.1.2) + coveralls (0.8.23) + json (>= 1.8, < 3) + simplecov (~> 0.16.1) + term-ansicolor (~> 1.3) + thor (>= 0.19.4, < 2.0) + tins (~> 1.6) crack (0.4.3) safe_yaml (~> 1.0.0) diff-lcs (1.3) + docile (1.3.2) faraday (1.0.0) multipart-post (>= 1.2, < 3) hashdiff (1.0.0) + json (2.3.0) method_source (0.9.2) multipart-post (2.1.1) pry (0.12.2) @@ -36,6 +44,17 @@ GEM rspec-support (~> 3.9.0) rspec-support (3.9.2) safe_yaml (1.0.5) + simplecov (0.16.1) + docile (~> 1.1) + json (>= 1.8, < 3) + simplecov-html (~> 0.10.0) + simplecov-html (0.10.2) + sync (0.5.0) + term-ansicolor (1.7.1) + tins (~> 1.0) + thor (1.0.1) + tins (1.24.1) + sync vcr (5.1.0) webmock (2.3.2) addressable (>= 2.3.6) @@ -47,6 +66,7 @@ PLATFORMS DEPENDENCIES bundler (~> 2.0) + coveralls (~> 0.8.15) faraday momoapi-ruby! pry (~> 0.12) diff --git a/README.md b/README.md index 691ac53..1e1db94 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,8 @@ # MTN MoMo API Ruby Gem [![Build Status](https://travis-ci.com/sparkplug/momoapi-ruby.svg?branch=master)](https://travis-ci.com/sparkplug/momoapi-ruby) - +[![Coverage Status](https://coveralls.io/repos/github/sparkplug/momoapi-ruby/badge.svg?branch=master)](https://coveralls.io/github/sparkplug/momoapi-ruby?branch=master) +[![Join the community on Spectrum](https://withspectrum.github.io/badge/badge.svg)](https://spectrum.chat/momo-api-developers/) ## Usage diff --git a/momoapi-ruby.gemspec b/momoapi-ruby.gemspec index 477afb6..94b355a 100644 --- a/momoapi-ruby.gemspec +++ b/momoapi-ruby.gemspec @@ -9,17 +9,9 @@ Gem::Specification.new do |spec| spec.version = Momoapi::VERSION spec.authors = ['Lydia Sanyu Naggayi'] spec.email = ['lydiansanyu@gmail.com'] - - spec.summary = 'MTN MoMo API gem' - # spec.description = %q{TODO: Write a longer description} - # spec.homepage = "TODO: Put your gem's website or public repo URL here." - # spec.license = "MIT" - - # spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com'" - - # spec.metadata["homepage_uri"] = spec.homepage - # spec.metadata["source_code_uri"] = "" - # spec.metadata["changelog_uri"] = "" + spec.summary = 'MTN MoMo gem' + spec.description = 'MTN MoMo API Client for Ruby' + spec.license = 'MIT' # Specify which files should be added to the gem when it is released. # The `git ls-files -z` loads the files in the @@ -33,6 +25,7 @@ Gem::Specification.new do |spec| spec.require_paths = ['lib'] spec.add_development_dependency 'bundler', '~> 2.0' + spec.add_development_dependency 'coveralls', '~> 0.8.15' spec.add_development_dependency 'faraday' spec.add_development_dependency 'pry', '~> 0.12' spec.add_development_dependency 'rake', '~> 10.0' diff --git a/spec/cassettes/Momoapi_Collection/collections/checks_is_user_is_active.yml b/spec/cassettes/Momoapi_Collection/collections/checks_is_user_is_active.yml new file mode 100644 index 0000000..0041499 --- /dev/null +++ b/spec/cassettes/Momoapi_Collection/collections/checks_is_user_is_active.yml @@ -0,0 +1,83 @@ +--- +http_interactions: +- request: + method: post + uri: https://sandbox.momodeveloper.mtn.com/collection/token/ + body: + encoding: UTF-8 + string: '' + headers: + Ocp-Apim-Subscription-Key: + - b5e0f061fa5a4cbbbd2192530b7cedfb + Authorization: + - Basic NzgzYThmMjEtM2ZjNi00ZTM5LWFhNzYtZGE4ZTU2MmZiYTdlOjMxM2NmYWY5YTQwYjQwMjliNzEzOWY0YzlkOGFmYjIz + Content-Length: + - '0' + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + response: + status: + code: 200 + message: OK + headers: + Cache-Control: + - no-store + Pragma: + - no-cache + Content-Length: + - '628' + Content-Type: + - application/json;charset=utf-8 + Request-Context: + - appId=cid-v1:e996501c-e721-4ac1-97ff-dc6887b85e8c + Date: + - Mon, 02 Mar 2020 11:29:47 GMT + body: + encoding: UTF-8 + string: '{"access_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJSMjU2In0.eyJjbGllbnRJZCI6Ijc4M2E4ZjIxLTNmYzYtNGUzOS1hYTc2LWRhOGU1NjJmYmE3ZSIsImV4cGlyZXMiOiIyMDIwLTAzLTAyVDEyOjI5OjQ3LjUxMCIsInNlc3Npb25JZCI6IjA3NDk2NmEzLWZhYzktNDMzNC1iYWM0LTM3ZDk1NzRkZDBlYSJ9.d29q6K1ne03SSOdSVaQ_ofTL8mkhXxjoLgRl92h9Dboo5dSyP-pvXW7plMEuU_9yqCRV3B3wGcb0y9791vZAbjgag9cixJBUJY9vktPr_O32VoTB-wnMzy44xUJc3pfqCnne4U8jkm3C3uYrZnEp3jJGh9Ac7mC-SPASEcRRb2g2l9dH8gU1BG43zjkr3MWY7LIk6ZWZ0qDMc6zughjKldp93aphLMvL-WGcwufjtkej6XrXbHw_6maFGdsz5RdYIIHUbGobphOAL9zqEqW0n4Cbr-AC2BGuMI0k_B94Iy4csZ-knbtsDy1819cInW2Fxg_K88rhQZPvRDhf6LvDZA","token_type":"access_token","expires_in":3600}' + http_version: null + recorded_at: Mon, 02 Mar 2020 11:29:47 GMT +- request: + method: get + uri: https://sandbox.momodeveloper.mtn.com/collection/v1_0/accountholder/msisdn/0243656543/active + body: + encoding: US-ASCII + string: '' + headers: + X-Target-Environment: + - sandbox + Content-Type: + - application/json + Ocp-Apim-Subscription-Key: + - b5e0f061fa5a4cbbbd2192530b7cedfb + Authorization: + - Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSMjU2In0.eyJjbGllbnRJZCI6Ijc4M2E4ZjIxLTNmYzYtNGUzOS1hYTc2LWRhOGU1NjJmYmE3ZSIsImV4cGlyZXMiOiIyMDIwLTAzLTAyVDEyOjI5OjQ3LjUxMCIsInNlc3Npb25JZCI6IjA3NDk2NmEzLWZhYzktNDMzNC1iYWM0LTM3ZDk1NzRkZDBlYSJ9.d29q6K1ne03SSOdSVaQ_ofTL8mkhXxjoLgRl92h9Dboo5dSyP-pvXW7plMEuU_9yqCRV3B3wGcb0y9791vZAbjgag9cixJBUJY9vktPr_O32VoTB-wnMzy44xUJc3pfqCnne4U8jkm3C3uYrZnEp3jJGh9Ac7mC-SPASEcRRb2g2l9dH8gU1BG43zjkr3MWY7LIk6ZWZ0qDMc6zughjKldp93aphLMvL-WGcwufjtkej6XrXbHw_6maFGdsz5RdYIIHUbGobphOAL9zqEqW0n4Cbr-AC2BGuMI0k_B94Iy4csZ-knbtsDy1819cInW2Fxg_K88rhQZPvRDhf6LvDZA + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + response: + status: + code: 200 + message: OK + headers: + Content-Length: + - '15' + Content-Type: + - application/json;charset=utf-8 + Request-Context: + - appId=cid-v1:e996501c-e721-4ac1-97ff-dc6887b85e8c + Date: + - Mon, 02 Mar 2020 11:29:49 GMT + body: + encoding: UTF-8 + string: '{"result":true}' + http_version: null + recorded_at: Mon, 02 Mar 2020 11:29:49 GMT +recorded_with: VCR 5.1.0 diff --git a/spec/cassettes/Momoapi_Remittance/remittances/gets_balance.yml b/spec/cassettes/Momoapi_Remittance/remittances/gets_balance.yml new file mode 100644 index 0000000..6032575 --- /dev/null +++ b/spec/cassettes/Momoapi_Remittance/remittances/gets_balance.yml @@ -0,0 +1,83 @@ +--- +http_interactions: +- request: + method: post + uri: https://sandbox.momodeveloper.mtn.com/remittance/token/ + body: + encoding: UTF-8 + string: '' + headers: + Ocp-Apim-Subscription-Key: + - d314b91c889340b682a9a3144a9ffd1b + Authorization: + - Basic NzgzYThmMjEtM2ZjNi00ZTM5LWFhNzYtZGE4ZTU2MmZiYTdlOjMxM2NmYWY5YTQwYjQwMjliNzEzOWY0YzlkOGFmYjIz + Content-Length: + - '0' + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + response: + status: + code: 200 + message: OK + headers: + Cache-Control: + - no-store + Pragma: + - no-cache + Content-Length: + - '628' + Content-Type: + - application/json;charset=utf-8 + Request-Context: + - appId=cid-v1:e996501c-e721-4ac1-97ff-dc6887b85e8c + Date: + - Mon, 02 Mar 2020 12:07:55 GMT + body: + encoding: UTF-8 + string: '{"access_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJSMjU2In0.eyJjbGllbnRJZCI6Ijc4M2E4ZjIxLTNmYzYtNGUzOS1hYTc2LWRhOGU1NjJmYmE3ZSIsImV4cGlyZXMiOiIyMDIwLTAzLTAyVDEzOjA3OjU1LjE0MyIsInNlc3Npb25JZCI6IjgzY2Y3Zjg3LWNlN2EtNDlmYi04ZDU4LTdiMTFmODA0NWE1NSJ9.gT1-u80gziEk8_DaT3y4T14PJdJ2tfPYdK1yJAlIMTA-g3eIfIVmCQ7PIo1SnHhRHcJN-CIL0kRsk9lBxSWN5r2aUWLHrZQoTrnE0HkmSZtAsofzKJOhpHgk4K_L2H9aFnSHISDGqFnosRh6RcNOsactnVw4YPxKvbs9ysZ8Vh5eJPpqQ7KdhDRnILuBzikN1cJe-kOjsv0nKWOp88peDHy_HtXPzrAXJBzP0a5ElodnjnlXLu0J-TQET0l-Sll26YN4T9FdnC-3teJIwwNWSufndy0ynvHbagrG6VB_im27wa4Z7EwXhXmOgJe0PsnEAdzbmEEF87kSQ2rb-FnYdw","token_type":"access_token","expires_in":3600}' + http_version: null + recorded_at: Mon, 02 Mar 2020 12:07:55 GMT +- request: + method: get + uri: https://sandbox.momodeveloper.mtn.com/remittance/v1_0/account/balance + body: + encoding: US-ASCII + string: '' + headers: + X-Target-Environment: + - sandbox + Content-Type: + - application/json + Ocp-Apim-Subscription-Key: + - d314b91c889340b682a9a3144a9ffd1b + Authorization: + - Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSMjU2In0.eyJjbGllbnRJZCI6Ijc4M2E4ZjIxLTNmYzYtNGUzOS1hYTc2LWRhOGU1NjJmYmE3ZSIsImV4cGlyZXMiOiIyMDIwLTAzLTAyVDEzOjA3OjU1LjE0MyIsInNlc3Npb25JZCI6IjgzY2Y3Zjg3LWNlN2EtNDlmYi04ZDU4LTdiMTFmODA0NWE1NSJ9.gT1-u80gziEk8_DaT3y4T14PJdJ2tfPYdK1yJAlIMTA-g3eIfIVmCQ7PIo1SnHhRHcJN-CIL0kRsk9lBxSWN5r2aUWLHrZQoTrnE0HkmSZtAsofzKJOhpHgk4K_L2H9aFnSHISDGqFnosRh6RcNOsactnVw4YPxKvbs9ysZ8Vh5eJPpqQ7KdhDRnILuBzikN1cJe-kOjsv0nKWOp88peDHy_HtXPzrAXJBzP0a5ElodnjnlXLu0J-TQET0l-Sll26YN4T9FdnC-3teJIwwNWSufndy0ynvHbagrG6VB_im27wa4Z7EwXhXmOgJe0PsnEAdzbmEEF87kSQ2rb-FnYdw + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + response: + status: + code: 500 + message: Server Error + headers: + Content-Length: + - '93' + Content-Type: + - application/json;charset=utf-8 + Request-Context: + - appId=cid-v1:e996501c-e721-4ac1-97ff-dc6887b85e8c + Date: + - Mon, 02 Mar 2020 12:07:56 GMT + body: + encoding: UTF-8 + string: '{"message":"An internal error occurred while processing.","code":"INTERNAL_PROCESSING_ERROR"}' + http_version: null + recorded_at: Mon, 02 Mar 2020 12:07:56 GMT +recorded_with: VCR 5.1.0 diff --git a/spec/cassettes/Momoapi_Remittance/remittances/gets_transaction_status.yml b/spec/cassettes/Momoapi_Remittance/remittances/gets_transaction_status.yml new file mode 100644 index 0000000..ea71bf2 --- /dev/null +++ b/spec/cassettes/Momoapi_Remittance/remittances/gets_transaction_status.yml @@ -0,0 +1,81 @@ +--- +http_interactions: +- request: + method: post + uri: https://sandbox.momodeveloper.mtn.com/remittance/token/ + body: + encoding: UTF-8 + string: '' + headers: + Ocp-Apim-Subscription-Key: + - d314b91c889340b682a9a3144a9ffd1b + Authorization: + - Basic NzgzYThmMjEtM2ZjNi00ZTM5LWFhNzYtZGE4ZTU2MmZiYTdlOjMxM2NmYWY5YTQwYjQwMjliNzEzOWY0YzlkOGFmYjIz + Content-Length: + - '0' + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + response: + status: + code: 200 + message: OK + headers: + Cache-Control: + - no-store + Pragma: + - no-cache + Content-Length: + - '628' + Content-Type: + - application/json;charset=utf-8 + Request-Context: + - appId=cid-v1:e996501c-e721-4ac1-97ff-dc6887b85e8c + Date: + - Mon, 02 Mar 2020 12:07:57 GMT + body: + encoding: UTF-8 + string: '{"access_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJSMjU2In0.eyJjbGllbnRJZCI6Ijc4M2E4ZjIxLTNmYzYtNGUzOS1hYTc2LWRhOGU1NjJmYmE3ZSIsImV4cGlyZXMiOiIyMDIwLTAzLTAyVDEzOjA3OjU3LjQ0NyIsInNlc3Npb25JZCI6ImE1MjM3NzJkLTQ2ZTQtNGRiNy05YjliLWZjYzQyMTMyOTVmNyJ9.hck9MYcTndOMH45kMoqhQO7-Ml0a6fBtwZOtB-Xax_Ru-FP-1efBLnpbTIWzC9H888o6NieyZPHpecnMoak1OwgudseSsF8cW5W0cYVWgqe1YEBppJlSvo6vTLBWIpR0nJ6QhHew3uZMl6CJoya5Zgu1DDNpfbNOOatNy-ae_1TDqsGbTi7eGZQ0ePzsgJ88EMpUekyjP5gbwlvWO1SWcsrAG3kgzmWb6twHdTN355izeQ4iXYt_bCyHdmKJhb2M2Bz_M9CDpq4QWXhXdUIeFqv0bRk9ReLnUoIM2bMtaXzwb6JX4ouulYuhP3knvYbzikb8HEjDr_h3Bke5KPIGjw","token_type":"access_token","expires_in":3600}' + http_version: null + recorded_at: Mon, 02 Mar 2020 12:07:57 GMT +- request: + method: get + uri: https://sandbox.momodeveloper.mtn.com/remittance/v1_0/transfer/888a79ff-0535-4a9f-8a66-457f7903bd8ab + body: + encoding: US-ASCII + string: '' + headers: + X-Target-Environment: + - sandbox + Content-Type: + - application/json + Ocp-Apim-Subscription-Key: + - d314b91c889340b682a9a3144a9ffd1b + Authorization: + - Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSMjU2In0.eyJjbGllbnRJZCI6Ijc4M2E4ZjIxLTNmYzYtNGUzOS1hYTc2LWRhOGU1NjJmYmE3ZSIsImV4cGlyZXMiOiIyMDIwLTAzLTAyVDEzOjA3OjU3LjQ0NyIsInNlc3Npb25JZCI6ImE1MjM3NzJkLTQ2ZTQtNGRiNy05YjliLWZjYzQyMTMyOTVmNyJ9.hck9MYcTndOMH45kMoqhQO7-Ml0a6fBtwZOtB-Xax_Ru-FP-1efBLnpbTIWzC9H888o6NieyZPHpecnMoak1OwgudseSsF8cW5W0cYVWgqe1YEBppJlSvo6vTLBWIpR0nJ6QhHew3uZMl6CJoya5Zgu1DDNpfbNOOatNy-ae_1TDqsGbTi7eGZQ0ePzsgJ88EMpUekyjP5gbwlvWO1SWcsrAG3kgzmWb6twHdTN355izeQ4iXYt_bCyHdmKJhb2M2Bz_M9CDpq4QWXhXdUIeFqv0bRk9ReLnUoIM2bMtaXzwb6JX4ouulYuhP3knvYbzikb8HEjDr_h3Bke5KPIGjw + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + response: + status: + code: 400 + message: Bad Request + headers: + Content-Length: + - '0' + Request-Context: + - appId=cid-v1:e996501c-e721-4ac1-97ff-dc6887b85e8c + Date: + - Mon, 02 Mar 2020 12:07:57 GMT + body: + encoding: UTF-8 + string: '' + http_version: null + recorded_at: Mon, 02 Mar 2020 12:07:58 GMT +recorded_with: VCR 5.1.0 diff --git a/spec/cassettes/Momoapi_Remittance/remittances/makes_transfer.yml b/spec/cassettes/Momoapi_Remittance/remittances/makes_transfer.yml new file mode 100644 index 0000000..093649e --- /dev/null +++ b/spec/cassettes/Momoapi_Remittance/remittances/makes_transfer.yml @@ -0,0 +1,90 @@ +--- +http_interactions: +- request: + method: post + uri: https://sandbox.momodeveloper.mtn.com/remittance/token/ + body: + encoding: UTF-8 + string: '' + headers: + Ocp-Apim-Subscription-Key: + - d314b91c889340b682a9a3144a9ffd1b + Authorization: + - Basic NzgzYThmMjEtM2ZjNi00ZTM5LWFhNzYtZGE4ZTU2MmZiYTdlOjMxM2NmYWY5YTQwYjQwMjliNzEzOWY0YzlkOGFmYjIz + Content-Length: + - '0' + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + response: + status: + code: 200 + message: OK + headers: + Cache-Control: + - no-store + Pragma: + - no-cache + Content-Length: + - '628' + Content-Type: + - application/json;charset=utf-8 + Request-Context: + - appId=cid-v1:e996501c-e721-4ac1-97ff-dc6887b85e8c + Date: + - Mon, 02 Mar 2020 12:07:59 GMT + body: + encoding: UTF-8 + string: '{"access_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJSMjU2In0.eyJjbGllbnRJZCI6Ijc4M2E4ZjIxLTNmYzYtNGUzOS1hYTc2LWRhOGU1NjJmYmE3ZSIsImV4cGlyZXMiOiIyMDIwLTAzLTAyVDEzOjA3OjU5LjQ4MyIsInNlc3Npb25JZCI6Ijg2NGU2ZTdmLTBkZmMtNGM3MS04ODIyLWZjY2Y1NDgxMGI0OCJ9.MDAyvP439yl-G-O9hiO8AjDxgO7R-nreq2eSiEf13B9xz4HjmyulUa0cp1Ls_8mtkrdIgeYXXAV-L0d4L6u_02hUC5MGzA5IbNxwfd9Lt74LlEUn7TvVkhfK1hbBUA_D_vrH1Imgmt7KT5SZC54WaEmWTUHRx5OS_acrekeny0oV1DhQuCoA1ArA_W6-sZLzXG7S8N6QZy6usU8fWD9Fs7hiuS8B9lMthg2EjXpqa5UWdmlNUuQdzh5ri0_nxzeWLHsq64OPYeFlppKQXYHUf6Lrd4YSMCNq9ktSHSSNjmWSrWwrUPMuji5NZ2uB7djCDZ7LmLWUfxhEmZwIigjg5w","token_type":"access_token","expires_in":3600}' + http_version: null + recorded_at: Mon, 02 Mar 2020 12:07:59 GMT +- request: + method: post + uri: https://sandbox.momodeveloper.mtn.com/remittance/v1_0/transfer + body: + encoding: UTF-8 + string: '' + headers: + X-Target-Environment: + - sandbox + Content-Type: + - application/json + X-Reference-Id: + - df2b6f54-114f-4588-8dce-a4c50734f9e4 + Ocp-Apim-Subscription-Key: + - 0c74e0a1cf344d45a3d02b1da52c12f5 + Authorization: + - Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSMjU2In0.eyJjbGllbnRJZCI6Ijc4M2E4ZjIxLTNmYzYtNGUzOS1hYTc2LWRhOGU1NjJmYmE3ZSIsImV4cGlyZXMiOiIyMDIwLTAzLTAyVDEzOjA3OjU5LjQ4MyIsInNlc3Npb25JZCI6Ijg2NGU2ZTdmLTBkZmMtNGM3MS04ODIyLWZjY2Y1NDgxMGI0OCJ9.MDAyvP439yl-G-O9hiO8AjDxgO7R-nreq2eSiEf13B9xz4HjmyulUa0cp1Ls_8mtkrdIgeYXXAV-L0d4L6u_02hUC5MGzA5IbNxwfd9Lt74LlEUn7TvVkhfK1hbBUA_D_vrH1Imgmt7KT5SZC54WaEmWTUHRx5OS_acrekeny0oV1DhQuCoA1ArA_W6-sZLzXG7S8N6QZy6usU8fWD9Fs7hiuS8B9lMthg2EjXpqa5UWdmlNUuQdzh5ri0_nxzeWLHsq64OPYeFlppKQXYHUf6Lrd4YSMCNq9ktSHSSNjmWSrWwrUPMuji5NZ2uB7djCDZ7LmLWUfxhEmZwIigjg5w + Content-Length: + - '0' + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + response: + status: + code: 401 + message: Access Denied + headers: + Content-Length: + - '143' + Content-Type: + - application/json + Request-Context: + - appId=cid-v1:e996501c-e721-4ac1-97ff-dc6887b85e8c + Www-Authenticate: + - AzureApiManagementKey realm="https://sandbox.momodeveloper.mtn.com/remittance",name="Ocp-Apim-Subscription-Key",type="header" + Date: + - Mon, 02 Mar 2020 12:07:59 GMT + body: + encoding: UTF-8 + string: '{ "statusCode": 401, "message": "Access denied due to invalid subscription + key. Make sure to provide a valid key for an active subscription." }' + http_version: null + recorded_at: Mon, 02 Mar 2020 12:08:00 GMT +recorded_with: VCR 5.1.0 diff --git a/spec/features/collection_spec.rb b/spec/features/collection_spec.rb index 3a9f3a1..fc30a6e 100644 --- a/spec/features/collection_spec.rb +++ b/spec/features/collection_spec.rb @@ -14,9 +14,12 @@ end describe 'collections', vcr: { record: :new_episodes } do + it 'checks is user is active' do + response = Momoapi::Collection.new.is_user_active('0243656543') + expect(response[:code]).to eq(200) + end + it 'gets balance' do - # response = Momoapi::Collection.new.get_balance - # expect(response).to have_http_status 200 expect { Momoapi::Collection.new.get_balance } .to raise_error(Error::APIError) end diff --git a/spec/features/remittance_spec.rb b/spec/features/remittance_spec.rb index 8c966b6..33b26bc 100644 --- a/spec/features/remittance_spec.rb +++ b/spec/features/remittance_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Momoapi::Disbursement do +RSpec.describe Momoapi::Remittance do before(:all) do Momoapi.configure do |config| config.base_url = 'https://sandbox.momodeveloper.mtn.com' diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index c2ce482..473a5da 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,5 +1,8 @@ # frozen_string_literal: true +require 'coveralls' +Coveralls.wear! + require 'bundler/setup' require 'momoapi-ruby' require 'webmock/rspec'