campay 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 7bc61d686a4ee807457519c2e3a6c961186e20a2c9d25bb83a933afcbaf65feb
4
+ data.tar.gz: 85217e1686de496b46bf583a72e387af7598c769c612705077c8d63e4fc47aca
5
+ SHA512:
6
+ metadata.gz: 7e84c520cfdee0b360353ace37ca9654520da0d4422140bd8ff9dd136c90b6153e449d2cc91e147538b89b62a9c8dbf799bd09690dc7ebf1ca3453323b9d1bda
7
+ data.tar.gz: 17258d79a81ce6a5cde24af746fcfecda78fc8473db0f0386e879823dd611a0c8e4ff77ec31fa71bef78ed706f7086b282f36390dc90438fda811ce2de92ec58
data/.byebug_history ADDED
@@ -0,0 +1,69 @@
1
+ q!
2
+ response_json.to_s
3
+ puts ">>>>>>>>>>>>>>>>>>: " + response_json.to_s
4
+ puts ">>>>>>>>>>>>>>>>>>: " + response_json
5
+ response_json
6
+ q!
7
+ MultiJson.load(withdraw_response.body).values[0]
8
+ MultiJson.load(withdraw_response.body),values
9
+ MultiJson.load(withdraw_response.body)
10
+ (withdraw_response.body)['message']
11
+ (withdraw_response.body)
12
+ (withdraw_response.body)[0]
13
+ (withdraw_response.body).first
14
+ (withdraw_response.body).values
15
+ withdraw_response.body
16
+ MultiJson.dump(withdraw_response.body)
17
+ puts "The response is" + (withdraw_response_json.values).to_s
18
+ puts "The response is" + (withdraw_response_json.values).to_string
19
+ puts "The response is" + withdraw_response_json.values
20
+ puts "The response is" + withdraw_response_json.value
21
+ withdraw_response_json.values
22
+ withdraw_response_json.value
23
+ withdraw_response_json.message
24
+ withdraw_response_json
25
+ puts "The response is" + withdraw_response_json
26
+ q!
27
+ (MultiJson.load(withdraw_response.body))
28
+ (MultiJson.load(withdraw_response.body)).keys
29
+ (MultiJson.load(withdraw_response.body)).values
30
+ MultiJson.load(withdraw_response.body)
31
+ withdraw_response.body.values
32
+ withdraw_response.body['message']
33
+ withdraw_response.body[:message]
34
+ withdraw_response.body
35
+ withdraw_response.status
36
+ withdraw_response.reason_phrase
37
+ withdraw_response.response
38
+ (to_str(withdraw_response)).to_json
39
+ to_str(withdraw_response)
40
+ MultiJson.load(withdraw_response)
41
+ MultiJson.dump(withdraw_response)
42
+ withdraw_response.to_json
43
+ JSON.parse(withdraw_response)
44
+ withdraw_response.body
45
+ q!
46
+ MultiJson.load(collect_response_json)
47
+ collect_response_json.to_json
48
+ collect_response_json.status
49
+ collect_response_json
50
+ collect_response.body
51
+ collect_response
52
+ collect_response.message
53
+ collect_response
54
+ link_value
55
+ q!
56
+ take_reference.values[0]
57
+ take_reference.values
58
+ take_reference[:reference]
59
+ take_reference.reference
60
+ take_reference
61
+ q!
62
+ MultiJson.load(collect_response.body)
63
+ take_reference
64
+ reference.to_json
65
+ reference
66
+ reference[:reference]
67
+ reference.reference
68
+ reference
69
+ q!
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/.rubocop.yml ADDED
@@ -0,0 +1,13 @@
1
+ AllCops:
2
+ TargetRubyVersion: 2.6
3
+
4
+ Style/StringLiterals:
5
+ Enabled: true
6
+ EnforcedStyle: double_quotes
7
+
8
+ Style/StringLiteralsInInterpolation:
9
+ Enabled: true
10
+ EnforcedStyle: double_quotes
11
+
12
+ Layout/LineLength:
13
+ Max: 120
data/CHANGELOG.md ADDED
@@ -0,0 +1,5 @@
1
+ ## [Unreleased]
2
+
3
+ ## [0.1.0] - 2022-11-10
4
+
5
+ - Initial release
@@ -0,0 +1,84 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation.
6
+
7
+ We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community.
8
+
9
+ ## Our Standards
10
+
11
+ Examples of behavior that contributes to a positive environment for our community include:
12
+
13
+ * Demonstrating empathy and kindness toward other people
14
+ * Being respectful of differing opinions, viewpoints, and experiences
15
+ * Giving and gracefully accepting constructive feedback
16
+ * Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience
17
+ * Focusing on what is best not just for us as individuals, but for the overall community
18
+
19
+ Examples of unacceptable behavior include:
20
+
21
+ * The use of sexualized language or imagery, and sexual attention or
22
+ advances of any kind
23
+ * Trolling, insulting or derogatory comments, and personal or political attacks
24
+ * Public or private harassment
25
+ * Publishing others' private information, such as a physical or email
26
+ address, without their explicit permission
27
+ * Other conduct which could reasonably be considered inappropriate in a
28
+ professional setting
29
+
30
+ ## Enforcement Responsibilities
31
+
32
+ Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful.
33
+
34
+ Community leaders have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, and will communicate reasons for moderation decisions when appropriate.
35
+
36
+ ## Scope
37
+
38
+ This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public spaces. Examples of representing our community include using an official e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event.
39
+
40
+ ## Enforcement
41
+
42
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at hguruman@gmail.com. All complaints will be reviewed and investigated promptly and fairly.
43
+
44
+ All community leaders are obligated to respect the privacy and security of the reporter of any incident.
45
+
46
+ ## Enforcement Guidelines
47
+
48
+ Community leaders will follow these Community Impact Guidelines in determining the consequences for any action they deem in violation of this Code of Conduct:
49
+
50
+ ### 1. Correction
51
+
52
+ **Community Impact**: Use of inappropriate language or other behavior deemed unprofessional or unwelcome in the community.
53
+
54
+ **Consequence**: A private, written warning from community leaders, providing clarity around the nature of the violation and an explanation of why the behavior was inappropriate. A public apology may be requested.
55
+
56
+ ### 2. Warning
57
+
58
+ **Community Impact**: A violation through a single incident or series of actions.
59
+
60
+ **Consequence**: A warning with consequences for continued behavior. No interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, for a specified period of time. This includes avoiding interactions in community spaces as well as external channels like social media. Violating these terms may lead to a temporary or permanent ban.
61
+
62
+ ### 3. Temporary Ban
63
+
64
+ **Community Impact**: A serious violation of community standards, including sustained inappropriate behavior.
65
+
66
+ **Consequence**: A temporary ban from any sort of interaction or public communication with the community for a specified period of time. No public or private interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, is allowed during this period. Violating these terms may lead to a permanent ban.
67
+
68
+ ### 4. Permanent Ban
69
+
70
+ **Community Impact**: Demonstrating a pattern of violation of community standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals.
71
+
72
+ **Consequence**: A permanent ban from any sort of public interaction within the community.
73
+
74
+ ## Attribution
75
+
76
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.0,
77
+ available at https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
78
+
79
+ Community Impact Guidelines were inspired by [Mozilla's code of conduct enforcement ladder](https://github.com/mozilla/diversity).
80
+
81
+ [homepage]: https://www.contributor-covenant.org
82
+
83
+ For answers to common questions about this code of conduct, see the FAQ at
84
+ https://www.contributor-covenant.org/faq. Translations are available at https://www.contributor-covenant.org/translations.
data/Gemfile ADDED
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ # Specify your gem's dependencies in campay.gemspec
6
+ gemspec
7
+
8
+ gem "rake", "~> 13.0"
9
+
10
+ gem "rspec", "~> 3.0"
11
+
12
+ gem "faraday", "~> 2.5", ">= 2.5.2"
13
+ gem "multi_json", "~> 1.15"
14
+ gem "rubocop", "~> 1.21"
15
+ gem "faraday-net_http", "~> 3.0"
data/Gemfile.lock ADDED
@@ -0,0 +1,68 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ campay (0.1.0)
5
+ json_pure (~> 2.6, >= 2.6.2)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ ast (2.4.2)
11
+ byebug (11.1.3)
12
+ diff-lcs (1.5.0)
13
+ faraday (2.6.0)
14
+ faraday-net_http (>= 2.0, < 3.1)
15
+ ruby2_keywords (>= 0.0.4)
16
+ faraday-net_http (3.0.1)
17
+ json_pure (2.6.2)
18
+ multi_json (1.15.0)
19
+ parallel (1.22.1)
20
+ parser (3.1.2.1)
21
+ ast (~> 2.4.1)
22
+ rainbow (3.1.1)
23
+ rake (13.0.6)
24
+ regexp_parser (2.6.0)
25
+ rexml (3.2.5)
26
+ rspec (3.12.0)
27
+ rspec-core (~> 3.12.0)
28
+ rspec-expectations (~> 3.12.0)
29
+ rspec-mocks (~> 3.12.0)
30
+ rspec-core (3.12.0)
31
+ rspec-support (~> 3.12.0)
32
+ rspec-expectations (3.12.0)
33
+ diff-lcs (>= 1.2.0, < 2.0)
34
+ rspec-support (~> 3.12.0)
35
+ rspec-mocks (3.12.0)
36
+ diff-lcs (>= 1.2.0, < 2.0)
37
+ rspec-support (~> 3.12.0)
38
+ rspec-support (3.12.0)
39
+ rubocop (1.31.0)
40
+ parallel (~> 1.10)
41
+ parser (>= 3.1.0.0)
42
+ rainbow (>= 2.2.2, < 4.0)
43
+ regexp_parser (>= 1.8, < 3.0)
44
+ rexml (>= 3.2.5, < 4.0)
45
+ rubocop-ast (>= 1.18.0, < 2.0)
46
+ ruby-progressbar (~> 1.7)
47
+ unicode-display_width (>= 1.4.0, < 3.0)
48
+ rubocop-ast (1.23.0)
49
+ parser (>= 3.1.1.0)
50
+ ruby-progressbar (1.11.0)
51
+ ruby2_keywords (0.0.5)
52
+ unicode-display_width (2.3.0)
53
+
54
+ PLATFORMS
55
+ x86_64-linux
56
+
57
+ DEPENDENCIES
58
+ byebug
59
+ campay!
60
+ faraday (~> 2.5, >= 2.5.2)
61
+ faraday-net_http (~> 3.0)
62
+ multi_json (~> 1.15)
63
+ rake (~> 13.0)
64
+ rspec (~> 3.0)
65
+ rubocop (~> 1.21)
66
+
67
+ BUNDLED WITH
68
+ 2.3.25
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2022 happiguru
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,155 @@
1
+ # [CamPay](https://www.campay.net/) Ruby SDK
2
+
3
+ Ruby on Rails SDK for CamPay Payment Gateway
4
+
5
+ CamPay is a Fintech service of the company TAKWID
6
+ GROUP which launched its financial services in Cameroon
7
+ from January 2021.
8
+
9
+ We provide businesses and institutions with solutions for
10
+ collecting and transferring money online, via primarily
11
+ Mobile Money(MTN and Orange).
12
+
13
+ With CamPay, simplify the purchasing experience for
14
+ your customers thanks to our mobile money
15
+ payment solutions, accessible via your website
16
+ and/or mobile application.
17
+
18
+
19
+ ## Summary
20
+
21
+ - [Getting Started](#getting-started)
22
+ - [Running the samples](#running-the-samples)
23
+ - [Deployment](#deployment)
24
+
25
+ ## Getting Started
26
+
27
+ These instructions will get you started with the CamPay SDK for development and testing purposes. See deployment
28
+ for notes on how to deploy the project on a live system.
29
+
30
+ ### Prerequisites
31
+
32
+ - Create an account on [CamPay](https://www.campay.net/) platform
33
+ - Register an application under your account.
34
+ - Expand your registered application to get access to your API keys
35
+
36
+ ### Installing
37
+
38
+ ```
39
+ gem install campay
40
+ ```
41
+ or
42
+ ```
43
+ gem campay
44
+ ```
45
+ ## Running the samples
46
+
47
+ - If you plan to use `.env` then add:
48
+ ```gem 'dotenv'```
49
+ to your gemfile in order to save your secret credentials
50
+ ```
51
+ campay = Campay::CamPay.new(
52
+ ENV.fetch('PAY_UNIT_API_USERNAME'),
53
+ ENV.fetch('PAY_UNIT_API_PASSWORD'),
54
+ ENV.fetch('PAY_UNIT_MODE'))
55
+ ```
56
+ ### To collect payments from your client - DIRECTLY
57
+
58
+ ```
59
+ collect = collect(
60
+ amount, #The amount you want to collect
61
+ currency, #XAF
62
+ from, #Phone number to request amount from - Must include country code
63
+ description, #some description
64
+ external_reference #Reference from the system initiating the transaction
65
+ )
66
+
67
+
68
+ puts collect
69
+ #{"reference": "bcedde9b-62a7-4421-96ac-2e6179552a1a", "external_reference":"12345678", "status": "SUCCESSFUL", "amount": 5, "currency": "XAF", "operator": "MTN", "code": "CP201027T00005", "operator_reference": "1880106956" }
70
+
71
+ ```
72
+ > status can be SUCCESSFUL or FAILED
73
+
74
+ ### To collect payments from your client - using PAYMENT LINKS
75
+
76
+ ```
77
+ link = campay.fetch_payment_link(
78
+ amount,
79
+ currency,
80
+ from,
81
+ description,
82
+ reference,
83
+ redirect_url
84
+ )
85
+ '''
86
+ Redirect your customer to the returned payment link
87
+ '''
88
+
89
+ ```
90
+ > status can be SUCCESSFUL or FAILED
91
+
92
+ ### To disburse
93
+ > Please enable API withdrawal under app settings before trying this request
94
+
95
+ ```
96
+ disburse = campay.disburse(
97
+ amount,
98
+ currency,
99
+ to,
100
+ description,
101
+ external_reference
102
+ )
103
+
104
+ puts disburse
105
+ #{"reference": "bcedde9b-62a7-4421-96ac-2e6179552a1a", "external_reference":"12345678", "status": "SUCCESSFUL", "amount": 5, "currency": "XAF", "operator": "MTN", "code": "CP201027T00005", "operator_reference": "1880106956" }
106
+
107
+ ```
108
+ > status can be SUCCESSFUL or FAILED
109
+
110
+ ### To Get application balance.
111
+
112
+ ```
113
+ balance = campay.fetch_balance
114
+
115
+ puts balance
116
+ #{"total_balance": 0, "mtn_balance": 0, "orange_balance": 0, "currency": "XAF"}
117
+ ```
118
+
119
+ ### Transfer Airtime
120
+ > Please enable API withdrawal under app settings before trying this request
121
+
122
+ ```
123
+ airtime = campay.transfer_airtime(
124
+ amount,
125
+ to,
126
+ external_reference
127
+ )
128
+
129
+ puts airtime
130
+ #{"reference": "bcedde9b-62a7-4421-96ac-2e6179552a1a", "external_reference":"12345678", "status": "SUCCESSFUL", "amount": 5, "currency": "XAF", "operator": "MTN", "code": "CP201027U00005", "operator_reference": "1880106956" }
131
+
132
+ ```
133
+ > status can be SUCCESSFUL or FAILED
134
+
135
+ ### ✒️ Authors
136
+
137
+ 👤 **Stanley Enow Lekunze**
138
+
139
+ - Github: [@happiguru](https://github.com/happiguru)
140
+ - LinkedIn:[LinkedIn](https://www.linkedin.com/in/lekunze-nley)
141
+
142
+ 👤 **CHE NSOH BLANCHARD**
143
+
144
+ - GitHub: [@che30](https://github.com/che30)
145
+ - Twitter: [@BlanchardNsoh](https://twitter.com/che55085128 )
146
+ - LinkedIn: [Che Blanchard](https://www.linkedin.com/in/che-nsoh-9455271b0/)
147
+
148
+ ## License
149
+
150
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
151
+
152
+
153
+ ## Code of Conduct
154
+
155
+ Everyone interacting in the Campay project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/campay/blob/main/CODE_OF_CONDUCT.md).
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rspec/core/rake_task"
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ require "rubocop/rake_task"
9
+
10
+ RuboCop::RakeTask.new
11
+
12
+ task default: %i[spec rubocop]
data/campay-0.1.0.gem ADDED
Binary file
@@ -0,0 +1,130 @@
1
+ q!
2
+ take_token.values[0]
3
+ take_token.value[0]
4
+ take_token.values
5
+ take_token.value
6
+ take_token
7
+ take_token[token]
8
+ take_token[0]
9
+ take_token.token
10
+ q!
11
+ JSON.parse(token_response.body)
12
+ take_token[0]
13
+ take_token['token']
14
+ take_token.token
15
+ take_token
16
+ q!
17
+ token_response.body.to_json
18
+ token_response
19
+ MultiJson.load(token_response)
20
+ MultiJson.dump(token_response)
21
+ MultiJson.dump(json_token_response)
22
+ MultiJson.load(json_token_response)
23
+ json_token_response.to_json
24
+ json_token_response.inspect
25
+ json_token_response
26
+ token_response.body
27
+ token_response.body.token
28
+ token_response.body['token']
29
+ token_response.body
30
+ token_response._body
31
+ token_response.response_body
32
+ token_response['response_body']
33
+ token_response
34
+ token_response.to_json
35
+ token_response['token']
36
+ token_response.token
37
+ token_response
38
+ json_token_response
39
+ json_token_response.inspect
40
+ json_token_response.to_json
41
+ json_token_response
42
+ json_token_response.token
43
+ json_token_response['token']
44
+ token_response_response_status_code
45
+ token
46
+ q!
47
+ MultiJson.dump(token_response)
48
+ MultiJson.load(token_response)
49
+ token_response
50
+ q!
51
+ token_response
52
+ q!
53
+ token_response
54
+ q!
55
+ conn.post(@host+'/api/token/', data=json_data, headers=token_headers)
56
+ conn.post(@host+'/api/token/', data=json_datah, headers=token_headers)
57
+ conn.post(@host+'/api/token/', data=json_datah, headers=token_headers, verify=false)
58
+ conn.post(@host+'/api/token/', data=json_datah, headers=token_headers, verify=False)
59
+ json_datah
60
+ q!
61
+ MultiJson.dump(data)
62
+ MultiJson({
63
+ "username": @app_username,
64
+ "password": @app_password
65
+ })
66
+ MultiJson.load(data)
67
+ MultiJson.load(json_data)
68
+ json_data
69
+ q!
70
+ json_data
71
+ conn.post("https://demo.campay.net", data=json_data, headers=token_headers)json_data
72
+ conn.post("https://demo.campay.net", '{
73
+ "username": "Z4y4ANtzsJOW87HDoXKBMFA1AaBgbrXCl-nexl4r2WqKLnq-B4xYqDT2vQ1xMNaFpl6KpB8Rbf0XgMQn3VJvUw",
74
+ "password": "2DSGX0gzAR1mGvMbXPTxQh9womLUHF4JtTo9SgtkxM31zCsncCAtOMoODBxBZrihvpA3KHWIDHTt8KYup1tNyg"
75
+ }', headers=token_headers)
76
+ conn.post("https://demo.campay.net", data=json_data, headers=token_headers)
77
+ conn
78
+ q!
79
+ conn.post("https://demo.campay.net", data=json_data, headers=token_headers)
80
+ conn.post("https://demo.campay.net", data=json_data)
81
+ conn.post("https://demo.campay.net", data)
82
+ q!
83
+ conn.post("https://demo.campay.net", data)
84
+ conn.post("https://demo.campay.net", data=json_data)
85
+ conn.post("https://demo.campay.net")
86
+ conn
87
+ q!
88
+ HTTP.post('https://demo.campay.net/api/token/', data=json_data, headers=token_headers)
89
+ data.to_json
90
+ data
91
+ q!
92
+ data
93
+ json_data
94
+ q!
95
+ JSON.parse(data)
96
+ token_headers
97
+ json_data
98
+ HTTP.post('https://demo.campay.net/api/token/', data=json_data)
99
+ HTTP.post('https://demo.campay.net/api/token/', data=json_data, headers=token_headers)
100
+ HTTP.post('https://demo.campay.net/api/token/')
101
+ HTTP.post('https://restapi.com/objects')
102
+ HTTP.get('https://www.google.com')
103
+ q!
104
+ token_headers.to_json
105
+ token_headers
106
+ json_data
107
+ Requests.post('https://demo.campay.net/api/token/', data=json_data, headers=token_headers)
108
+ Requests.request("GET", "http://example.com")
109
+ Requests.request("GET", "http://tecnovice.com/api/v1/institutions")
110
+ Requests.get("www.tecnovice.com/api/v1/institutions")
111
+ q!
112
+ Requests.get("www.tecnovice.com/api/v1/institutions")
113
+ Requests.request("GET", "www.tecnovice.com/api/v1/institutions")
114
+ Requests.request("GET", "http://tecnovice.com/api/v1/institutions")
115
+ Requests.request("GET", "http://example.com")
116
+ Requests.post('https://demo.campay.net/api/token/', data=json_data, headers=token_headers)
117
+ q!
118
+ JSON.generate(json_data)
119
+ json_data.to_json
120
+ token_headers
121
+ json_data
122
+ q!
123
+ eval get_token
124
+ conn
125
+ q!
126
+ token_response
127
+ eval get_token
128
+ conn
129
+ q!
130
+ conn
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Campay
4
+ VERSION = "0.1.1"
5
+ end
data/lib/campay.rb ADDED
@@ -0,0 +1,511 @@
1
+ # frozen_string_literal: true
2
+
3
+ # rubocop:disable Metrics/MethodLength
4
+ # rubocop:disable Metrics/AbcSize
5
+ # rubocop:disable Metrics/ClassLength
6
+ # rubocop:disable Metrics/PerceivedComplexity
7
+ # rubocop:disable Metrics/CyclomaticComplexity
8
+ # rubocop:disable Metrics/BlockNesting
9
+ # rubocop:disable Metrics/ParameterLists
10
+
11
+ require_relative "campay/version"
12
+ require "multi_json"
13
+ require "net/http"
14
+ require "faraday"
15
+ require "faraday/net_http"
16
+ Faraday.default_adapter = :net_http
17
+
18
+ module Campay
19
+ class Error < StandardError; end
20
+
21
+ # Campay payment class
22
+ class CamPay
23
+ def initialize(app_username, app_password, environment)
24
+ @app_username = app_username
25
+ @app_password = app_password
26
+ @environment = environment
27
+
28
+ if @environment == "DEV"
29
+ @host = "https://demo.campay.net"
30
+ @debug = true
31
+ else
32
+ @host = "https://campay.net"
33
+ @debug = false
34
+ end
35
+ end
36
+
37
+ def fetch_token
38
+ token_headers = {
39
+ "Content-Type": "application/json"
40
+ }
41
+
42
+ data = {
43
+ "username": @app_username,
44
+ "password": @app_password
45
+ }
46
+ json_data = MultiJson.dump(data)
47
+ got_json_response = false
48
+
49
+ begin
50
+ conn = Faraday.new(
51
+ url: "#{@host}/api/token/",
52
+ headers: token_headers
53
+ )
54
+ token_response = conn.post("#{@host}/api/token/", json_data, token_headers)
55
+ json_token_response = MultiJson.dump(token_response)
56
+
57
+ got_json_response = true
58
+ puts got_json_response
59
+ rescue StandardError => e
60
+ puts e
61
+ end
62
+ if got_json_response
63
+ token_response_response_status_code = token_response.status
64
+ if token_response_response_status_code == 200
65
+ take_token = JSON.parse(token_response.body)
66
+ token = take_token.values[0]
67
+ is_successful = true
68
+ else
69
+ token = "None"
70
+ is_successful = false
71
+ puts json_token_response if @debug
72
+ end
73
+ { "token": token, "is_successful": is_successful }
74
+ else
75
+ { "token": "None", "is_successful": false }
76
+ end
77
+ end
78
+
79
+ def collect(amount, currency, from, description, external_reference)
80
+ puts ">>>>>>>>>>>>>>>>>>:Collecting..." if @debug
81
+ token = fetch_token[:token]
82
+
83
+ if token
84
+ #### Request collect
85
+ collect_data = {
86
+ "amount": to_str(amount),
87
+ "currency": to_str(currency),
88
+ "from": to_str(from),
89
+ "description": to_str(description),
90
+ "external_reference": to_str(external_reference)
91
+ }
92
+ collect_payload = MultiJson.dump(collect_data)
93
+ collect_headers = {
94
+ 'Authorization': "Token #{token}",
95
+ 'Content-Type': "application/json"
96
+ }
97
+
98
+ got_json_response = false
99
+
100
+ begin
101
+ conn = Faraday.new(
102
+ url: "#{@host}/api/collect/",
103
+ headers: collect_headers
104
+ )
105
+ collect_response = conn.post("#{@host}/api/collect/", collect_payload, collect_headers)
106
+ collect_response_json = collect_response.inspect
107
+ got_json_response = true
108
+ puts collect_response
109
+ rescue StandardError => e
110
+ puts e
111
+ end
112
+
113
+ if got_json_response
114
+ puts ">>>>>>>>>>>>>>>>>>: #{collect_response_json}" if @debug
115
+ collect_response_status_code = collect_response.status
116
+ if collect_response_status_code == 200
117
+ take_reference = MultiJson.load(collect_response.body)
118
+ reference = take_reference.values[0]
119
+
120
+ puts ">>>>>>>>>>>>>>>>>>: Confirm on phone..."
121
+ is_successful = true
122
+ else
123
+ reference = "None"
124
+ is_successful = false
125
+ end
126
+
127
+ if is_successful
128
+ # ###Check Transaction Status
129
+ status_headers = {
130
+ 'Authorization': "Token #{token}",
131
+ 'Content-Type': "application/json"
132
+ }
133
+ status = "PENDING"
134
+ # trial = 0
135
+ while status == "PENDING"
136
+ sleep(5)
137
+ got_json_response = false
138
+ # trial += 1
139
+ begin
140
+ conn = Faraday.new(
141
+ url: "#{@host}/api/transaction/",
142
+ headers: status_headers
143
+ )
144
+ status_response = conn.get("#{@host}/api/transaction/#{reference}", status_headers)
145
+ status_response_json = status_response.to_json
146
+ got_json_response = true
147
+ rescue StandardError => e
148
+ puts e
149
+ end
150
+
151
+ next unless got_json_response
152
+
153
+ status_response_status_code = status_response.status
154
+ if status_response_status_code == 200
155
+ status = status_response_json["status"]
156
+
157
+ if status != "PENDING"
158
+ puts ">>>>>>>>>>>>>>>>>>: #{status_response_json}" if @debug
159
+ return status_response_json
160
+ end
161
+ else
162
+ puts "Awaiting transaction details!"
163
+ end
164
+ # break if trial == 10
165
+ end
166
+ else
167
+ message = collect_response_json["message"]
168
+ puts ">>>>>>>>>>>>>>>>>>: #{message}" if @debug
169
+ { "status": "FAILED", "message": message }
170
+ end
171
+ else
172
+ message = "Collect error"
173
+ puts ">>>>>>>>>>>>>>>>>>: #{message}" if @debug
174
+ { "status": "FAILED", "message": message }
175
+ end
176
+ else
177
+ message = "Token error. Please check your App Username and Pass password. Also check your environment"
178
+ puts ">>>>>>>>>>>>>>>>>>: #{message}" if @debug
179
+ { "status": "FAILED", "message": message }
180
+ end
181
+ end
182
+
183
+ def fetch_payment_link(amount, currency, description, external_reference, redirect_url)
184
+ puts ">>>>>>>>>>>>>>>>>>: Getting payment link..." if @debug
185
+
186
+ token = fetch_token[:token]
187
+
188
+ if token
189
+
190
+ #### Request collect
191
+ collect_data = {
192
+ "amount": to_str(amount),
193
+ "currency": to_str(currency),
194
+ "description": to_str(description),
195
+ "external_reference": to_str(external_reference),
196
+ "redirect_url": to_str(redirect_url)
197
+ }
198
+ collect_payload = MultiJson.dump(collect_data)
199
+ collect_headers = {
200
+ 'Authorization': "Token #{token}",
201
+ 'Content-Type': "application/json"
202
+ }
203
+ got_json_response = false
204
+
205
+ begin
206
+ conn = Faraday.new(
207
+ url: "#{@host}/api/get_payment_link/",
208
+ headers: collect_headers
209
+ )
210
+ collect_response = conn.post("#{@host}/api/get_payment_link/", collect_payload, collect_headers)
211
+
212
+ collect_response_json = collect_response.inspect
213
+ got_json_response = true
214
+
215
+ puts "Payment link response #{collect_response_json}"
216
+ rescue StandardError => e
217
+ puts e
218
+ end
219
+ if got_json_response
220
+ puts ">>>>>>>>>>>>>>>>>>: #{collect_response_json}" if @debug
221
+
222
+ collect_response_status_code = collect_response.status
223
+ if collect_response_status_code == 200
224
+ link_value = MultiJson.load(collect_response.body)
225
+ link = link_value.values[0]
226
+ puts "The link is #{link}"
227
+ if @debug
228
+ puts ">>>>>>>>>>>>>>>>>>: Redirect your customer to the payment link..."
229
+ is_successful = true
230
+ end
231
+ else
232
+ link = "None"
233
+ is_successful = false
234
+ end
235
+
236
+ if is_successful
237
+ # ###Check Transaction Status
238
+ { "status": "SUCCESSFUL", "link": link }
239
+
240
+ else
241
+ message = collect_response_json
242
+ puts ">>>>>>>>>>>>>>>>>>: #{message}" if @debug
243
+
244
+ { "status": "FAILED", "message": message }
245
+ end
246
+ else
247
+ message = "Collect error"
248
+ puts ">>>>>>>>>>>>>>>>>>: #{message}" if @debug
249
+ { "status": "FAILED", "message": message }
250
+ end
251
+ else
252
+ message = "Token error. Please check your App Username and Pass password. Also check your environment"
253
+ puts ">>>>>>>>>>>>>>>>>>: #{message}" if @debug
254
+ { "status": "FAILED", "message": message }
255
+ end
256
+ end
257
+
258
+ def disburse(amount, currency, to, description, external_reference)
259
+ puts ">>>>>>>>>>>>>>>>>>: Disbursing..." if @debug
260
+
261
+ token = fetch_token[:token]
262
+ if token
263
+
264
+ #### Request withdraw
265
+ withdraw_data = {
266
+ "amount": to_str(amount),
267
+ "currency": to_str(currency),
268
+ "to": to_str(to),
269
+ "description": to_str(description),
270
+ "external_reference": to_str(external_reference)
271
+ }
272
+ withdraw_payload = MultiJson.dump(withdraw_data)
273
+ withdraw_headers = {
274
+ 'Authorization': "Token #{token}",
275
+ 'Content-Type': "application/json"
276
+ }
277
+ # got_json_response = false
278
+ begin
279
+ conn = Faraday.new(
280
+ url: "#{@host}/api/withdraw/",
281
+ headers: withdraw_headers
282
+ )
283
+ withdraw_response = conn.post("#{@host}/api/withdraw/", withdraw_payload, withdraw_headers)
284
+ withdraw_response_json = MultiJson.load(withdraw_response.body).values[0]
285
+
286
+ got_json_response = true
287
+ puts "The response is#{withdraw_response_json}"
288
+
289
+ if got_json_response
290
+ puts ">>>>>>>>>>>>>>>>>>: #{withdraw_response_json}" if @debug
291
+ withdraw_response_status_code = withdraw_response.status
292
+ if withdraw_response_status_code == 200
293
+ reference = withdraw_response_json
294
+ is_successful = true
295
+ else
296
+ reference = "None"
297
+ is_successful = false
298
+ end
299
+ if is_successful
300
+ # ###Check Transaction Status
301
+ status_headers = {
302
+ 'Authorization': "Token #{token}",
303
+ 'Content-Type': "application/json"
304
+ }
305
+
306
+ status = "PENDING"
307
+ while status == "PENDING"
308
+ sleep(5)
309
+
310
+ got_json_response = false
311
+ begin
312
+ conn = Faraday.new(
313
+ url: "#{@host}/api/transaction/",
314
+ headers: status_headers
315
+ )
316
+ status_response = conn.get("#{@host}/api/transaction/#{reference}", status_headers)
317
+ status_response_json = MultiJson.dump(status_response)
318
+ got_json_response = true
319
+ rescue StandardError => e
320
+ puts e
321
+ end
322
+
323
+ next unless got_json_response
324
+
325
+ status_response_status_code = status_response.status
326
+ if status_response_status_code == 200
327
+ status = status_response_json.status
328
+
329
+ if status != "PENDING"
330
+ puts ">>>>>>>>>>>>>>>>>>: #{status_response_json}" if @debug
331
+ return status_response_json
332
+ end
333
+ else
334
+ pass
335
+ end
336
+ end
337
+
338
+ else
339
+ message = withdraw_response_json
340
+ puts ">>>>>>>>>>>>>>>>>>: #{message}" if @debug
341
+ { "status": "FAILED", "message": message }
342
+ end
343
+ else
344
+ message = "Disburse error"
345
+ puts ">>>>>>>>>>>>>>>>>>: #{message}" if @debug
346
+ { "status": "FAILED", "message": message }
347
+ end
348
+ rescue StandardError => e
349
+ puts e
350
+ end
351
+ else
352
+ message = "Token error. Please check your App Username and Pass password. Also check your environment"
353
+ puts ">>>>>>>>>>>>>>>>>>: #{message}" if @debug
354
+ { "status": "FAILED", "message": message }
355
+ end
356
+ end
357
+
358
+ def transfer_airtime(amount, to, external_reference)
359
+ puts ">>>>>>>>>>>>>>>>>>: Airtime Transfer..." if @debug
360
+ token = fetch_token[:token]
361
+ if token
362
+ #### Request airtime
363
+ airtime_data = {
364
+ "amount": to_str(amount),
365
+ "to": to_str(to),
366
+ "external_reference": to_str(external_reference)
367
+ }
368
+ airtime_payload = MultiJson.dump(airtime_data)
369
+ airtime_headers = {
370
+ 'Authorization': "Token #{token}",
371
+ 'Content-Type': "application/json"
372
+ }
373
+ got_json_response = false
374
+ begin
375
+ conn = Faraday.new(
376
+ url: "#{@host}/api/utilities/airtime/transfer/",
377
+ headers: airtime_headers
378
+ )
379
+ airtime_response = conn.post("#{@host}/api/utilities/airtime/transfer/", airtime_payload, airtime_headers)
380
+ airtime_response_json = MultiJson.load(airtime_response.body).values[0]
381
+ got_json_response = true
382
+ rescue StandardError => e
383
+ puts e
384
+ end
385
+ if got_json_response
386
+ puts ">>>>>>>>>>>>>>>>>>: #{airtime_response_json}" if @debug
387
+ airtime_response_status_code = airtime_response.status
388
+ if airtime_response_status_code == 200
389
+ reference = airtime_response_json
390
+ is_successful = true
391
+ else
392
+ reference = "None"
393
+ is_successful = false
394
+ end
395
+ if is_successful
396
+ # ###Check Transaction Status
397
+ status_headers = {
398
+ 'Authorization': "Token #{token}",
399
+ 'Content-Type': "application/json"
400
+ }
401
+
402
+ status = "PENDING"
403
+ while status == "PENDING"
404
+ sleep(5)
405
+
406
+ got_json_response = false
407
+ begin
408
+ conn = Faraday.new(
409
+ url: "#{@host}/api/utilities/transaction/",
410
+ headers: airtime_headers
411
+ )
412
+ status_response = conn.get("#{@host}/api/utilities/transaction/#{reference}/", status_headers)
413
+ status_response_json = MultiJson.dump(status_response)
414
+ got_json_response = true
415
+ rescue StandardError => e
416
+ puts e
417
+ end
418
+ next unless got_json_response
419
+
420
+ status_response_status_code = status_response.status
421
+ if status_response_status_code == 200
422
+ status = status_response_json
423
+
424
+ if status != "PENDING"
425
+ puts ">>>>>>>>>>>>>>>>>>: #{status_response_json}" if @debug
426
+ return status_response_json
427
+ end
428
+ else
429
+ pass
430
+ end
431
+ end
432
+ else
433
+ message = airtime_response_json
434
+ puts ">>>>>>>>>>>>>>>>>>: #{message}" if @debug
435
+ { "status": "FAILED", "message": message }
436
+ end
437
+ else
438
+ message = "Disburse error"
439
+ puts ">>>>>>>>>>>>>>>>>>: #{message}" if @debug
440
+ { "status": "FAILED", "message": message }
441
+ end
442
+ else
443
+ message = "Token error. Please check your App Username and Pass password. Also check your environment"
444
+ puts ">>>>>>>>>>>>>>>>>>: #{message}" if @debug
445
+ { "status": "FAILED", "message": message }
446
+ end
447
+ end
448
+
449
+ def fetch_balance
450
+ puts ">>>>>>>>>>>>>>>>>>: Getting balance..." if @debug
451
+ token = fetch_token[:token]
452
+ if token
453
+ status_headers = {
454
+ 'Authorization': "Token #{token}",
455
+ 'Content-Type': "application/json"
456
+ }
457
+
458
+ begin
459
+ conn = Faraday.new(
460
+ url: "#{@host}/api/utilities/balance/",
461
+ headers: status_headers
462
+ )
463
+ response = conn.get("#{@host}/api/balance/", status_headers)
464
+ response_json = MultiJson.load(response.body).values[0]
465
+ got_json_response = true
466
+ if got_json_response
467
+ puts ">>>>>>>>>>>>>>>>>>: #{to_str(response_json)}" if @debug
468
+ to_str(response_json)
469
+ else
470
+ message = "Balance error"
471
+ puts ">>>>>>>>>>>>>>>>>>: #{message}" if @debug
472
+ { "status": "FAILED", "message": message }
473
+ end
474
+ rescue StandardError => e
475
+ puts e
476
+ end
477
+ else
478
+ message = "Token error. Please check your App Username and Pass password. Also check your environment"
479
+ puts ">>>>>>>>>>>>>>>>>>: #{message}" if @debug
480
+ { "status": "FAILED", "message": message }
481
+ end
482
+ end
483
+
484
+ private
485
+
486
+ def to_str(param)
487
+ param.to_s
488
+ end
489
+ end
490
+ end
491
+ # rubocop:enable Metrics/MethodLength
492
+ # rubocop:enable Metrics/AbcSize
493
+ # rubocop:enable Metrics/ClassLength
494
+ # rubocop:enable Metrics/PerceivedComplexity
495
+ # rubocop:enable Metrics/CyclomaticComplexity
496
+ # rubocop:enable Metrics/BlockNesting
497
+ # rubocop:enable Metrics/ParameterLists
498
+ app_username = "Z4y4ANtzsJOW87HDoXKBMFA1AaBgbrXCl-nexl4r2WqKLnq-B4xYqDT2vQ1xMNaFpl6KpB8Rbf0XgMQn3VJvUw"
499
+ app_password = "2DSGX0gzAR1mGvMbXPTxQh9womLUHF4JtTo9SgtkxM31zCsncCAtOMoODBxBZrihvpA3KHWIDHTt8KYup1tNyg"
500
+ environment = "DEV"
501
+
502
+ campay = Campay::CamPay.new("Z4y4ANtzsJOW87HDoXKBMFA1AaBgbrXCl-nexl4r2WqKLnq-B4xYqDT2vQ1xMNaFpl6KpB8Rbf0XgMQn3VJvUw", "2DSGX0gzAR1mGvMbXPTxQh9womLUHF4JtTo9SgtkxM31zCsncCAtOMoODBxBZrihvpA3KHWIDHTt8KYup1tNyg", "DEV")
503
+ campay = Campay::CamPay.new(app_username, app_password, environment)
504
+ # campay.fetch_token
505
+ # campay.collect(100, "XAF", "237651982230", "test transaction", "1BTre7frence")
506
+ campay.fetch_payment_link(100, "XAF", "test transaction", "1BTre7frence", "https://example.com")
507
+ # campay.disburse(100, "XAF", "237651982230", "test transaction", "1BTre7frence")
508
+ # campay.transfer_airtime(100, "237651982230", "1BTre7frence")
509
+ # campay.fetch_balance
510
+ # fetch_payment_link(amount, currency, description, external_reference, redirect_url)
511
+ # collect(amount, currency, from, external_reference)
data/sig/campay.rbs ADDED
@@ -0,0 +1,4 @@
1
+ module Campay
2
+ VERSION: String
3
+ # See the writing guide of rbs: https://github.com/ruby/rbs#guides
4
+ end
metadata ADDED
@@ -0,0 +1,132 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: campay
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ platform: ruby
6
+ authors:
7
+ - happiguru
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2022-11-13 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: json_pure
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.6'
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 2.6.2
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '2.6'
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 2.6.2
33
+ - !ruby/object:Gem::Dependency
34
+ name: multi_json
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '1.15'
40
+ type: :runtime
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '1.15'
47
+ - !ruby/object:Gem::Dependency
48
+ name: faraday
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '2.5'
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ version: 2.5.2
57
+ type: :runtime
58
+ prerelease: false
59
+ version_requirements: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - "~>"
62
+ - !ruby/object:Gem::Version
63
+ version: '2.5'
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ version: 2.5.2
67
+ - !ruby/object:Gem::Dependency
68
+ name: faraday-net_http
69
+ requirement: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - "~>"
72
+ - !ruby/object:Gem::Version
73
+ version: '3.0'
74
+ type: :runtime
75
+ prerelease: false
76
+ version_requirements: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - "~>"
79
+ - !ruby/object:Gem::Version
80
+ version: '3.0'
81
+ description: |-
82
+ To aid Cameroon businesses to make both national and
83
+ international payments using MTN and Orange Mobile Money, Credit Card.
84
+ email:
85
+ - hguruman@gmail.com
86
+ executables: []
87
+ extensions: []
88
+ extra_rdoc_files: []
89
+ files:
90
+ - ".byebug_history"
91
+ - ".rspec"
92
+ - ".rubocop.yml"
93
+ - CHANGELOG.md
94
+ - CODE_OF_CONDUCT.md
95
+ - Gemfile
96
+ - Gemfile.lock
97
+ - LICENSE.txt
98
+ - README.md
99
+ - Rakefile
100
+ - campay-0.1.0.gem
101
+ - lib/.byebug_history
102
+ - lib/campay.rb
103
+ - lib/campay/version.rb
104
+ - sig/campay.rbs
105
+ homepage: https://rubygems.org/gems/campay
106
+ licenses:
107
+ - MIT
108
+ metadata:
109
+ allowed_push_host: https://rubygems.org/
110
+ homepage_uri: https://rubygems.org/gems/campay
111
+ source_code_uri: https://github.com/happiguru/campay
112
+ changelog_uri: https://github.com/happiguru/campay/issues
113
+ post_install_message:
114
+ rdoc_options: []
115
+ require_paths:
116
+ - lib
117
+ required_ruby_version: !ruby/object:Gem::Requirement
118
+ requirements:
119
+ - - ">="
120
+ - !ruby/object:Gem::Version
121
+ version: 2.6.0
122
+ required_rubygems_version: !ruby/object:Gem::Requirement
123
+ requirements:
124
+ - - ">="
125
+ - !ruby/object:Gem::Version
126
+ version: '0'
127
+ requirements: []
128
+ rubygems_version: 3.3.7
129
+ signing_key:
130
+ specification_version: 4
131
+ summary: Cameroon Payment Gateway.
132
+ test_files: []