lib/active_merchant/billing/gateways/wompi.rb
module ActiveMerchant #:nodoc:
module Billing #:nodoc:
class WompiGateway < Gateway
self.test_url = 'https://sync.sandbox.wompi.co/v1'
self.live_url = 'https://sync.production.wompi.co/v1'
self.supported_countries = ['CO']
self.default_currency = 'COP'
self.supported_cardtypes = %i[visa master american_express]
self.homepage_url = 'https://wompi.co/'
self.display_name = 'Wompi'
self.money_format = :cents
def initialize(options = {})
## Sandbox keys have prefix pub_test_ and prv_test_
## Production keys have prefix pub_prod_ and prv_prod_
begin
requires!(options, :prod_private_key, :prod_public_key)
rescue ArgumentError
begin
requires!(options, :test_private_key, :test_public_key)
rescue ArgumentError
raise ArgumentError, 'Gateway requires both test_private_key and test_public_key, or both prod_private_key and prod_public_key'
end
end
super
end
def purchase(money, payment, options = {})
post = {
reference: options[:reference] || generate_reference,
public_key: public_key
}
add_invoice(post, money, options)
add_tip_in_cents(post, options)
add_card(post, payment, options)
commit('sale', post, '/transactions_sync')
end
def authorize(money, payment, options = {})
post = {
public_key: public_key,
type: 'CARD',
financial_operation: 'PREAUTHORIZATION'
}
add_auth_params(post, money, payment, options)
commit('authorize', post, '/payment_sources_sync')
end
def capture(money, authorization, options = {})
post = {
reference: options[:reference] || generate_reference,
public_key: public_key,
payment_source_id: authorization.to_i
}
add_invoice(post, money, options)
commit('capture', post, '/transactions_sync')
end
def refund(money, authorization, options = {})
# post = { amount_in_cents: amount(money).to_i, transaction_id: authorization.to_s }
# commit('refund', post, '/refunds_sync')
# All refunds will instead be voided. This is temporary.
void(authorization, options, money)
end
def void(authorization, options = {}, money = nil)
post = money ? { amount_in_cents: amount(money).to_i } : {}
commit('void', post, "/transactions/#{authorization}/void_sync")
end
def supports_scrubbing?
true
end
def scrub(transcript)
transcript.gsub(/(Bearer )\w+/, '\1[REDACTED]').
gsub(/(\\\"number\\\":\\\")\d+/, '\1[REDACTED]').
gsub(/(\\\"cvc\\\":\\\")\d+/, '\1[REDACTED]').
gsub(/(\\\"phone_number\\\":\\\")\+?\d+/, '\1[REDACTED]').
gsub(/(\\\"email\\\":\\\")\S+\\\",/, '\1[REDACTED]\",').
gsub(/(\\\"legal_id\\\":\\\")\d+/, '\1[REDACTED]')
end
private
def headers
{
'Authorization' => "Bearer #{private_key}",
'Content-Type' => 'application/json'
}
end
def generate_reference
SecureRandom.alphanumeric(12)
end
def private_key
test? ? options[:test_private_key] : options[:prod_private_key]
end
def public_key
test? ? options[:test_public_key] : options[:prod_public_key]
end
def add_invoice(post, money, options)
post[:amount_in_cents] = amount(money).to_i
post[:currency] = (options[:currency] || currency(money))
end
def add_card(post, card, options)
payment_method = {
type: 'CARD'
}
add_basic_card_info(payment_method, card, options)
post[:payment_method] = payment_method
end
def add_auth_params(post, money, card, options)
data = {
amount_in_cents: amount(money).to_i,
currency: (options[:currency] || currency(money))
}
add_basic_card_info(data, card, options)
post[:data] = data
end
def add_basic_card_info(post, card, options)
installments = options[:installments] ? options[:installments].to_i : 1
cvc = card.verification_value || nil
post[:number] = card.number
post[:exp_month] = card.month.to_s.rjust(2, '0')
post[:exp_year] = card.year.to_s[2..3]
post[:installments] = installments
post[:card_holder] = card.name
post[:cvc] = cvc if cvc && !cvc.empty?
end
def add_tip_in_cents(post, options)
post[:tip_in_cents] = options[:tip_in_cents].to_i if options[:tip_in_cents]
end
def parse(body)
JSON.parse(body)
end
def commit(action, parameters, endpoint)
url = (test? ? test_url : live_url) + endpoint
response = parse(ssl_post(url, post_data(action, parameters), headers))
Response.new(
success_from(response),
message_from(response),
response,
authorization: authorization_from(response),
avs_result: nil,
cvv_result: nil,
test: test?,
error_code: error_code_from(response)
)
end
def handle_response(response)
case response.code.to_i
when 200...300, 401, 404, 422
response.body
else
raise ResponseError.new(response)
end
end
def success_from(response)
success_statuses.include? response.dig('data', 'status')
end
def success_statuses
%w(APPROVED AVAILABLE)
end
def message_from(response)
response.dig('data', 'status_message') || response.dig('error', 'reason') || response.dig('error', 'messages').to_json
end
def authorization_from(response)
response.dig('data', 'transaction_id') || response.dig('data', 'id') || response.dig('data', 'transaction', 'id')
end
def post_data(action, parameters = {})
parameters.to_json
end
def error_code_from(response)
response.dig('error', 'type') unless success_from(response)
end
end
end
end