Skip to content

Commit

Permalink
Add CAMS gateway
Browse files Browse the repository at this point in the history
  • Loading branch information
Trevor Grayson authored and ntalbott committed Oct 24, 2015
1 parent 214888a commit c7b9cec
Show file tree
Hide file tree
Showing 8 changed files with 592 additions and 1 deletion.
1 change: 1 addition & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
* AuthorizeNet: Don't send currency to void [duff]
* Add Komoju gateway [k2nr]
* Replace Connection magic numbers with constant references [larrylv]
* Add CAMS gateway [trevorgrayson]

== Version 1.54.0 (October 2, 2015)
* Beanstream: Add Network Tokenization support [girasquid]
Expand Down
4 changes: 4 additions & 0 deletions CONTRIBUTORS
Original file line number Diff line number Diff line change
Expand Up @@ -546,3 +546,7 @@ SecurionPay (October 2015)
Komoju (October 2015)

* Kazunori Kajihiro (k2nr)

CAMS: Central Account Management System (October 2015)

* Trevor Grayson (trevorgrayson)
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ The [ActiveMerchant Wiki](http://github.com/activemerchant/active_merchant/wikis
* [Cashnet](http://www.higherone.com/) - US
* [Cecabank](http://www.ceca.es/es/) - ES
* [Cenpos](https://www.cenpos.com/) - AD, AI, AG, AR, AU, AT, BS, BB, BE, BZ, BM, BR, BN, BG, CA, HR, CY, CZ, DK, DM, EE, FI, FR, DE, GR, GD, GY, HK, HU, IS, IN, IL, IT, JP, LV, LI, LT, LU, MY, MT, MX, MC, MS, NL, PA, PL, PT, KN, LC, MF, VC, SM, SG, SK, SI, ZA, ES, SR, SE, CH, TR, GB, US, UY
* [CAMS: Central Account Management System](https://www.centralams.com/) - US
* [CertoDirect](http://www.certodirect.com/) - BE, BG, CZ, DK, DE, EE, IE, EL, ES, FR, IT, CY, LV, LT, LU, HU, MT, NL, AT, PL, PT, RO, SI, SK, FI, SE, GB
* [Checkout.com](https://www.checkout.com/) - AT, BE, BG, CY, CZ, DE, DK, EE, ES, FI, FR, GR, HR, HU, IE, IS, IT, LI, LT, LU, LV, MT, MU, NL, NO, PL, PT, RO, SE, SI, SK, US
* [Commercegate](http://www.commercegate.com/) - AD, AT, AX, BE, BG, CH, CY, CZ, DE, DK, ES, FI, FR, GB, GG, GI, GR, HR, HU, IE, IM, IS, IT, JE, LI, LT, LU, LV, MC, MT, NL, NO, PL, PT, RO, SE, SI, SK, VA
Expand Down
230 changes: 230 additions & 0 deletions lib/active_merchant/billing/gateways/cams.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,230 @@
module ActiveMerchant #:nodoc:
module Billing #:nodoc:
class CamsGateway < Gateway
self.live_url = "https://secure.centralams.com/gw/api/transact.php"

self.supported_countries = ['US']
self.default_currency = 'USD'
self.supported_cardtypes = [:visa, :master, :american_express, :discover]

self.homepage_url = 'https://www.centralams.com/'
self.display_name = 'CAMS: Central Account Management System'

STANDARD_ERROR_CODE_MAPPING = {
'200' => STANDARD_ERROR_CODE[:card_declined],
'201' => STANDARD_ERROR_CODE[:card_declined],
'202' => STANDARD_ERROR_CODE[:card_declined],
'203' => STANDARD_ERROR_CODE[:card_declined],
'204' => STANDARD_ERROR_CODE[:card_declined],
'220' => STANDARD_ERROR_CODE[:card_declined],
'221' => STANDARD_ERROR_CODE[:card_declined],
'222' => STANDARD_ERROR_CODE[:incorrect_number],
'223' => STANDARD_ERROR_CODE[:expired_card],
'224' => STANDARD_ERROR_CODE[:invalid_expiry_date],
'225' => STANDARD_ERROR_CODE[:invalid_cvc],
'240' => STANDARD_ERROR_CODE[:call_issuer],
'250' => STANDARD_ERROR_CODE[:pickup_card],
'251' => STANDARD_ERROR_CODE[:pickup_card],
'252' => STANDARD_ERROR_CODE[:pickup_card],
'253' => STANDARD_ERROR_CODE[:pickup_card],
'260' => STANDARD_ERROR_CODE[:card_declined],
'261' => STANDARD_ERROR_CODE[:card_declined],
'262' => STANDARD_ERROR_CODE[:card_declined],
'263' => STANDARD_ERROR_CODE[:processing_error],
'264' => STANDARD_ERROR_CODE[:card_declined],
'300' => STANDARD_ERROR_CODE[:card_declined],
'400' => STANDARD_ERROR_CODE[:processing_error],
'410' => STANDARD_ERROR_CODE[:processing_error],
'411' => STANDARD_ERROR_CODE[:processing_error],
'420' => STANDARD_ERROR_CODE[:processing_error],
'421' => STANDARD_ERROR_CODE[:processing_error],
'430' => STANDARD_ERROR_CODE[:processing_error],
'440' => STANDARD_ERROR_CODE[:processing_error],
'441' => STANDARD_ERROR_CODE[:processing_error],
'460' => STANDARD_ERROR_CODE[:invalid_number],
'461' => STANDARD_ERROR_CODE[:processing_error],
'801' => STANDARD_ERROR_CODE[:processing_error],
'811' => STANDARD_ERROR_CODE[:processing_error],
'812' => STANDARD_ERROR_CODE[:processing_error],
'813' => STANDARD_ERROR_CODE[:processing_error],
'814' => STANDARD_ERROR_CODE[:processing_error],
'815' => STANDARD_ERROR_CODE[:processing_error],
'823' => STANDARD_ERROR_CODE[:processing_error],
'824' => STANDARD_ERROR_CODE[:processing_error],
'881' => STANDARD_ERROR_CODE[:processing_error],
'882' => STANDARD_ERROR_CODE[:processing_error],
'883' => STANDARD_ERROR_CODE[:processing_error],
'884' => STANDARD_ERROR_CODE[:card_declined],
'885' => STANDARD_ERROR_CODE[:card_declined],
'886' => STANDARD_ERROR_CODE[:card_declined],
'887' => STANDARD_ERROR_CODE[:processing_error],
'888' => STANDARD_ERROR_CODE[:processing_error],
'889' => STANDARD_ERROR_CODE[:processing_error],
'890' => STANDARD_ERROR_CODE[:processing_error],
'891' => STANDARD_ERROR_CODE[:incorrect_cvc],
'892' => STANDARD_ERROR_CODE[:incorrect_cvc],
'893' => STANDARD_ERROR_CODE[:processing_error],
'894' => STANDARD_ERROR_CODE[:processing_error]
}

def initialize(options={})
requires!(options, :username, :password)
super
end

def purchase(money, payment, options={})
post = {}
add_invoice(post, money, options)

if payment.respond_to?(:number)
add_payment(post, payment)
add_address(post, payment, options)
elsif payment.kind_of?(String)
post[:transactionid] = split_authorization(payment)[0]
end

commit("sale", post)
end

def authorize(money, payment, options={})
post = {}
add_invoice(post, money, options)
add_payment(post, payment)
add_address(post, payment, options)

commit('auth', post)
end

def capture(money, authorization, options={})
post = {}
add_reference(post, authorization)
add_invoice(post, money, options)

commit('capture', post)
end

def refund(money, authorization, options={})
post = {}
add_reference(post, authorization)
add_invoice(post, money, options)
commit('refund', post)
end

def void(authorization, options={})
post = {}
add_reference(post, authorization)
commit('void', post)
end

def verify(credit_card, options={})
post = {}
add_invoice(post, 0, options)
add_payment(post, credit_card)
add_address(post, credit_card, options)
commit('verify', post)
end

def supports_scrubbing?
true
end

def scrub(transcript)
%w(ccnumber cvv password).each do |field|
transcript = transcript.gsub(%r((#{field}=)[^&]+), '\1[FILTERED]\2')
end

transcript
end

private

def add_address(post, creditcard, options={})
post[:firstname] = creditcard.first_name
post[:lastname ] = creditcard.last_name

return unless options[:billing_address]

address = options[:billing_address]
post[:address1 ] = address[:address1]
post[:address2 ] = address[:address2]
post[:city ] = address[:city]
post[:state ] = address[:state]
post[:zip ] = address[:zip]
post[:country ] = address[:country]
post[:phone ] = address[:phone]
end

def add_reference(post, authorization)
transaction_id, authcode = split_authorization(authorization)
post["transactionid"] = transaction_id
post["authcode"] = authcode
end

def add_invoice(post, money, options)
post[:amount] = amount(money)
post[:currency] = (options[:currency] || default_currency)
end

def add_payment(post, payment)
post[:ccnumber] = payment.number
post[:ccexp ] = "#{payment.month.to_s.rjust(2,"0")}#{payment.year.to_s[-2..-1]}"
post[:cvv ] = payment.verification_value
end

def parse(body)
kvs = body.split("&")

kvs.inject({}) { |h, kv|
k,v = kv.split("=")
h[k] = v
h
}
end

def commit(action, parameters)
url = live_url
parameters[:type] = action

response_body = ssl_post(url, post_data(parameters))
response = parse(response_body)

Response.new(
success_from(response),
message_from(response),
response,
authorization: authorization_from(response),
test: test?,
error_code: error_code_from(response)
)
end

def success_from(response)
response["response_code"] == "100"
end

def message_from(response)
response["responsetext"]
end

def authorization_from(response)
[response["transactionid"], response["authcode"]].join("#")
end

def split_authorization(authorization)
transaction_id, authcode = authorization.split("#")
[transaction_id, authcode]
end

def post_data(parameters = {})
parameters[:password] = @options[:password]
parameters[:username] = @options[:username]

parameters.collect{|k,v| "#{k}=#{v}" }.join("&")
end

def error_code_from(response)
STANDARD_ERROR_CODE_MAPPING[response["response_code"]]
end
end
end
end
5 changes: 5 additions & 0 deletions test/fixtures.yml
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,11 @@ bridge_pay:
user_name: Spre3676
password: H3392nc5

# Working credentials, no need to replace
cams:
username: testintegrationc
password: password9

#Username/Password given in sign up email. Not MMS credentials
card_save:
login: merchant_id
Expand Down
Loading

0 comments on commit c7b9cec

Please sign in to comment.