t2_airtime 0.1.2

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
+ SHA1:
3
+ metadata.gz: c6e8d1b5cfa93a9f398cc58bd1089bfc128a0dd0
4
+ data.tar.gz: e75396f390b165e992e87e37d75557fb82a7c427
5
+ SHA512:
6
+ metadata.gz: ae9a53249041d93c36146080f8cefa03052c5d90b32afe117d097f0333b68c835672a0aad09aefe1bdf0a61204a328371c52331a6bb1eb1010569aee16c2ff1d
7
+ data.tar.gz: 764234e7bfbfd290da1effb363c223ad7c21193df6e30c10ed5c200b674db654324ea18d2d2505cbf2e66adb5cf0032b9a3c0c50abc1e7b8ff010d82d8b40f99
data/.gitignore ADDED
@@ -0,0 +1,15 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ /bin/
11
+
12
+ # rspec failure tracking
13
+ .rspec_status
14
+
15
+ .env
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.3.3
5
+ before_install: gem install bundler -v 1.15.4
@@ -0,0 +1,74 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ In the interest of fostering an open and welcoming environment, we as
6
+ contributors and maintainers pledge to making participation in our project and
7
+ our community a harassment-free experience for everyone, regardless of age, body
8
+ size, disability, ethnicity, gender identity and expression, level of experience,
9
+ nationality, personal appearance, race, religion, or sexual identity and
10
+ orientation.
11
+
12
+ ## Our Standards
13
+
14
+ Examples of behavior that contributes to creating a positive environment
15
+ include:
16
+
17
+ * Using welcoming and inclusive language
18
+ * Being respectful of differing viewpoints and experiences
19
+ * Gracefully accepting constructive criticism
20
+ * Focusing on what is best for the community
21
+ * Showing empathy towards other community members
22
+
23
+ Examples of unacceptable behavior by participants include:
24
+
25
+ * The use of sexualized language or imagery and unwelcome sexual attention or
26
+ advances
27
+ * Trolling, insulting/derogatory comments, and personal or political attacks
28
+ * Public or private harassment
29
+ * Publishing others' private information, such as a physical or electronic
30
+ address, without explicit permission
31
+ * Other conduct which could reasonably be considered inappropriate in a
32
+ professional setting
33
+
34
+ ## Our Responsibilities
35
+
36
+ Project maintainers are responsible for clarifying the standards of acceptable
37
+ behavior and are expected to take appropriate and fair corrective action in
38
+ response to any instances of unacceptable behavior.
39
+
40
+ Project maintainers have the right and responsibility to remove, edit, or
41
+ reject comments, commits, code, wiki edits, issues, and other contributions
42
+ that are not aligned to this Code of Conduct, or to ban temporarily or
43
+ permanently any contributor for other behaviors that they deem inappropriate,
44
+ threatening, offensive, or harmful.
45
+
46
+ ## Scope
47
+
48
+ This Code of Conduct applies both within project spaces and in public spaces
49
+ when an individual is representing the project or its community. Examples of
50
+ representing a project or community include using an official project e-mail
51
+ address, posting via an official social media account, or acting as an appointed
52
+ representative at an online or offline event. Representation of a project may be
53
+ further defined and clarified by project maintainers.
54
+
55
+ ## Enforcement
56
+
57
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
58
+ reported by contacting the project team at TODO: Write your email address. All
59
+ complaints will be reviewed and investigated and will result in a response that
60
+ is deemed necessary and appropriate to the circumstances. The project team is
61
+ obligated to maintain confidentiality with regard to the reporter of an incident.
62
+ Further details of specific enforcement policies may be posted separately.
63
+
64
+ Project maintainers who do not follow or enforce the Code of Conduct in good
65
+ faith may face temporary or permanent repercussions as determined by other
66
+ members of the project's leadership.
67
+
68
+ ## Attribution
69
+
70
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71
+ available at [http://contributor-covenant.org/version/1/4][version]
72
+
73
+ [homepage]: http://contributor-covenant.org
74
+ [version]: http://contributor-covenant.org/version/1/4/
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ # Specify your gem's dependencies in t2_airtime.gemspec
6
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2017 matteolc
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,83 @@
1
+ # TransferTo Airtime API
2
+
3
+ TransferTo helps businesses offer airtime top-ups, goods and services, and mobile money around the world in real time.
4
+ This API enables developers to integrate TransferTo Top-up service into their system. If you are building
5
+ application that leverages international recharge services, then this is the API for you.
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 't2_airtime'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install t2_airtime
22
+
23
+ ## Usage
24
+
25
+ ### Retrieve your API Token
26
+ Once you have received your account credentials (login, password) to access the TransferTo web
27
+ interface, you must log in and retrieve your API token to be used with the TransferTo API.
28
+ To activate access to your API account, enable Two Factor Authentication (2FA).
29
+
30
+ TSHOP_USER=
31
+ TSHOP_SECRET=
32
+
33
+ ## Test
34
+
35
+ Execute:
36
+
37
+ $ rspec
38
+
39
+ T2Airtime
40
+ has a version number
41
+ has the correct API URL
42
+ has 7 test numbers
43
+ responds to ping
44
+ checks wallet
45
+ checks number information
46
+ reserves a transaction id
47
+ returns a countries list
48
+ returns a country operators
49
+ returns an operator products
50
+ returns error code 0 for PIN based Top-up (successful transaction)
51
+ returns error code 0 for PIN less Top-up (successful transaction)
52
+ returns error code 204 (destination number is not a valid prepaid phone number) (FAILED - 1)
53
+ returns error code 301 (input value out of range or invalid product) (FAILED - 2)
54
+ returns error code 214 (transaction refused by the operator) (FAILED - 3)
55
+ returns error code 998 (system not available, please retry later) (FAILED - 4)
56
+ returns error code 999 (unknown error, please contact support) (FAILED - 5)
57
+ returns a transaction list
58
+
59
+ Failed examples:
60
+
61
+ rspec ./spec/t2_airtime_spec.rb:99 # T2Airtime returns error code 204 (destination number is not a valid prepaid phone number)
62
+ rspec ./spec/t2_airtime_spec.rb:108 # T2Airtime returns error code 301 (input value out of range or invalid product)
63
+ rspec ./spec/t2_airtime_spec.rb:117 # T2Airtime returns error code 214 (transaction refused by the operator)
64
+ rspec ./spec/t2_airtime_spec.rb:126 # T2Airtime returns error code 998 (system not available, please retry later)
65
+ rspec ./spec/t2_airtime_spec.rb:135 # T2Airtime returns error code 999 (unknown error, please contact support)
66
+
67
+ ## Development
68
+
69
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
70
+
71
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
72
+
73
+ ## Contributing
74
+
75
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/t2_airtime. 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.
76
+
77
+ ## License
78
+
79
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
80
+
81
+ ## Code of Conduct
82
+
83
+ Everyone interacting in the T2Airtime project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/t2_airtime/blob/master/CODE_OF_CONDUCT.md).
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,290 @@
1
+ module T2Airtime
2
+ class API < Base
3
+
4
+ # Test the connection to the Airtime API. Can be used for keep-alive.
5
+ def ping
6
+ run_action :ping
7
+ end
8
+
9
+ # Returns the balance in your TransferTo account.
10
+ # This method shall not be used more than 24 times per day.
11
+ def check_wallet
12
+ run_action :check_wallet
13
+ end
14
+
15
+ # This method is used to recharge a destination number with a specified
16
+ # denomination (“product” field).
17
+ # This is the API’s most important action as it is required when sending
18
+ # a topup to a prepaid account phone numberin a live! environment.
19
+ #
20
+ # parameters
21
+ # ==========
22
+ # msisdn
23
+ # ------
24
+ # The international phone number of the user requesting to credit
25
+ # a TransferToAPI phone number. The format must contain the country code,
26
+ # and will be valid with or without the ‘+’ or ‘00’ placed before it. For
27
+ # example: “6012345678” or “+6012345678” or “006012345678” (Malaysia) are
28
+ # all valid.
29
+ #
30
+ # product
31
+ # -------
32
+ # This field is used to define the remote product(often, the same as the
33
+ # amount in destination currency) to use in the request.
34
+ #
35
+ # destination
36
+ # -----------
37
+ # This is the destination phone number that will be credited with the
38
+ # amount transferred. Format is similar to “msisdn”.
39
+ #
40
+ # operator_id
41
+ # -----------
42
+ # It defines the operator id of the destination MSISDN that must be used
43
+ # when treating the request. If set, the platform will be forced to use
44
+ # this operatorID and will not identify the operator of the destination
45
+ # MSISDN based on the numbering plan. It must be very useful in case of
46
+ # countries with number portability if you are able to know the destination
47
+ # operator.
48
+
49
+ # Most receiving operators (or carriers) are PIN less (direct top-up), meaning that the mobile phone of the
50
+ # recipient is recharged in real time. A few operators are however PIN based (mostly in the USA and UK).
51
+ # For these PIN based operators, a PIN code is sent by SMS to the recipient, who then has to manually
52
+ # complete the recharge process (usually by calling an IVR to redeem the PIN).
53
+
54
+ # Name Type Description
55
+ # pin_based String Returns “Yes” if PIN-based transactions. Else “No”.
56
+ # pin_option_1 String Additional information. For example, it can describe how to use
57
+ # the PIN directly from handset (by entering a dedicated USSD code).
58
+ # pin_option_2 String Additional information. For example, it can provide the operator refill website.
59
+ # pin_option_3 String Additional information. For example, it can provide the operator refill call center.
60
+ # pin_value Integer Value of the PIN.
61
+ # pin_code Alphanumeric String Code of the PIN.
62
+ # pin_ivr Integer IVR number of the PIN.
63
+ # pin_serial Alphanumeric String Serial number of the PIN.
64
+ # pin_validity String Validity of the PIN
65
+
66
+ # By default, an SMS notification is sent to the recipient after every successful Top-up.
67
+ # The default originating address for the SMS is “8888”.
68
+ # The following is the default SMS which is translated into local languages for most of recipient countries:
69
+ # Congratulations! You've received
70
+ # AMOUNT_CURRENCY from SENDER. Thank you for using
71
+ # TransferTo. FREE_TEXT.
72
+ # • AMOUNT CURRENCY is the amount that has
73
+ # been sent with the currency.
74
+ # • SENDER can be a name or a phone number.
75
+ # • FREE_TEXT is the content of the field named
76
+ # “sms” of the topup method.
77
+
78
+ def topup(msisdn, destination_msisdn, product, method='topup',
79
+ reserved_id=nil, send_sms=true, sms=nil, sender_text=nil, operator_id=nil,
80
+ return_service_fee=1, delivered_amount_info=1, return_timestamp=1, return_version=1,
81
+ return_promo=0)
82
+
83
+ @params = {
84
+ msisdn: msisdn,
85
+ destination_msisdn: destination_msisdn,
86
+ product: product
87
+ }
88
+ self.oid = operator_id
89
+
90
+ @params.merge({
91
+ cid1: "", cid2: "", cid3: "",
92
+ reserved_id: reserved_id,
93
+ sender_sms: (sender_text ? "yes" : "no"),
94
+ send_sms: (send_sms ? "yes" : "no"),
95
+ sms: sms,
96
+ sender_text: sender_text,
97
+ delivered_amount_info: delivered_amount_info,
98
+ return_service_fee: return_service_fee,
99
+ return_timestamp: return_timestamp,
100
+ return_version: return_version,
101
+ return_promo: return_promo
102
+ })
103
+
104
+ run_action method
105
+ #{
106
+ # requesting_msisdn: response[:msisdn],
107
+ # destination_msisdn: response[:destination_msisdn],
108
+ # product_sent: response[:actual_product_sent].to_i,
109
+ # local_amount: response[:local_info_amount],
110
+ # local_value: response[:local_info_value],
111
+ # local_currency_code: response[:local_info_currency],
112
+ # transaction_status: response[:error_txt],
113
+ # operation_result: response[:error_code],
114
+ # operation_info: response[:info_txt],
115
+ # transaction_api_id: response[:transactionid].to_i,
116
+ # country_api_id: response[:countryid].to_i,
117
+ # operator_api_id: response[:operatorid].to_i,
118
+ # product_api_id: response[:product_requested].to_i,
119
+ # originator_currency_code: response[:originating_currency],
120
+ # destination_currency_code: response[:destination_currency],
121
+ # wholesale_price: response[:wholesale_price],
122
+ # retail_price: response[:retail_price],
123
+ # service_fee: response[:service_fee]
124
+ #}
125
+ end
126
+
127
+ # This method is used to retrieve various information of a specific MSISDN
128
+ # (operator, country…) as well as the list of all products configured for
129
+ # your specific account and the destination operator of the MSISDN.
130
+ # Returns relevant information on a MSISDN (operator, country…) as well as the
131
+ # list of products configured for your account and the destination operator
132
+ # linked to that MSISDN. Allows to check if a MSISDN is subjected to a promotion
133
+ #
134
+ # destination_msisdn
135
+ # Destination MSISDN (usually recipient phone number). This is the destination phone number that will
136
+ # be credited with the amount transferred. Format is similar to “msisdn” and restricted to international phone number only.
137
+ # delivered_amount_info
138
+ # Setting this to “1” will return the fields local_info_amount_list,local_info_currency and local_info_value_list in the API response.
139
+ # Blank or “no” if you do not want this returned.
140
+ # return_service_fee
141
+ # Setting this to “1” will return the field service_fee_list in the API response. Blank or “0” if you do not want it returned.
142
+ # operatorid
143
+ # Operator ID of the receiving operator that must be used when treating the request. If
144
+ # set, the platform will be forced to use this operator ID and will not identify the operator of
145
+ # the destination MSISDN based on the numbering plan. It is very useful in case of countries with number
146
+ # portability if you are able to know the destination operator.
147
+ # return_promo
148
+ # Setting this to “1” will return the current promotion related to the transaction’s operator.
149
+ def msisdn_info(destination_msisdn, operator_id=nil,
150
+ delivered_amount_info=1, return_service_fee=1, return_promo=1)
151
+ @params = {
152
+ destination_msisdn: destination_msisdn,
153
+ delivered_amount_info: delivered_amount_info,
154
+ return_service_fee: return_service_fee,
155
+ return_promo: return_promo
156
+ }
157
+ self.oid = operator_id
158
+ run_action :msisdn_info
159
+ end
160
+
161
+ # Get information about a phone number
162
+ def phone_search(number, operator_id=nil)
163
+ information = msisdn_info(number, operator_id).information
164
+ information[:product_list] = information[:product_list].split(",")
165
+ information
166
+ end
167
+
168
+ # This method is used to reserve an ID in the system. This ID can then be
169
+ # used in the “topup” or “simulation” requests.
170
+ # This way, your system knows the ID of the transaction before sending the
171
+ # request to TransferTo (else it will only be displayed in the response).
172
+ def reserve_id
173
+ run_action :reserve_id
174
+ end
175
+
176
+ # This method is used to retrieve the list of transactions performed within
177
+ # the date range by the MSISDN if set. Note that both dates are included
178
+ # during the search.
179
+ #
180
+ # parameters
181
+ # ==========
182
+ # msisdn
183
+ # ------
184
+ # The format must be international with or without the ‘+’ or ‘00’:
185
+ # “6012345678” or “+6012345678” or “006012345678” (Malaysia)
186
+ #
187
+ # destination_msisdn
188
+ # ------------------
189
+ # The format must be international with or without the ‘+’ or ‘00’:
190
+ # “6012345678” or “+6012345678” or “006012345678” (Malaysia)
191
+ #
192
+ # code
193
+ # ----
194
+ # The error_code of the transactions to search for. E.g “0” to search for
195
+ # only all successful transactions. If left empty, all transactions will be
196
+ # returned(Failed and successful).
197
+ #
198
+ # start_date
199
+ # ----------
200
+ # Defines the start date of the search. Format must be YYYY-MM-DD.
201
+ #
202
+ # stop_date
203
+ # ---------
204
+ # Defines the end date of the search (included). Format must be YYYY-MM-DD.
205
+ def trans_list(start, stop, msisdn = nil, destination = nil, code = nil)
206
+ @params[:code] = code unless code
207
+ @params[:msisdn] = msisdn unless msisdn
208
+ @params[:stop_date] = to_yyyymmdd(stop)
209
+ @params[:start_date] = to_yyyymmdd(start)
210
+ @params[:destination_msisdn] = destination unless destination
211
+ run_action :trans_list
212
+ end
213
+
214
+ # Retrieve available information on a specific transaction. Please note that values of “input_value” and
215
+ # “debit_amount_validated” are rounded to 2 digits after the comma but are
216
+ # the same as the values returned in the fields “input_value” and
217
+ # “validated_input_value” of the “topup” method response.
218
+ def trans_info(id)
219
+ @params = { transactionid: id }
220
+ run_action :trans_info
221
+ end
222
+
223
+ # This method is used to retrieve the ID of a transaction previously
224
+ # performed based on the key used in the request at that time.
225
+ def get_id_from_key(key)
226
+ @params = { from_key: key }
227
+ run_action :get_id_from_key
228
+ end
229
+
230
+ # These methods are used to retrieve coverage and pricelist offered to you.
231
+ # parameters
232
+ # ==========
233
+ # info_type
234
+ # ---------
235
+ # i) “countries”: Returns a list of all countries offered to you
236
+ # ii) “country” : Returns a list of operators in the country
237
+ # iii) “operator” : Returns a list of wholesale and retail price for the operator
238
+ #
239
+ # content
240
+ # -------
241
+ # i) Not used if info_type = “countries”
242
+ # ii) countryid of the requested country if info_type = “country”
243
+ # iii) operatorid of the requested operator if info_type = “operator”
244
+
245
+ def price_list(info_type, content=nil)
246
+ @params[:info_type] = info_type
247
+ content && @params[:content] = content
248
+ run_action :pricelist
249
+ end
250
+
251
+ def country_list
252
+ price_list('countries')
253
+ end
254
+
255
+ def operator_list(country_api_id)
256
+ price_list('country', country_api_id)
257
+ end
258
+
259
+ def product_list(operator_api_id)
260
+ price_list('operator', operator_api_id)
261
+ end
262
+
263
+ # Operator Logo URL
264
+ def operator_logo_url(operator_id, size=1)
265
+ "#{T2Airtime::PROTOCOL}://#{T2Airtime::OPLOGO_DN}.#{T2Airtime::DOMAIN}/logo-#{operator_id}-#{size}.png"
266
+ end
267
+
268
+ private
269
+
270
+ def oid=(operator_id)
271
+ @params[:operatorid] = operator_id.to_i if operator_id.is_a?(Integer)
272
+ end
273
+
274
+ def to_time(time)
275
+ case time.class.name
276
+ when "String" then return Time.parse(time)
277
+ when "Integer" then return Time.at(time)
278
+ when "Time" then return time
279
+ else raise ArgumentError
280
+ end
281
+ rescue
282
+ Time.now
283
+ end
284
+
285
+ def to_yyyymmdd(time)
286
+ to_time(time).strftime("%Y-%m-%d")
287
+ end
288
+
289
+ end
290
+ end
@@ -0,0 +1,26 @@
1
+ module T2Airtime
2
+ class Base
3
+
4
+ def initialize(user, password, url)
5
+ @user, @password, @url, @params = user, password, url, {}
6
+ end
7
+
8
+ def self.api
9
+ @api ||= new(
10
+ ENV['T2_SHOP_USER'],
11
+ ENV['T2_AIRTIME_KEY'],
12
+ "https://#{T2Airtime::AIRTIME_DN}.#{T2Airtime::DOMAIN}/#{T2Airtime::ENDPOINT}"
13
+ )
14
+ end
15
+
16
+ def run_action(name, method=:get)
17
+ request = T2Airtime::Request.new(@user, @password, @url, name, @params)
18
+ request.run(method).on_complete do |reply|
19
+ reply = T2Airtime::Reply.new(reply)
20
+ #raise ::T2Airtime::Error.new @reply.error_code, @reply.error_message unless @reply.success?
21
+ return reply.data
22
+ end
23
+ end
24
+
25
+ end
26
+ end
@@ -0,0 +1,89 @@
1
+ module T2Airtime
2
+ # 0 Transaction successful Indicates the Top-up was successfully delivered to the recipient.
3
+ # 101 Destination MSISDN out of range Numbering plan not recognized: the destination/recipient number was not identified as to belonging to any operators covered by TransferTo. Re-check recipient number and/or escalate the case to the TransferTo Support Team for further investigation.
4
+ # 104 MSISDN in blacklist Here MSISDN refers to both sender and recipient phone numbers which are blacklisted due to fraudulent activities.
5
+ # 105 Not enough credit on your account Transaction failed due to insufficient funds in your account's prepaid balance. Please reload balance and try again.
6
+ # 200 Transaction canceled by Customer
7
+ # 202 Transaction canceled by TransferTo
8
+ # 203 Transaction incomplete Transaction failed due to a technical issue. Please contact TransferTo Support Team for further investigation.
9
+ # 204 Destination Account is not prepaid or not valid Transaction refused by the operator because the recipient phone number is not a valid prepaid account.
10
+ # 207 Transaction amount limit exceeded Here limit refers to maximum amount defined for the destination MSISDN. There are some limitations set on the operator's side, not controlled by TransferTo. When one of these limits is reached, error code 207 will be returned. Some examples:
11
+ # • Indosat Indonesia operator's end, the customer must wait at least 5 mins before sending another transfer to the same recipient account.
12
+ # • Indian operators' end, the customer must wait 3 mins before sending another transfer of the same amount to the same recipient account.
13
+ # • Orange Africa, the recipient account is limited to a maximum rechargeable amount of 30 Euros per week and 60 Euros per month.
14
+ # 213 Duplicated transaction Transaction refused because it was submitted too closely after a preceding Top-up attempt.
15
+ # 214 Topup refused Transaction refused by the operator for a reason that was not specified. Common reasons for these types of failures are: Recipient number not valid for recharge. Service outage temporarily faced on the operator. Please try again at a later time and/or contact the TransferTo Support Team if the problem persists.
16
+ # 215 Service to this destination operator is Transaction failed due to an outage and/or connection issue with the operator. Please try again at a later time and/or contact the TransferTo Support Team if the problem persists.
17
+ # temporarily unavailable
18
+ # 216 Destination number not activated Transaction refused by the operator because the recipient number has not been activated.
19
+ # 217 Destination number expired Transaction refused by the operator because the recipient number is no longer an active account.
20
+ # 218 Request timeout Transaction timed-out and failed because of the long processing duration. Please try again at a later time and/or contact the TransferTo Support Team if the problem persists.
21
+ # 219 Key does not exist Request failed because the key provided does not exist (error returned for get_id_from_key method requests only).
22
+ # 221 Fraud suspicion Transaction refused and the recipient number flagged for suspicion of fraud, due to the number of consecutive Top-up requests within a short gap of time. The recipient phone number will be locked out from receiving any Top-up for a certain period of time, after which, the restriction will be automatically released.
23
+ # 222 Number barred from refill This error code is returned when the recipient has been blocked from refill directly by the recipient's operator. It prevents TransferTo system from reloading his account. Recipient must call the operator’s customer service to unblock it.
24
+ # 223 ID not reserved Transaction failed because the transaction ID specified in the request was not previously reserved.
25
+ # 224 Invalid length of destination MSISDN Transaction failed because the recipient number length does not match (shorter or longer) the mobile number format of the country.
26
+ # 230 Recipient reached maximum topup number This error is returned when a recipient reaches the maximum number of Top-up allowable in a certain gap of time.
27
+ # • 01 Day(s) => 10
28
+ # • 07 Day(s) => 15
29
+ # • 30 Day(s) => 40
30
+ # 231 Recipient reached maximum topup amount This error is returned when a recipient reaches the maximum amount (in USD) of Top-up allowable in a certain gap of time.
31
+ # • 01 Day(s) => max 100 USD
32
+ # • 07 Day(s) => max 150 USD
33
+ # • 30 Day(s) => max 200 USD
34
+ # 232 Account reached maximum topup number This error is returned when your account has reached its maximum number of Top-up allowable in a certain gap of time.
35
+ # 233 Account reached maximum topup amount This error is returned when your account has reached its maximum amount (in USD) of Top-up allowable in a certain gap of time.
36
+ # 241 Account reached maximum daily topup amount This error is returned when your account has reached its maximum amount (in USD) of Top-up allowable within a day.
37
+ # 242 Account reached maximum daily topup number This error is returned when your account has reached its maximum number of Top-up allowable within a day.
38
+ # 243 Account reached maximum weekly topup amount This error is returned when your account has reached its maximum amount (in USD) of Top-up allowable within a week.
39
+ # 244 Account reached maximum weekly topup number This error is returned when your account has reached its maximum number of Top-up allowable within a week.
40
+ # 245 Account reached maximum monthly topup amount This error is returned when your account has reached its maximum amount (in USD) of Top-up allowable within a month.
41
+ # 246 Account reached maximum monthly topup number This error is returned when your account has reached its maximum number of Top-up allowable within a month.
42
+ # 251 Sender reached maximum daily topup amount This error is returned when the sender has reached its maximum amount (in USD) of Top-up allowable within a day.
43
+ # 252 Sender reached maximum daily topup number This error is returned when the sender has reached its maximum number of Top-up allowable within a day.
44
+ # 253 Sender reached maximum weekly topup amount This error is returned when the sender has reached its maximum amount (in USD) of Top-up allowable within a week.
45
+ # 254 Sender reached maximum weekly topup number This error is returned when the sender has reached its maximum number of Top-up allowable within a week.
46
+ # 255 Sender reached maximum monthly topup amount This error is returned when the sender has reached its maximum amount (in USD) of Top-up allowable within a month.
47
+ # 256 Sender reached maximum monthly topup number This error is returned when the sender has reached its maximum number of Top-up allowable within a day month.
48
+ # 301 Denomination not available Denomination not available for this destination.
49
+ # 310 Denomination blocked Transaction failed because the Top-up is no longer available on the operator's offer or on the account.
50
+ # 320 Requested amount out of range Transaction failed because the Top-amount request was not within the range of valid amounts.
51
+ # 321 Requested currency not allowed for this account Transaction failed because the currency specified is not valid for the account.
52
+ # 401 Transaction ID not found or was not made No transaction was found with the ID specified (error returned for trans_info method requests only).
53
+ # by your account
54
+ # 777 Insufficient balance in your master account Transaction failed because there are not enough funds in your master account.
55
+ # 888 Insufficient balance in your subaccount Transaction failed because there are not enough funds in your sub-account.
56
+ # 900 Not enough information to process the topup Transaction failed because some of the required fields in your Top-up request are missing/empty.
57
+ # 901 Invalid action Transaction failed because the action specified in <action> field of the request is not valid.
58
+ # 902 Invalid input_currency
59
+ # 903 Invalid output_currency
60
+ # 904 Invalid input_value
61
+ # 905 Invalid start_date
62
+ # 906 Invalid stop_date
63
+ # 907 Invalid transaction ID Transaction ID specified in the <reserved_id> of the Top-up request is not valid.
64
+ # 908 Account not configured for this service Transaction failed because the account is not configured to carry out the requested action.
65
+ # 909 Invalid flag Transaction failed because the request included an invalid field/parameter.
66
+ # 919 All required argument not received Transaction failed because the request is missing a mandatory field/parameter.
67
+ # 921 Wrong MD5 encoding Transaction failed because the MD5 hash was not correct. Typically indicates that the password is incorrect.
68
+ # 922 Originating IP not allowed Transaction failed because the request originated from an IP that is not whitelisted for the account.
69
+ # 923 Key already used or invalid key value Transaction failed because the key value included in the request was not unique and greater than the previous key used.
70
+ # 926 Account not active Please contact your Account Manager.
71
+ # 995 Account not found Please enter and use a correct login.
72
+ # 998 System not available. Please retry later. Transaction failed due to technical issues. Please contact TransferTo Support Team for further investigation.
73
+ # 999 Unknown error To be escalated to the TransferTo Support Team for further investigation.
74
+
75
+
76
+ class Error < StandardError
77
+
78
+ attr_reader :code
79
+
80
+ def initialize(code, message=nil)
81
+ @code = code.to_i
82
+ super(message)
83
+ end
84
+
85
+ end
86
+
87
+ class ConfigurationError < StandardError; end
88
+
89
+ end
@@ -0,0 +1,58 @@
1
+ module T2Airtime
2
+ class Reply
3
+
4
+ def initialize(reply)
5
+ @response = reply.to_hash
6
+ end
7
+
8
+ def data
9
+ hash = {}
10
+ @response[:body].lines.each do |line|
11
+ key, value = line.strip.split "="
12
+ hash[key.to_sym] = (key == "error_code") ? value.to_i : value
13
+ end; hash
14
+ end
15
+
16
+ def status
17
+ @response[:status]
18
+ end
19
+
20
+ def error_code
21
+ data[:error_code]
22
+ end
23
+
24
+ def error_message
25
+ data[:error_txt]
26
+ end
27
+
28
+ def success?
29
+ status == 200 && error_code == 0
30
+ end
31
+
32
+ def url
33
+ @response[:url].to_s
34
+ end
35
+
36
+ def information
37
+ data.reject do |key, value|
38
+ [:authentication_key, :error_code, :error_txt].include?(key)
39
+ end
40
+ end
41
+
42
+ def message
43
+ information[:info_txt]
44
+ end
45
+
46
+ def auth_key
47
+ data[:authentication_key]
48
+ end
49
+
50
+ def headers
51
+ @response[:response_headers]
52
+ end
53
+
54
+ def raw
55
+ @response[:body]
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,73 @@
1
+ module T2Airtime
2
+ class Request
3
+
4
+ def initialize(user, password, url, name, params)
5
+ @user = user
6
+ @pass = password
7
+ @conn = Faraday.new(url: url) do |faraday|
8
+ faraday.request :url_encoded
9
+ faraday.adapter :net_http
10
+ end
11
+ reset
12
+ @name = name
13
+ add_param :action, name
14
+ @params.merge!(params)
15
+ end
16
+
17
+ def reset
18
+ @params = {}
19
+ authenticate
20
+ end
21
+
22
+ def authenticate
23
+ time = Time.now.to_i.to_s
24
+ add_param :key, time
25
+ add_param :md5, md5_hash(@user + @pass + time)
26
+ add_param :login, @user
27
+ end
28
+
29
+ def add_param(key, value)
30
+ @params[key.to_sym] = value
31
+ end
32
+
33
+ def key
34
+ @params[:key]
35
+ end
36
+
37
+ def get?
38
+ @params[:method] == :get
39
+ end
40
+
41
+ def post?
42
+ @params[:method] == :post
43
+ end
44
+
45
+ # More than 99.5% of the transactions are currently processed within a few seconds.
46
+ # However, it may happen in some rare cases that a transaction takes longer to be processed by the receiving
47
+ # operator due to congested system on their end for instance.
48
+ # TransferTo guarantees that transactions not processed within 600 seconds will not be charged, whatever
49
+ # the final status of the transaction (successful or not). In addition, TransferTo is operating a real time system;
50
+ # therefore, the status returned in the Top-up response is final and will not change.
51
+ # To ensure that your system captures successfully the status of all transactions especially the longest
52
+ # ones, it is advised to either set up a high timeout value of 600seconds to be on the safe side (TCP connection
53
+ # could potentially be opened for a long time in this case) or to set up a mechanism to check on
54
+ # the status (to do so, you can call the trans_info method to retrieve the final status of a transaction).
55
+ # In case of timeout, both methods reserve_id and get_id_from_key of the API could be useful to identify
56
+ # the ID of the transaction (we recommend to either send a reserve_id request and to use the ID returned
57
+ # in the response in the subsequent top-up request so that you know in advance the ID of the transaction).
58
+ def run(method = :get)
59
+ add_param :method, method
60
+ @conn.send(method, "/#{T2Airtime::ENDPOINT}", @params) do |req|
61
+ req.options = { timeout: 600, open_timeout: 600 }
62
+ end
63
+ end
64
+
65
+ private
66
+
67
+ def md5_hash(str)
68
+ (Digest::MD5.new << str).to_s
69
+ end
70
+
71
+
72
+ end
73
+ end
@@ -0,0 +1,67 @@
1
+ module T2Airtime
2
+
3
+ class Country
4
+
5
+ def self.all
6
+ serialize_reply(T2Airtime::API.api.country_list)
7
+ end
8
+
9
+ def self.serialize_reply(reply)
10
+ names = reply[:country].split(",")
11
+ ids = reply[:countryid].split(",")
12
+ ids.each_with_index.map{|id, n| {
13
+ name: names[n],
14
+ aid: Integer(id)
15
+ }}
16
+ end
17
+
18
+ end
19
+
20
+ class Operator
21
+
22
+ def self.all
23
+ countries = T2Airtime::Country.all
24
+ countries.flat_map{|country| serialize_reply(T2Airtime::API.api.operator_list(country[:aid]))}
25
+ end
26
+
27
+ def self.serialize_reply(reply)
28
+ names = reply[:operator].split(",")
29
+ ids = reply[:operatorid].split(",")
30
+ ids.each_with_index.map{|id, n| {
31
+ country: reply[:country],
32
+ country_aid: Integer(reply[:countryid]),
33
+ name: names[n],
34
+ aid: Integer(id)
35
+ }}
36
+ end
37
+
38
+ end
39
+
40
+ class Product
41
+
42
+ def self.all
43
+ operators = T2Airtime::Operator.all
44
+ operators.flat_map{|operator| serialize_reply(T2Airtime::API.api.product_list(operator[:aid]))}
45
+ end
46
+
47
+ def self.serialize_reply(reply)
48
+ currency = reply[:destination_currency]
49
+ retail_prices = reply[:retail_price_list].split(",")
50
+ wholesale_prices = reply[:wholesale_price_list].split(",")
51
+ ids = reply[:product_list].split(",")
52
+ ids.each_with_index.map{|id, n| {
53
+ country: reply[:country],
54
+ country_aid: Integer(reply[:countryid]),
55
+ operator: reply[:operator],
56
+ operator_aid: Integer(reply[:operatorid]),
57
+ name: "#{id}#{currency}",
58
+ currency: currency,
59
+ retail_price: retail_prices[n],
60
+ wholesale_price: wholesale_prices[n],
61
+ aid: Integer(id)
62
+ }}
63
+ end
64
+
65
+ end
66
+
67
+ end
@@ -0,0 +1,21 @@
1
+ module T2Airtime
2
+ class Test
3
+
4
+ # A few fake phone numbers in Indonesia have been created and set up with available products of IDR 5000, 10000, 20000, 50000 and 100000:
5
+ # 628123456710: error code 0 for PIN based Top-up (successful transaction).
6
+ # 628123456770: error code 0 for PIN less Top-up (successful transaction).
7
+ # 628123456780: error code 204 (destination number is not a valid prepaid phone number).
8
+ # 628123456781: error code 301 (input value out of range or invalid product).
9
+ # 628123456790: error code 214 (transaction refused by the operator).
10
+ # 628123456798: error code 998 (system not available, please retry later).
11
+ # 628123456799: error code 999 (unknown error, please contact support).
12
+
13
+ def self.numbers(num=0)
14
+ numbers = [ "628123456710", "628123456770", "628123456780",
15
+ "628123456781", "628123456790", "628123456798",
16
+ "628123456799" ]
17
+ num > 0 && num < 8 ? numbers[num-1] : numbers
18
+ end
19
+
20
+ end
21
+ end
@@ -0,0 +1,6 @@
1
+ module T2Airtime
2
+ DOMAIN = "transferto.com"
3
+ AIRTIME_DN = "airtime"
4
+ OPLOGO_DN = "operator-logo"
5
+ ENDPOINT = "cgi-bin/shop/topup"
6
+ end
@@ -0,0 +1,3 @@
1
+ module T2Airtime
2
+ VERSION = "0.1.2"
3
+ end
data/lib/t2_airtime.rb ADDED
@@ -0,0 +1,16 @@
1
+ require 'dotenv'
2
+ Dotenv.load
3
+ require "faraday"
4
+ require "net/http"
5
+
6
+ require "t2_airtime/version"
7
+ require "t2_airtime/url"
8
+ require "t2_airtime/errors"
9
+ require "t2_airtime/request"
10
+ require "t2_airtime/reply"
11
+ require "t2_airtime/base"
12
+ require "t2_airtime/api"
13
+ require "t2_airtime/test"
14
+ require "t2_airtime/rest"
15
+
16
+ module T2Airtime; end
@@ -0,0 +1,31 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "t2_airtime/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "t2_airtime"
8
+ spec.version = T2Airtime::VERSION
9
+ spec.authors = ["matteolc"]
10
+ spec.email = ["matteo@voxbox.io"]
11
+
12
+ spec.summary = "Wrapper methods to interface with [TransferTo](https://www.transfer-to.com/home) Airtime API"
13
+ spec.description = "Wrapper methods to interface with [TransferTo](https://www.transfer-to.com/home) Airtime API"
14
+ spec.homepage = "https://github.com/matteolc/t2_airtime"
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
18
+ f.match(%r{^(test|spec|features)/})
19
+ end
20
+ spec.bindir = "exe"
21
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
22
+ spec.require_paths = ["lib"]
23
+
24
+ spec.add_development_dependency "bundler", "~> 1.15"
25
+ spec.add_development_dependency "rake", "~> 10.0"
26
+ spec.add_development_dependency "rspec", "~> 3.0"
27
+
28
+ spec.add_runtime_dependency 'dotenv-rails', '~> 2.2', '>= 2.2.1'
29
+ spec.add_dependency "faraday", "0.9.1"
30
+
31
+ end
metadata ADDED
@@ -0,0 +1,141 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: t2_airtime
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.2
5
+ platform: ruby
6
+ authors:
7
+ - matteolc
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2017-08-26 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.15'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.15'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: dotenv-rails
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '2.2'
62
+ - - ">="
63
+ - !ruby/object:Gem::Version
64
+ version: 2.2.1
65
+ type: :runtime
66
+ prerelease: false
67
+ version_requirements: !ruby/object:Gem::Requirement
68
+ requirements:
69
+ - - "~>"
70
+ - !ruby/object:Gem::Version
71
+ version: '2.2'
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: 2.2.1
75
+ - !ruby/object:Gem::Dependency
76
+ name: faraday
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - '='
80
+ - !ruby/object:Gem::Version
81
+ version: 0.9.1
82
+ type: :runtime
83
+ prerelease: false
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - '='
87
+ - !ruby/object:Gem::Version
88
+ version: 0.9.1
89
+ description: Wrapper methods to interface with [TransferTo](https://www.transfer-to.com/home)
90
+ Airtime API
91
+ email:
92
+ - matteo@voxbox.io
93
+ executables: []
94
+ extensions: []
95
+ extra_rdoc_files: []
96
+ files:
97
+ - ".gitignore"
98
+ - ".rspec"
99
+ - ".travis.yml"
100
+ - CODE_OF_CONDUCT.md
101
+ - Gemfile
102
+ - LICENSE.txt
103
+ - README.md
104
+ - Rakefile
105
+ - lib/t2_airtime.rb
106
+ - lib/t2_airtime/api.rb
107
+ - lib/t2_airtime/base.rb
108
+ - lib/t2_airtime/errors.rb
109
+ - lib/t2_airtime/reply.rb
110
+ - lib/t2_airtime/request.rb
111
+ - lib/t2_airtime/rest.rb
112
+ - lib/t2_airtime/test.rb
113
+ - lib/t2_airtime/url.rb
114
+ - lib/t2_airtime/version.rb
115
+ - t2_airtime.gemspec
116
+ homepage: https://github.com/matteolc/t2_airtime
117
+ licenses:
118
+ - MIT
119
+ metadata: {}
120
+ post_install_message:
121
+ rdoc_options: []
122
+ require_paths:
123
+ - lib
124
+ required_ruby_version: !ruby/object:Gem::Requirement
125
+ requirements:
126
+ - - ">="
127
+ - !ruby/object:Gem::Version
128
+ version: '0'
129
+ required_rubygems_version: !ruby/object:Gem::Requirement
130
+ requirements:
131
+ - - ">="
132
+ - !ruby/object:Gem::Version
133
+ version: '0'
134
+ requirements: []
135
+ rubyforge_project:
136
+ rubygems_version: 2.5.2
137
+ signing_key:
138
+ specification_version: 4
139
+ summary: Wrapper methods to interface with [TransferTo](https://www.transfer-to.com/home)
140
+ Airtime API
141
+ test_files: []