lib/active_merchant/billing/gateways/quickpay/quickpay_v10.rb in activemerchant-1.52.0 vs lib/active_merchant/billing/gateways/quickpay/quickpay_v10.rb in activemerchant-1.53.0
- old
+ new
@@ -4,220 +4,269 @@
module ActiveMerchant
module Billing
class QuickpayV10Gateway < Gateway
include QuickpayCommon
API_VERSION = 10
-
+
self.live_url = self.test_url = 'https://api.quickpay.net'
-
+
def initialize(options = {})
requires!(options, :api_key)
super
end
-
+
def purchase(money, credit_card, options = {})
MultiResponse.run(true) do |r|
r.process { create_payment(money, options) }
r.process {
post = authorization_params(money, credit_card, options)
- add_autocapture(post, true)
+ add_autocapture(post, false)
commit(synchronized_path("/payments/#{r.authorization}/authorize"), post)
}
+ r.process {
+ post = capture_params(money, credit_card, options)
+ commit(synchronized_path("/payments/#{r.authorization}/capture"), post)
+ }
end
end
-
+
def authorize(money, credit_card, options = {})
MultiResponse.run(true) do |r|
r.process { create_payment(money, options) }
r.process {
post = authorization_params(money, credit_card, options)
commit(synchronized_path("/payments/#{r.authorization}/authorize"), post)
}
end
end
-
- def void(identification)
+
+ def void(identification, _options = {})
commit(synchronized_path "/payments/#{identification}/cancel")
end
def credit(money, identification, options = {})
ActiveMerchant.deprecated CREDIT_DEPRECATION_MESSAGE
refund(money, identification, options)
end
def capture(money, identification, options = {})
- post = {}
- add_amount(post, money, options)
- add_additional_params(:capture, post, options)
+ post = capture_params(money, identification, options)
commit(synchronized_path("/payments/#{identification}/capture"), post)
end
def refund(money, identification, options = {})
post = {}
add_amount(post, money, options)
add_additional_params(:refund, post, options)
commit(synchronized_path("/payments/#{identification}/refund"), post)
end
-
+
+ def verify(credit_card, options={})
+ MultiResponse.run(:use_first_response) do |r|
+ r.process { authorize(100, credit_card, options) }
+ r.process(:ignore_result) { void(r.authorization, options) }
+ end
+ end
+
def store(credit_card, options = {})
- MultiResponse.run(true) do |r|
+ MultiResponse.run(true) do |r|
r.process { create_subscription(options) }
- r.process {
- authorize_subscription(r.authorization, credit_card, options)
+ r.process {
+ authorize_subscription(r.authorization, credit_card, options)
}
end
end
-
+
def unstore(identification)
commit(synchronized_path "/subscriptions/#{identification}/cancel")
end
-
+
+ def supports_scrubbing?
+ true
+ end
+
+ def scrub(transcript)
+ transcript.
+ gsub(%r((Authorization: Basic )\w+), '\1[FILTERED]').
+ gsub(%r(("card\\?":{\\?"number\\?":\\?")\d+), '\1[FILTERED]').
+ gsub(%r(("cvd\\?":\\?")\d+), '\1[FILTERED]')
+ end
+
private
-
+
def authorization_params(money, credit_card, options = {})
post = {}
-
+
add_amount(post, money, options)
add_credit_card(post, credit_card)
add_additional_params(:authorize, post, options)
-
+
post
end
-
+
+ def capture_params(money, credit_card, options = {})
+ post = {}
+
+ add_amount(post, money, options)
+ add_additional_params(:capture, post, options)
+
+ post
+ end
+
def create_subscription(options = {})
- post = {}
-
+ requires!(options, :currency)
+ post = {}
+
+ add_currency(post, nil, options)
add_subscription_invoice(post, options)
commit('/subscriptions', post)
end
-
+
def authorize_subscription(identification, credit_card, options = {})
+ requires!(options, :amount)
post = {}
-
+
+ add_amount(post, nil, options)
add_credit_card(post, credit_card, options)
add_additional_params(:authorize_subscription, post, options)
commit(synchronized_path("/subscriptions/#{identification}/authorize"), post)
end
-
+
def create_payment(money, options = {})
post = {}
add_currency(post, money, options)
add_invoice(post, options)
commit('/payments', post)
end
def commit(action, params = {})
- success = false
+ success = false
begin
response = parse(ssl_post(self.live_url + action, params.to_json, headers))
success = successful?(response)
rescue ResponseError => e
response = response_error(e.response.body)
rescue JSON::ParserError
response = json_error(response)
end
-
+
Response.new(success, message_from(success, response), response,
:test => test?,
:authorization => response['id']
)
end
-
+
def add_subscription_invoice(post, options = {})
- requires!(options, :order_id, :description)
+ requires!(options, :order_id, :description)
post[:order_id] = options[:order_id]
post[:description] = options[:description]
end
-
+
def add_currency(post, money, options)
post[:currency] = options[:currency] || currency(money)
end
-
+
def add_amount(post, money, options)
- post[:amount] = amount(money)
+ post[:amount] = options[:amount] || amount(money)
end
-
+
def add_autocapture(post, value)
- post[:auto_capture] = value
+ post[:auto_capture] = value
end
-
+
def add_order_id(post, options)
- requires!(options, :order_id)
- post[:order_id] = options[:order_id]
+ requires!(options, :order_id)
+ post[:order_id] = format_order_id(options[:order_id])
end
-
+
def add_invoice(post, options)
- add_order_id(post, options)
-
+ add_order_id(post, options)
+
if options[:billing_address]
post[:invoice_address] = map_address(options[:billing_address])
end
-
+
if options[:shipping_address]
post[:shipping_address] = map_address(options[:shipping_address])
end
-
+
[:metadata, :brading_id, :variables].each do |field|
post[field] = options[field] if options[field]
end
end
-
+
def add_additional_params(action, post, options = {})
MD5_CHECK_FIELDS[API_VERSION][action].each do |key|
key = key.to_sym
post[key] = options[key] if options[key]
end
end
-
+
def add_credit_card(post, credit_card, options = {})
post[:card] ||= {}
post[:card][:number] = credit_card.number
post[:card][:cvd] = credit_card.verification_value
post[:card][:expiration] = expdate(credit_card)
post[:card][:issued_to] = credit_card.name
end
-
+
def parse(body)
JSON.parse(body)
end
-
+
def successful?(response)
has_error = response['errors']
- invalid_code = (response.key?('qp_status_code') and response['qp_status_code'] != "20000")
-
+ invalid_code = invalid_operation_code?(response)
+
!(has_error || invalid_code)
end
-
+
def message_from(success, response)
- success ? 'OK' : (response['message'] || response['qp_status_msg'])
+ success ? 'OK' : (response['message'] || invalid_operation_message(response) || "Unknown error - please contact QuickPay")
end
-
+
+ def invalid_operation_code?(response)
+ if response['operations']
+ operation = response['operations'].last
+ operation && operation['qp_status_code'] != "20000"
+ end
+ end
+
+ def invalid_operation_message(response)
+ response['operations'] && response['operations'].last['qp_status_msg']
+ end
+
def map_address(address)
return {} if address.nil?
requires!(address, :name, :address1, :city, :zip, :country)
+ country = Country.find(address[:country])
mapped = {
:name => address[:name],
:street => address[:address1],
:city => address[:city],
:region => address[:address2],
:zip_code => address[:zip],
- :country_code => address[:country]
+ :country_code => country.code(:alpha3).value
}
mapped
end
+ def format_order_id(order_id)
+ order_id.to_s.gsub(/#/, '')
+ end
+
def headers
auth = Base64.strict_encode64(":#{@options[:api_key]}")
{
"Authorization" => "Basic " + auth,
"User-Agent" => "Quickpay-v#{API_VERSION} ActiveMerchantBindings/#{ActiveMerchant::VERSION}",
"Accept" => "application/json",
"Accept-Version" => "v#{API_VERSION}",
"Content-Type" => "application/json"
}
end
-
+
def response_error(raw_response)
begin
parse(raw_response)
rescue JSON::ParserError
json_error(raw_response)
@@ -227,14 +276,14 @@
def json_error(raw_response)
msg = 'Invalid response received from the Quickpay API.'
msg += " (The raw response returned by the API was #{raw_response.inspect})"
{ "message" => msg }
end
-
+
def synchronized_path(path)
"#{path}?synchronized"
end
-
+
end
-
+
end
-end
\ No newline at end of file
+end