lib/t2_airtime/serializer.rb
module T2Airtime
class Topup
def self.serialize(data, ts = Time.zone.now.to_s)
{
type: 'topup',
balance: data[:balance],
balanceDisplay: "#{Money.new(Integer(data[:balance]) * 100, Account.currency).format}",
msisdn: data[:destination_msisdn],
destinationMsisdn: data[:destination_msisdn],
transactionId: data[:transactionid],
transactionAuthenticationKey: data[:authentication_key],
transactionErrorCode: Integer(data[:error_code]),
transactionErrorTxt: data[:error_txt],
referenceOperator: data[:reference_operator],
actualProductSent: data[:actual_product_sent],
sms: data[:sms],
smsSent: data[:sms_sent],
smsText: data[:sender_text],
cid1: data[:cid1],
cid2: data[:cid2],
cid3: data[:cid3],
currency: data[:originating_currency],
localCurrency: data[:destination_currency],
countryId: Integer(data[:countryid]),
countryName: data[:country],
operatorId: Integer(data[:operatorid]),
operatorName: data[:operator],
operatorLogo: T2Airtime::Util.operator_logo_url(data[:operatorid]),
productName: "#{Money.new(Integer(data[:product_requested]) * 100, data[:destination_currency]).format}",
productLocalCurrency: data[:destination_currency],
productLocalCurrencySymbol: Money::Currency.new(data[:destination_currency]).symbol,
productCurrency: Account.currency,
productCurrencySymbol: Money::Currency.new(Account.currency).symbol,
productLocalPrice: Float(data[:product_requested]),
productRetailPrice: Float(data[:retail_price]),
productWholesalePrice: Float(data[:wholesale_price]),
executedAt: T2Airtime::Util.format_time(ts)
}
end
end
class Msisdn
def self.info(msisdn)
Rails.cache.fetch("msisdn/#{msisdn}", expires_in: 24.hours) do # cache the result for 1 day
T2Airtime::API.api.msisdn_info(msisdn)
end
end
def self.serialize(data, ts = Time.zone.now.to_s)
{
type: 'msisdn',
msisdn: data[:destination_msisdn],
country: data[:country],
countryId: data[:countryid],
operator: data[:operator],
operatorId: data[:operatorid],
fetchedAt: T2Airtime::Util.format_time(ts)
}
end
end
class Account
def self.get
Rails.cache.fetch('accounts', expires_in: 1.hour) do
T2Airtime::API.api.account_info
end
end
def self.currency
account = serialize(get.data)
Rails.cache.fetch('accounts/currency', expires_in: 24.hours) do # cache the result for 1 day
account[:attributes][:currency]
end
end
def self.info
get.success? ? serialize(get.data, get.headers[:date]) : []
end
def self.serialize(data, ts = Time.zone.now.to_s)
{
type: 'accounts',
id: T2Airtime::API.api.user,
attributes: {
type: data[:type],
name: data[:name],
currency: data[:currency],
balance: Float(data[:balance]),
wallet: Float(data[:wallet]),
fetchedAt: T2Airtime::Util.format_time(ts)
}
}
end
end
class Country
def self.all
Rails.cache.fetch('countries', expires_in: 1.hour) do
T2Airtime::API.api.country_list
end
end
def self.take(qty = 5)
countries = all
countries.success? ? serialize(countries.data, countries.headers[:date], qty) : []
end
def self.serialize(data, ts = Time.zone.now.to_s, qty = 'all')
return [] if data[:countryid].nil?
names = data[:country].split(',')
ids = data[:countryid].split(',')
Rails.cache.fetch('countries/serializer', expires_in: 1.hour) do
ids.take(qty==='all' ? ids.count : qty).each_with_index.map do |id, n|
{
type: 'countries',
id: Integer(id),
attributes: {
name: names[n],
alpha3: alpha3(names[n]),
callingCode: calling_code(alpha3(names[n])),
fetchedAt: T2Airtime::Util.format_time(ts)
}
}
end
end
end
def self.normalize(name)
name.starts_with?('St') ? name.gsub('St', 'Saint') : name
end
def self.alpha3(name)
alpha3 = ISO3166::Country.find_country_by_name(name).try(:alpha3)
unless alpha3
alpha3 = case name
when 'Saint Vincent Grenadines'
'VCT'
when 'Kosovo'
'UNK'
when 'Netherlands Antilles'
'ANT'
when 'Serbia and Montenegro'
'SCG'
end
register_alpha3(alpha3, name) if %w[VCT UNK ANT SCG].include?(alpha3)
end
alpha3 || 'XXX'
end
def self.register_alpha3(alpha3, name)
ISO3166::Data.register(
alpha2: 'XX',
alpha3: alpha3,
name: name
)
end
def self.calling_code(alpha3)
country_code = case alpha3
when 'PCN'
'64'
when 'ATF'
'262'
end
country_code || ISO3166::Country.find_country_by_alpha3(alpha3).try(:country_code)
end
end
class Operator
def self.all(country_id)
Rails.cache.fetch("operators/#{country_id}", expires_in: 1.hour) do
T2Airtime::API.api.operator_list(country_id)
end
end
def self.take(qty = 5, country_qty = 1)
countries = T2Airtime::Country.take(country_qty).shuffle
unless countries.empty?
countries.flat_map do |country| (
operators = all(country[:id])
operators.success? ? serialize(operators.data, operators.headers[:date], qty) : []
)
end
end
end
def self.serialize(data, ts = Time.zone.now.to_s, qty = 'all')
return [] if data[:operator].nil?
names = data[:operator].split(',')
ids = data[:operatorid].split(',')
Rails.cache.fetch("operators/#{data[:countryid]}/serializer", expires_in: 1.hour) do
ids.take(qty==='all' ? ids.count : qty).each_with_index.map do |id, n|
{
type: 'operators',
id: Integer(id),
attributes: {
name: names[n],
logo: T2Airtime::Util.operator_logo_url(id),
countryId: Integer(data[:countryid]),
countryName: data[:country],
countryAlpha3: T2Airtime::Country.alpha3(data[:country]),
fetchedAt: T2Airtime::Util.format_time(ts)
},
relationships: {
country: {
data: {
type: 'countries',
id: Integer(data[:countryid])
}
}
}
}
end
end
end
end
class Product
def self.all(operator_id)
Rails.cache.fetch("products/#{operator_id}", expires_in: 1.hour) do
T2Airtime::API.api.product_list(operator_id)
end
end
def self.take(qty = 5, operator_qty = 1, country_qty = 1)
operators = T2Airtime::Operator.take(operator_qty, country_qty).shuffle
unless operators.empty?
operators.flat_map do |operator| (
products = all(operator[:id])
products.success? ? serialize(products.data, products.headers[:date], qty) : []
)
end
end
end
def self.serialize(data, ts = Time.zone.now.to_s, qty = 'all')
return [] if data[:product_list].nil?
ids = data[:product_list].split(',')
retail_prices = data[:retail_price_list].split(',')
wholesale_prices = data[:wholesale_price_list].split(',')
Rails.cache.fetch("products/#{data[:operatorid]}/serializer", expires_in: 1.hour) do
ids.take(qty==='all' ? ids.count : qty).each_with_index.map do |id, n|
{
type: 'products',
id: Integer(id),
attributes: {
name: "#{Money.new(Integer(id) * 100, data[:destination_currency]).format}",
localCurrency: data[:destination_currency],
localCurrencySymbol: Money::Currency.new(data[:destination_currency]).symbol,
currency: Account.currency,
currencySymbol: Money::Currency.new(Account.currency).symbol,
localPrice: Float(id),
retailPrice: Float(retail_prices[n]),
wholesalePrice: Float(wholesale_prices[n]),
countryId: Integer(data[:countryid]),
countryName: data[:country],
countryAlpha3: T2Airtime::Country.alpha3(data[:country]),
operatorId: Integer(data[:operatorid]),
operatorName: data[:operator],
operatorLogo: T2Airtime::Util.operator_logo_url(data[:operatorid]),
fetchedAt: T2Airtime::Util.format_time(ts)
},
relationships: {
country: {
data: {
type: 'countries',
id: Integer(data[:countryid])
}
},
operator: {
data: {
type: 'operators',
id: Integer(data[:operatorid])
}
}
}
}
end
end
end
end
class Transaction
def self.take(start = (Time.now - 24.hours), stop = Time.now, msisdn = nil, destination = nil, code = nil, qty = 5)
reply = T2Airtime::API.api.transaction_list(start, stop, msisdn, destination, code)
reply.success? ? serialize(reply.data, qty) : []
end
def self.serialize(data, qty = 'all')
return [] if data[:transaction_list].nil?
ids = data[:transaction_list].split(',')
ids.take(qty==='all' ? ids.count : qty).each.map { |id| show(id) }
end
def self.get(id)
Rails.cache.fetch("transactions/#{id}", expires_in: 365.days) do # once we've got it, no need to refetch
T2Airtime::API.api.transaction_info(id)
end
end
def self.show(id)
transaction = get(id)
transaction.success? ? serialize_one(transaction.data, transaction.headers[:date]) : {}
end
def self.serialize_one(data, ts = Time.zone.now.to_s)
Rails.cache.fetch("transactions/#{data[:transactionid]}/serializer", expires_in: 365.days) do
{
type: 'transactions',
id: Integer(data[:transactionid]),
attributes: {
msisdn: data[:msisdn],
destinationMsisdn: data[:destination_msisdn],
transactionAuthenticationKey: data[:transaction_authentication_key],
transactionErrorCode: Integer(data[:transaction_error_code]),
transactionErrorTxt: data[:transaction_error_txt],
referenceOperator: data[:reference_operator],
actualProductSent: data[:actual_product_sent],
sms: data[:sms],
cid1: data[:cid1],
cid2: data[:cid2],
cid3: data[:cid3],
date: data[:date],
currency: data[:originating_currency] && data[:originating_currency] || 'XXX',
localCurrency: data[:destination_currency] && data[:destination_currency] || 'XXX',
pinBased: data[:pin_based],
localInfoAmount: data[:local_info_amount],
localInfoCurrency: data[:local_info_currency],
localInfoValue: data[:local_info_value],
errorCode: data[:error_code],
errorTxt: data[:error_txt],
countryId: data[:countryid] && Integer(data[:countryid]) || nil,
countryName: data[:country],
countryAlpha3: data[:country] && T2Airtime::Country.alpha3(data[:country]) || 'XXX',
operatorId: data[:operatorid] && Integer(data[:operatorid]) || nil,
operatorName: data[:operator],
operatorLogo: data[:operatorid] && T2Airtime::Util.operator_logo_url(data[:operatorid]) || nil,
productName: data[:destination_currency] && "#{Money.new(Integer(data[:product_requested]) * 100, data[:destination_currency]).format}" || nil,
productLocalCurrency: data[:destination_currency],
productLocalCurrencySymbol: data[:destination_currency] && Money::Currency.new(data[:destination_currency]).symbol || 'XXX',
productCurrency: Account.currency,
productCurrencySymbol: Money::Currency.new(Account.currency).symbol,
productLocalPrice: data[:product_requested] && Float(data[:product_requested]) || 0,
productRetailPrice: data[:retail_price] && Float(data[:retail_price]) || 0,
productWholesalePrice: data[:wholesale_price] && Float(data[:wholesale_price]) || 0,
fetchedAt: T2Airtime::Util.format_time(ts)
},
relationships: {
country: {
data: {
type: 'countries',
id: data[:countryid] && Integer(data[:countryid]) || nil
}
},
operator: {
data: {
type: 'operators',
id: data[:operatorid] && Integer(data[:operatorid]) || nil
}
},
product: {
data: {
type: 'products',
id: data[:product_requested] && Integer(data[:product_requested]) || nil
}
}
}
}
end
end
end
end