aktivemerchant 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG +1596 -0
- data/CONTRIBUTORS +511 -0
- data/MIT-LICENSE +20 -0
- data/README.md +18 -0
- data/lib/active_merchant.rb +108 -0
- data/lib/active_merchant/billing.rb +13 -0
- data/lib/active_merchant/billing/apple_pay_payment_token.rb +22 -0
- data/lib/active_merchant/billing/avs_result.rb +98 -0
- data/lib/active_merchant/billing/base.rb +72 -0
- data/lib/active_merchant/billing/check.rb +76 -0
- data/lib/active_merchant/billing/compatibility.rb +120 -0
- data/lib/active_merchant/billing/credit_card.rb +352 -0
- data/lib/active_merchant/billing/credit_card_formatting.rb +24 -0
- data/lib/active_merchant/billing/credit_card_methods.rb +160 -0
- data/lib/active_merchant/billing/cvv_result.rb +38 -0
- data/lib/active_merchant/billing/gateway.rb +268 -0
- data/lib/active_merchant/billing/gateways.rb +17 -0
- data/lib/active_merchant/billing/gateways/adyen.rb +209 -0
- data/lib/active_merchant/billing/gateways/alfabank.rb +117 -0
- data/lib/active_merchant/billing/gateways/app55.rb +176 -0
- data/lib/active_merchant/billing/gateways/authorize_net.rb +419 -0
- data/lib/active_merchant/billing/gateways/authorize_net_arb.rb +417 -0
- data/lib/active_merchant/billing/gateways/authorize_net_cim.rb +976 -0
- data/lib/active_merchant/billing/gateways/balanced.rb +256 -0
- data/lib/active_merchant/billing/gateways/bank_frick.rb +225 -0
- data/lib/active_merchant/billing/gateways/banwire.rb +105 -0
- data/lib/active_merchant/billing/gateways/barclays_epdq.rb +314 -0
- data/lib/active_merchant/billing/gateways/barclays_epdq_extra_plus.rb +15 -0
- data/lib/active_merchant/billing/gateways/be2bill.rb +131 -0
- data/lib/active_merchant/billing/gateways/beanstream.rb +188 -0
- data/lib/active_merchant/billing/gateways/beanstream/beanstream_core.rb +393 -0
- data/lib/active_merchant/billing/gateways/beanstream_interac.rb +54 -0
- data/lib/active_merchant/billing/gateways/blue_pay.rb +506 -0
- data/lib/active_merchant/billing/gateways/bogus.rb +140 -0
- data/lib/active_merchant/billing/gateways/borgun.rb +210 -0
- data/lib/active_merchant/billing/gateways/braintree.rb +19 -0
- data/lib/active_merchant/billing/gateways/braintree/braintree_common.rb +9 -0
- data/lib/active_merchant/billing/gateways/braintree_blue.rb +515 -0
- data/lib/active_merchant/billing/gateways/braintree_orange.rb +20 -0
- data/lib/active_merchant/billing/gateways/bridge_pay.rb +189 -0
- data/lib/active_merchant/billing/gateways/card_save.rb +23 -0
- data/lib/active_merchant/billing/gateways/card_stream.rb +220 -0
- data/lib/active_merchant/billing/gateways/cashnet.rb +191 -0
- data/lib/active_merchant/billing/gateways/cc5.rb +201 -0
- data/lib/active_merchant/billing/gateways/cecabank.rb +229 -0
- data/lib/active_merchant/billing/gateways/certo_direct.rb +278 -0
- data/lib/active_merchant/billing/gateways/checkout.rb +213 -0
- data/lib/active_merchant/billing/gateways/commercegate.rb +143 -0
- data/lib/active_merchant/billing/gateways/conekta.rb +209 -0
- data/lib/active_merchant/billing/gateways/cyber_source.rb +709 -0
- data/lib/active_merchant/billing/gateways/data_cash.rb +600 -0
- data/lib/active_merchant/billing/gateways/efsnet.rb +219 -0
- data/lib/active_merchant/billing/gateways/elavon.rb +348 -0
- data/lib/active_merchant/billing/gateways/epay.rb +275 -0
- data/lib/active_merchant/billing/gateways/evo_ca.rb +308 -0
- data/lib/active_merchant/billing/gateways/eway.rb +214 -0
- data/lib/active_merchant/billing/gateways/eway_managed.rb +291 -0
- data/lib/active_merchant/billing/gateways/eway_rapid.rb +524 -0
- data/lib/active_merchant/billing/gateways/exact.rb +218 -0
- data/lib/active_merchant/billing/gateways/fat_zebra.rb +173 -0
- data/lib/active_merchant/billing/gateways/federated_canada.rb +160 -0
- data/lib/active_merchant/billing/gateways/finansbank.rb +23 -0
- data/lib/active_merchant/billing/gateways/first_giving.rb +143 -0
- data/lib/active_merchant/billing/gateways/first_pay.rb +160 -0
- data/lib/active_merchant/billing/gateways/firstdata_e4.rb +355 -0
- data/lib/active_merchant/billing/gateways/garanti.rb +257 -0
- data/lib/active_merchant/billing/gateways/global_transport.rb +183 -0
- data/lib/active_merchant/billing/gateways/hdfc.rb +207 -0
- data/lib/active_merchant/billing/gateways/hps.rb +288 -0
- data/lib/active_merchant/billing/gateways/iats_payments.rb +251 -0
- data/lib/active_merchant/billing/gateways/ideal/ideal_base.rb +246 -0
- data/lib/active_merchant/billing/gateways/ideal/ideal_rabobank.pem +13 -0
- data/lib/active_merchant/billing/gateways/ideal/ideal_response.rb +29 -0
- data/lib/active_merchant/billing/gateways/ideal_rabobank.rb +66 -0
- data/lib/active_merchant/billing/gateways/inspire.rb +213 -0
- data/lib/active_merchant/billing/gateways/instapay.rb +163 -0
- data/lib/active_merchant/billing/gateways/iridium.rb +457 -0
- data/lib/active_merchant/billing/gateways/itransact.rb +448 -0
- data/lib/active_merchant/billing/gateways/jetpay.rb +275 -0
- data/lib/active_merchant/billing/gateways/linkpoint.rb +438 -0
- data/lib/active_merchant/billing/gateways/litle.rb +346 -0
- data/lib/active_merchant/billing/gateways/maxipago.rb +197 -0
- data/lib/active_merchant/billing/gateways/merchant_e_solutions.rb +170 -0
- data/lib/active_merchant/billing/gateways/merchant_one.rb +114 -0
- data/lib/active_merchant/billing/gateways/merchant_ware.rb +319 -0
- data/lib/active_merchant/billing/gateways/merchant_ware_version_four.rb +268 -0
- data/lib/active_merchant/billing/gateways/merchant_warrior.rb +195 -0
- data/lib/active_merchant/billing/gateways/mercury.rb +333 -0
- data/lib/active_merchant/billing/gateways/metrics_global.rb +303 -0
- data/lib/active_merchant/billing/gateways/migs.rb +265 -0
- data/lib/active_merchant/billing/gateways/migs/migs_codes.rb +100 -0
- data/lib/active_merchant/billing/gateways/modern_payments.rb +37 -0
- data/lib/active_merchant/billing/gateways/modern_payments_cim.rb +219 -0
- data/lib/active_merchant/billing/gateways/moneris.rb +309 -0
- data/lib/active_merchant/billing/gateways/moneris_us.rb +291 -0
- data/lib/active_merchant/billing/gateways/money_movers.rb +152 -0
- data/lib/active_merchant/billing/gateways/nab_transact.rb +280 -0
- data/lib/active_merchant/billing/gateways/net_registry.rb +198 -0
- data/lib/active_merchant/billing/gateways/netaxept.rb +181 -0
- data/lib/active_merchant/billing/gateways/netbilling.rb +190 -0
- data/lib/active_merchant/billing/gateways/netpay.rb +223 -0
- data/lib/active_merchant/billing/gateways/network_merchants.rb +242 -0
- data/lib/active_merchant/billing/gateways/nmi.rb +256 -0
- data/lib/active_merchant/billing/gateways/ogone.rb +435 -0
- data/lib/active_merchant/billing/gateways/openpay.rb +194 -0
- data/lib/active_merchant/billing/gateways/optimal_payment.rb +313 -0
- data/lib/active_merchant/billing/gateways/orbital.rb +803 -0
- data/lib/active_merchant/billing/gateways/orbital/orbital_soft_descriptors.rb +47 -0
- data/lib/active_merchant/billing/gateways/pac_net_raven.rb +207 -0
- data/lib/active_merchant/billing/gateways/pago_facil.rb +122 -0
- data/lib/active_merchant/billing/gateways/pay_gate_xml.rb +261 -0
- data/lib/active_merchant/billing/gateways/pay_junction.rb +390 -0
- data/lib/active_merchant/billing/gateways/pay_secure.rb +112 -0
- data/lib/active_merchant/billing/gateways/pay_u_latam.rb +462 -0
- data/lib/active_merchant/billing/gateways/paybox_direct.rb +188 -0
- data/lib/active_merchant/billing/gateways/payex.rb +412 -0
- data/lib/active_merchant/billing/gateways/payflow.rb +304 -0
- data/lib/active_merchant/billing/gateways/payflow/payflow_common_api.rb +209 -0
- data/lib/active_merchant/billing/gateways/payflow/payflow_express_response.rb +39 -0
- data/lib/active_merchant/billing/gateways/payflow/payflow_response.rb +13 -0
- data/lib/active_merchant/billing/gateways/payflow_express.rb +224 -0
- data/lib/active_merchant/billing/gateways/payflow_express_uk.rb +15 -0
- data/lib/active_merchant/billing/gateways/payflow_uk.rb +21 -0
- data/lib/active_merchant/billing/gateways/payment_express.rb +353 -0
- data/lib/active_merchant/billing/gateways/paymill.rb +281 -0
- data/lib/active_merchant/billing/gateways/paypal.rb +117 -0
- data/lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb +670 -0
- data/lib/active_merchant/billing/gateways/paypal/paypal_express_response.rb +65 -0
- data/lib/active_merchant/billing/gateways/paypal/paypal_recurring_api.rb +262 -0
- data/lib/active_merchant/billing/gateways/paypal_ca.rb +13 -0
- data/lib/active_merchant/billing/gateways/paypal_digital_goods.rb +44 -0
- data/lib/active_merchant/billing/gateways/paypal_express.rb +264 -0
- data/lib/active_merchant/billing/gateways/paypal_express_common.rb +30 -0
- data/lib/active_merchant/billing/gateways/payscout.rb +162 -0
- data/lib/active_merchant/billing/gateways/paystation.rb +199 -0
- data/lib/active_merchant/billing/gateways/payway.rb +207 -0
- data/lib/active_merchant/billing/gateways/pin.rb +197 -0
- data/lib/active_merchant/billing/gateways/plugnpay.rb +283 -0
- data/lib/active_merchant/billing/gateways/psigate.rb +216 -0
- data/lib/active_merchant/billing/gateways/psl_card.rb +303 -0
- data/lib/active_merchant/billing/gateways/qbms.rb +292 -0
- data/lib/active_merchant/billing/gateways/quantum.rb +276 -0
- data/lib/active_merchant/billing/gateways/quickpay.rb +367 -0
- data/lib/active_merchant/billing/gateways/realex.rb +298 -0
- data/lib/active_merchant/billing/gateways/redsys.rb +391 -0
- data/lib/active_merchant/billing/gateways/sage.rb +175 -0
- data/lib/active_merchant/billing/gateways/sage/sage_bankcard.rb +87 -0
- data/lib/active_merchant/billing/gateways/sage/sage_core.rb +114 -0
- data/lib/active_merchant/billing/gateways/sage/sage_vault.rb +149 -0
- data/lib/active_merchant/billing/gateways/sage/sage_virtual_check.rb +102 -0
- data/lib/active_merchant/billing/gateways/sage_pay.rb +398 -0
- data/lib/active_merchant/billing/gateways/sallie_mae.rb +143 -0
- data/lib/active_merchant/billing/gateways/secure_net.rb +252 -0
- data/lib/active_merchant/billing/gateways/secure_pay.rb +201 -0
- data/lib/active_merchant/billing/gateways/secure_pay_au.rb +281 -0
- data/lib/active_merchant/billing/gateways/secure_pay_tech.rb +105 -0
- data/lib/active_merchant/billing/gateways/skip_jack.rb +452 -0
- data/lib/active_merchant/billing/gateways/smart_ps.rb +283 -0
- data/lib/active_merchant/billing/gateways/so_easy_pay.rb +194 -0
- data/lib/active_merchant/billing/gateways/spreedly_core.rb +247 -0
- data/lib/active_merchant/billing/gateways/stripe.rb +411 -0
- data/lib/active_merchant/billing/gateways/swipe_checkout.rb +157 -0
- data/lib/active_merchant/billing/gateways/tns.rb +227 -0
- data/lib/active_merchant/billing/gateways/trans_first.rb +126 -0
- data/lib/active_merchant/billing/gateways/transax.rb +23 -0
- data/lib/active_merchant/billing/gateways/transnational.rb +10 -0
- data/lib/active_merchant/billing/gateways/trust_commerce.rb +416 -0
- data/lib/active_merchant/billing/gateways/usa_epay.rb +25 -0
- data/lib/active_merchant/billing/gateways/usa_epay_advanced.rb +1516 -0
- data/lib/active_merchant/billing/gateways/usa_epay_transaction.rb +254 -0
- data/lib/active_merchant/billing/gateways/verifi.rb +225 -0
- data/lib/active_merchant/billing/gateways/viaklix.rb +183 -0
- data/lib/active_merchant/billing/gateways/vindicia.rb +385 -0
- data/lib/active_merchant/billing/gateways/webpay.rb +97 -0
- data/lib/active_merchant/billing/gateways/wepay.rb +189 -0
- data/lib/active_merchant/billing/gateways/wirecard.rb +421 -0
- data/lib/active_merchant/billing/gateways/worldpay.rb +331 -0
- data/lib/active_merchant/billing/gateways/worldpay_us.rb +181 -0
- data/lib/active_merchant/billing/model.rb +30 -0
- data/lib/active_merchant/billing/payment_token.rb +21 -0
- data/lib/active_merchant/billing/rails.rb +3 -0
- data/lib/active_merchant/billing/response.rb +91 -0
- data/lib/active_merchant/country.rb +332 -0
- data/lib/active_merchant/empty.rb +20 -0
- data/lib/active_merchant/errors.rb +29 -0
- data/lib/active_merchant/offsite_payments_shim.rb +19 -0
- data/lib/active_merchant/version.rb +3 -0
- data/lib/activemerchant.rb +1 -0
- data/lib/support/gateway_support.rb +71 -0
- data/lib/support/outbound_hosts.rb +25 -0
- data/lib/support/ssl_verify.rb +93 -0
- metadata +400 -0
@@ -0,0 +1,448 @@
|
|
1
|
+
require 'nokogiri'
|
2
|
+
|
3
|
+
module ActiveMerchant #:nodoc:
|
4
|
+
module Billing #:nodoc:
|
5
|
+
# iTransact, Inc. is an authorized reseller of the PaymentClearing gateway. If your merchant service provider uses PaymentClearing.com to process payments, you can use this module.
|
6
|
+
#
|
7
|
+
#
|
8
|
+
# Please note, the username and API Access Key are not what you use to log into the Merchant Control Panel.
|
9
|
+
#
|
10
|
+
# ==== How to get your GatewayID and API Access Key
|
11
|
+
#
|
12
|
+
# 1. If you don't already have a Gateway Account, go to http://www.itransact.com/merchant/test.html to sign up.
|
13
|
+
# 2. Go to http://support.paymentclearing.com and login or register, if necessary.
|
14
|
+
# 3. Click on "Submit a Ticket."
|
15
|
+
# 4. Select "Merchant Support" as the department and click "Next"
|
16
|
+
# 5. Enter *both* your company name and GatewayID. Put "API Access Key" in the subject. In the body, you can request a username, but it may already be in use.
|
17
|
+
#
|
18
|
+
# ==== Initialization
|
19
|
+
#
|
20
|
+
# Once you have the username, API Access Key, and your GatewayId, you're ready
|
21
|
+
# to begin. You initialize the Gateway like so:
|
22
|
+
#
|
23
|
+
# gateway = ActiveMerchant::Billing::ItransactGateway.new(
|
24
|
+
# :login => "#{THE_USERNAME}",
|
25
|
+
# :password => "#{THE_API_ACCESS_KEY}",
|
26
|
+
# :gateway_id => "#{THE_GATEWAY_ID}"
|
27
|
+
# )
|
28
|
+
#
|
29
|
+
# ==== Important Notes
|
30
|
+
# 1. Recurring is not implemented
|
31
|
+
# 1. CreditTransactions are not implemented (these are credits not related to a previously run transaction).
|
32
|
+
# 1. TransactionStatus is not implemented
|
33
|
+
#
|
34
|
+
class ItransactGateway < Gateway
|
35
|
+
self.live_url = self.test_url = 'https://secure.paymentclearing.com/cgi-bin/rc/xmltrans2.cgi'
|
36
|
+
|
37
|
+
# The countries the gateway supports merchants from as 2 digit ISO country codes
|
38
|
+
self.supported_countries = ['US']
|
39
|
+
|
40
|
+
# The card types supported by the payment gateway
|
41
|
+
self.supported_cardtypes = [:visa, :master, :american_express, :discover]
|
42
|
+
|
43
|
+
# The homepage URL of the gateway
|
44
|
+
self.homepage_url = 'http://www.itransact.com/'
|
45
|
+
|
46
|
+
# The name of the gateway
|
47
|
+
self.display_name = 'iTransact'
|
48
|
+
|
49
|
+
#
|
50
|
+
# Creates a new instance of the iTransact Gateway.
|
51
|
+
#
|
52
|
+
# ==== Parameters
|
53
|
+
# * <tt>options</tt> - A Hash of options
|
54
|
+
#
|
55
|
+
# ==== Options Hash
|
56
|
+
# * <tt>:login</tt> - A String containing your PaymentClearing assigned API Access Username
|
57
|
+
# * <tt>:password</tt> - A String containing your PaymentClearing assigned API Access Key
|
58
|
+
# * <tt>:gateway_id</tt> - A String containing your PaymentClearing assigned GatewayID
|
59
|
+
# * <tt>:test_mode</tt> - <tt>true</tt> or <tt>false</tt>. Run *all* transactions with the 'TestMode' element set to 'TRUE'.
|
60
|
+
#
|
61
|
+
def initialize(options = {})
|
62
|
+
requires!(options, :login, :password, :gateway_id)
|
63
|
+
super
|
64
|
+
end
|
65
|
+
|
66
|
+
# Performs an authorize transaction. In PaymentClearing's documentation
|
67
|
+
# this is known as a "PreAuth" transaction.
|
68
|
+
#
|
69
|
+
# ==== Parameters
|
70
|
+
# * <tt>money</tt> - The amount to be captured. Should be an Integer amount in cents.
|
71
|
+
# * <tt>creditcard</tt> - The CreditCard details for the transaction
|
72
|
+
# * <tt>options</tt> - A Hash of options
|
73
|
+
#
|
74
|
+
# ==== Options Hash
|
75
|
+
# The standard options apply here (:order_id, :ip, :customer, :invoice, :merchant, :description, :email, :currency, :address, :billing_address, :shipping_address), as well as:
|
76
|
+
# * <tt>:order_items</tt> - An Array of Hash objects with the keys <tt>:description</tt>, <tt>:cost</tt> (in cents!), and <tt>:quantity</tt>. If this is provided, <tt>:description</tt> and <tt>money</tt> will be ignored.
|
77
|
+
# * <tt>:vendor_data</tt> - An Array of Hash objects with the keys being the name of the VendorData element and value being the value.
|
78
|
+
# * <tt>:send_customer_email</tt> - <tt>true</tt> or <tt>false</tt>. Runs the transaction with the 'SendCustomerEmail' element set to 'TRUE' or 'FALSE'.
|
79
|
+
# * <tt>:send_merchant_email</tt> - <tt>true</tt> or <tt>false</tt>. Runs the transaction with the 'SendMerchantEmail' element set to 'TRUE' or 'FALSE'.
|
80
|
+
# * <tt>:email_text</tt> - An Array of (up to ten (10)) String objects to be included in emails
|
81
|
+
# * <tt>:test_mode</tt> - <tt>true</tt> or <tt>false</tt>. Runs the transaction with the 'TestMode' element set to 'TRUE' or 'FALSE'.
|
82
|
+
#
|
83
|
+
# ==== Examples
|
84
|
+
# response = gateway.authorize(1000, creditcard,
|
85
|
+
# :order_id => '1212', :address => {...}, :email => 'test@test.com',
|
86
|
+
# :order_items => [
|
87
|
+
# {:description => 'Line Item 1', :cost => '8.98', :quantity => '6'},
|
88
|
+
# {:description => 'Line Item 2', :cost => '6.99', :quantity => '4'}
|
89
|
+
# ],
|
90
|
+
# :vendor_data => [{'repId' => '1234567'}, {'customerId' => '9886'}],
|
91
|
+
# :send_customer_email => true,
|
92
|
+
# :send_merchant_email => true,
|
93
|
+
# :email_text => ['line1', 'line2', 'line3'],
|
94
|
+
# :test_mode => true
|
95
|
+
# )
|
96
|
+
#
|
97
|
+
def authorize(money, payment_source, options = {})
|
98
|
+
payload = Nokogiri::XML::Builder.new do |xml|
|
99
|
+
xml.AuthTransaction {
|
100
|
+
xml.Preauth
|
101
|
+
add_customer_data(xml, payment_source, options)
|
102
|
+
add_invoice(xml, money, options)
|
103
|
+
add_payment_source(xml, payment_source)
|
104
|
+
add_transaction_control(xml, options)
|
105
|
+
add_vendor_data(xml, options)
|
106
|
+
}
|
107
|
+
end.doc
|
108
|
+
|
109
|
+
commit(payload)
|
110
|
+
end
|
111
|
+
|
112
|
+
# Performs an authorize and capture in single transaction. In PaymentClearing's
|
113
|
+
# documentation this is known as an "Auth" or a "Sale" transaction
|
114
|
+
#
|
115
|
+
# ==== Parameters
|
116
|
+
# * <tt>money</tt> - The amount to be captured. Should be <tt>nil</tt> or an Integer amount in cents.
|
117
|
+
# * <tt>creditcard</tt> - The CreditCard details for the transaction
|
118
|
+
# * <tt>options</tt> - A Hash of options
|
119
|
+
#
|
120
|
+
# ==== Options Hash
|
121
|
+
# The standard options apply here (:order_id, :ip, :customer, :invoice, :merchant, :description, :email, :currency, :address, :billing_address, :shipping_address), as well as:
|
122
|
+
# * <tt>:order_items</tt> - An Array of Hash objects with the keys <tt>:description</tt>, <tt>:cost</tt> (in cents!), and <tt>:quantity</tt>. If this is provided, <tt>:description</tt> and <tt>money</tt> will be ignored.
|
123
|
+
# * <tt>:vendor_data</tt> - An Array of Hash objects with the keys being the name of the VendorData element and value being the value.
|
124
|
+
# * <tt>:send_customer_email</tt> - <tt>true</tt> or <tt>false</tt>. Runs the transaction with the 'SendCustomerEmail' element set to 'TRUE' or 'FALSE'.
|
125
|
+
# * <tt>:send_merchant_email</tt> - <tt>true</tt> or <tt>false</tt>. Runs the transaction with the 'SendMerchantEmail' element set to 'TRUE' or 'FALSE'.
|
126
|
+
# * <tt>:email_text</tt> - An Array of (up to ten (10)) String objects to be included in emails
|
127
|
+
# * <tt>:test_mode</tt> - <tt>true</tt> or <tt>false</tt>. Runs the transaction with the 'TestMode' element set to 'TRUE' or 'FALSE'.
|
128
|
+
#
|
129
|
+
# ==== Examples
|
130
|
+
# response = gateway.purchase(1000, creditcard,
|
131
|
+
# :order_id => '1212', :address => {...}, :email => 'test@test.com',
|
132
|
+
# :order_items => [
|
133
|
+
# {:description => 'Line Item 1', :cost => '8.98', :quantity => '6'},
|
134
|
+
# {:description => 'Line Item 2', :cost => '6.99', :quantity => '4'}
|
135
|
+
# ],
|
136
|
+
# :vendor_data => [{'repId' => '1234567'}, {'customerId' => '9886'}],
|
137
|
+
# :send_customer_email => true,
|
138
|
+
# :send_merchant_email => true,
|
139
|
+
# :email_text => ['line1', 'line2', 'line3'],
|
140
|
+
# :test_mode => true
|
141
|
+
# )
|
142
|
+
#
|
143
|
+
def purchase(money, payment_source, options = {})
|
144
|
+
payload = Nokogiri::XML::Builder.new do |xml|
|
145
|
+
xml.AuthTransaction {
|
146
|
+
add_customer_data(xml, payment_source, options)
|
147
|
+
add_invoice(xml, money, options)
|
148
|
+
add_payment_source(xml, payment_source)
|
149
|
+
add_transaction_control(xml, options)
|
150
|
+
add_vendor_data(xml, options)
|
151
|
+
}
|
152
|
+
end.doc
|
153
|
+
|
154
|
+
commit(payload)
|
155
|
+
end
|
156
|
+
|
157
|
+
# Captures the funds from an authorize transaction. In PaymentClearing's
|
158
|
+
# documentation this is known as a "PostAuth" transaction.
|
159
|
+
#
|
160
|
+
# ==== Parameters
|
161
|
+
# * <tt>money</tt> - The amount to be captured. Should be an Integer amount in cents
|
162
|
+
# * <tt>authorization</tt> - The authorization returned from the previous capture or purchase request
|
163
|
+
# * <tt>options</tt> - A Hash of options, all are optional.
|
164
|
+
#
|
165
|
+
# ==== Options Hash
|
166
|
+
# The standard options apply here (:order_id, :ip, :customer, :invoice, :merchant, :description, :email, :currency, :address, :billing_address, :shipping_address), as well as:
|
167
|
+
# * <tt>:vendor_data</tt> - An Array of Hash objects with the keys being the name of the VendorData element and value being the value.
|
168
|
+
# * <tt>:send_customer_email</tt> - <tt>true</tt> or <tt>false</tt>. Runs the transaction with the 'SendCustomerEmail' element set to 'TRUE' or 'FALSE'.
|
169
|
+
# * <tt>:send_merchant_email</tt> - <tt>true</tt> or <tt>false</tt>. Runs the transaction with the 'SendMerchantEmail' element set to 'TRUE' or 'FALSE'.
|
170
|
+
# * <tt>:email_text</tt> - An Array of (up to ten (10)) String objects to be included in emails
|
171
|
+
# * <tt>:test_mode</tt> - <tt>true</tt> or <tt>false</tt>. Runs the transaction with the 'TestMode' element set to 'TRUE' or 'FALSE'.
|
172
|
+
#
|
173
|
+
# ==== Examples
|
174
|
+
# response = gateway.capture(1000, creditcard,
|
175
|
+
# :vendor_data => [{'repId' => '1234567'}, {'customerId' => '9886'}],
|
176
|
+
# :send_customer_email => true,
|
177
|
+
# :send_merchant_email => true,
|
178
|
+
# :email_text => ['line1', 'line2', 'line3'],
|
179
|
+
# :test_mode => true
|
180
|
+
# )
|
181
|
+
#
|
182
|
+
def capture(money, authorization, options = {})
|
183
|
+
payload = Nokogiri::XML::Builder.new do |xml|
|
184
|
+
xml.PostAuthTransaction {
|
185
|
+
xml.OperationXID(authorization)
|
186
|
+
add_invoice(xml, money, options)
|
187
|
+
add_transaction_control(xml, options)
|
188
|
+
add_vendor_data(xml, options)
|
189
|
+
}
|
190
|
+
end.doc
|
191
|
+
|
192
|
+
commit(payload)
|
193
|
+
end
|
194
|
+
|
195
|
+
# This will reverse a previously run transaction which *has* *not* settled.
|
196
|
+
#
|
197
|
+
# ==== Parameters
|
198
|
+
# * <tt>authorization</tt> - The authorization returned from the previous capture or purchase request
|
199
|
+
# * <tt>options</tt> - A Hash of options, all are optional
|
200
|
+
#
|
201
|
+
# ==== Options Hash
|
202
|
+
# The standard options (:order_id, :ip, :customer, :invoice, :merchant, :description, :email, :currency, :address, :billing_address, :shipping_address) are ignored.
|
203
|
+
# * <tt>:vendor_data</tt> - An Array of Hash objects with the keys being the name of the VendorData element and value being the value.
|
204
|
+
# * <tt>:send_customer_email</tt> - <tt>true</tt> or <tt>false</tt>. Runs the transaction with the 'SendCustomerEmail' element set to 'TRUE' or 'FALSE'.
|
205
|
+
# * <tt>:send_merchant_email</tt> - <tt>true</tt> or <tt>false</tt>. Runs the transaction with the 'SendMerchantEmail' element set to 'TRUE' or 'FALSE'.
|
206
|
+
# * <tt>:email_text</tt> - An Array of (up to ten (10)) String objects to be included in emails
|
207
|
+
# * <tt>:test_mode</tt> - <tt>true</tt> or <tt>false</tt>. Runs the transaction with the 'TestMode' element set to 'TRUE' or 'FALSE'.
|
208
|
+
#
|
209
|
+
# ==== Examples
|
210
|
+
# response = gateway.void('9999999999',
|
211
|
+
# :vendor_data => [{'repId' => '1234567'}, {'customerId' => '9886'}],
|
212
|
+
# :send_customer_email => true,
|
213
|
+
# :send_merchant_email => true,
|
214
|
+
# :email_text => ['line1', 'line2', 'line3'],
|
215
|
+
# :test_mode => true
|
216
|
+
# )
|
217
|
+
#
|
218
|
+
def void(authorization, options = {})
|
219
|
+
payload = Nokogiri::XML::Builder.new do |xml|
|
220
|
+
xml.VoidTransaction {
|
221
|
+
xml.OperationXID(authorization)
|
222
|
+
add_transaction_control(xml, options)
|
223
|
+
add_vendor_data(xml, options)
|
224
|
+
}
|
225
|
+
end.doc
|
226
|
+
|
227
|
+
commit(payload)
|
228
|
+
end
|
229
|
+
|
230
|
+
# This will reverse a previously run transaction which *has* settled.
|
231
|
+
#
|
232
|
+
# ==== Parameters
|
233
|
+
# * <tt>money</tt> - The amount to be credited. Should be an Integer amount in cents
|
234
|
+
# * <tt>authorization</tt> - The authorization returned from the previous capture or purchase request
|
235
|
+
# * <tt>options</tt> - A Hash of options, all are optional
|
236
|
+
#
|
237
|
+
# ==== Options Hash
|
238
|
+
# The standard options (:order_id, :ip, :customer, :invoice, :merchant, :description, :email, :currency, :address, :billing_address, :shipping_address) are ignored.
|
239
|
+
# * <tt>:vendor_data</tt> - An Array of Hash objects with the keys being the name of the VendorData element and value being the value.
|
240
|
+
# * <tt>:send_customer_email</tt> - <tt>true</tt> or <tt>false</tt>. Runs the transaction with the 'SendCustomerEmail' element set to 'TRUE' or 'FALSE'.
|
241
|
+
# * <tt>:send_merchant_email</tt> - <tt>true</tt> or <tt>false</tt>. Runs the transaction with the 'SendMerchantEmail' element set to 'TRUE' or 'FALSE'.
|
242
|
+
# * <tt>:email_text</tt> - An Array of (up to ten (10)) String objects to be included in emails
|
243
|
+
# * <tt>:test_mode</tt> - <tt>true</tt> or <tt>false</tt>. Runs the transaction with the 'TestMode' element set to 'TRUE' or 'FALSE'.
|
244
|
+
#
|
245
|
+
# ==== Examples
|
246
|
+
# response = gateway.refund(555, '9999999999',
|
247
|
+
# :vendor_data => [{'repId' => '1234567'}, {'customerId' => '9886'}],
|
248
|
+
# :send_customer_email => true,
|
249
|
+
# :send_merchant_email => true,
|
250
|
+
# :email_text => ['line1', 'line2', 'line3'],
|
251
|
+
# :test_mode => true
|
252
|
+
# )
|
253
|
+
#
|
254
|
+
def refund(money, authorization, options = {})
|
255
|
+
payload = Nokogiri::XML::Builder.new do |xml|
|
256
|
+
xml.TranCredTransaction {
|
257
|
+
xml.OperationXID(authorization)
|
258
|
+
add_invoice(xml, money, options)
|
259
|
+
add_transaction_control(xml, options)
|
260
|
+
add_vendor_data(xml, options)
|
261
|
+
}
|
262
|
+
end.doc
|
263
|
+
|
264
|
+
commit(payload)
|
265
|
+
end
|
266
|
+
|
267
|
+
private
|
268
|
+
|
269
|
+
def add_customer_data(xml, payment_source, options)
|
270
|
+
billing_address = options[:billing_address] || options[:address]
|
271
|
+
shipping_address = options[:shipping_address] || options[:address]
|
272
|
+
|
273
|
+
xml.CustomerData {
|
274
|
+
xml.Email(options[:email]) unless options[:email].blank?
|
275
|
+
xml.CustId(options[:order_id]) unless options[:order_id].blank?
|
276
|
+
xml.BillingAddress {
|
277
|
+
xml.FirstName(payment_source.first_name || parse_first_name(billing_address[:name]))
|
278
|
+
xml.LastName(payment_source.last_name || parse_last_name(billing_address[:name]))
|
279
|
+
xml.Address1(billing_address[:address1])
|
280
|
+
xml.Address2(billing_address[:address2]) unless billing_address[:address2].blank?
|
281
|
+
xml.City(billing_address[:city])
|
282
|
+
xml.State(billing_address[:state])
|
283
|
+
xml.Zip(billing_address[:zip])
|
284
|
+
xml.Country(billing_address[:country])
|
285
|
+
xml.Phone(billing_address[:phone])
|
286
|
+
}
|
287
|
+
xml.ShippingAddress {
|
288
|
+
xml.FirstName(payment_source.first_name || parse_first_name(shipping_address[:name]))
|
289
|
+
xml.LastName(payment_source.last_name || parse_last_name(shipping_address[:name]))
|
290
|
+
xml.Address1(shipping_address[:address1])
|
291
|
+
xml.Address2(shipping_address[:address2]) unless shipping_address[:address2].blank?
|
292
|
+
xml.City(shipping_address[:city])
|
293
|
+
xml.State(shipping_address[:state])
|
294
|
+
xml.Zip(shipping_address[:zip])
|
295
|
+
xml.Country(shipping_address[:country])
|
296
|
+
xml.Phone(shipping_address[:phone])
|
297
|
+
} unless shipping_address.blank?
|
298
|
+
}
|
299
|
+
end
|
300
|
+
|
301
|
+
def add_invoice(xml, money, options)
|
302
|
+
xml.AuthCode options[:force] if options[:force]
|
303
|
+
if options[:order_items].blank?
|
304
|
+
xml.Total(amount(money)) unless(money.nil? || money < 0.01)
|
305
|
+
xml.Description(options[:description]) unless( options[:description].blank?)
|
306
|
+
else
|
307
|
+
xml.OrderItems {
|
308
|
+
options[:order_items].each do |item|
|
309
|
+
xml.Item {
|
310
|
+
xml.Description(item[:description])
|
311
|
+
xml.Cost(amount(item[:cost]))
|
312
|
+
xml.Qty(item[:quantity].to_s)
|
313
|
+
}
|
314
|
+
end
|
315
|
+
}
|
316
|
+
end
|
317
|
+
end
|
318
|
+
|
319
|
+
def add_payment_source(xml, source)
|
320
|
+
case determine_funding_source(source)
|
321
|
+
when :credit_card then add_creditcard(xml, source)
|
322
|
+
when :check then add_check(xml, source)
|
323
|
+
end
|
324
|
+
end
|
325
|
+
|
326
|
+
def determine_funding_source(payment_source)
|
327
|
+
case payment_source
|
328
|
+
when ActiveMerchant::Billing::CreditCard
|
329
|
+
:credit_card
|
330
|
+
when ActiveMerchant::Billing::Check
|
331
|
+
:check
|
332
|
+
end
|
333
|
+
end
|
334
|
+
|
335
|
+
def add_creditcard(xml, creditcard)
|
336
|
+
xml.AccountInfo {
|
337
|
+
xml.CardAccount {
|
338
|
+
xml.AccountNumber(creditcard.number.to_s)
|
339
|
+
xml.ExpirationMonth(creditcard.month.to_s.rjust(2,'0'))
|
340
|
+
xml.ExpirationYear(creditcard.year.to_s)
|
341
|
+
xml.CVVNumber(creditcard.verification_value.to_s) unless creditcard.verification_value.blank?
|
342
|
+
}
|
343
|
+
}
|
344
|
+
end
|
345
|
+
|
346
|
+
def add_check(xml, check)
|
347
|
+
xml.AccountInfo {
|
348
|
+
xml.ABA(check.routing_number.to_s)
|
349
|
+
xml.AccountNumber(check.account_number.to_s)
|
350
|
+
xml.AccountSource(check.account_type.to_s)
|
351
|
+
xml.AccountType(check.account_holder_type.to_s)
|
352
|
+
xml.CheckNumber(check.number.to_s)
|
353
|
+
}
|
354
|
+
end
|
355
|
+
|
356
|
+
def add_transaction_control(xml, options)
|
357
|
+
xml.TransactionControl {
|
358
|
+
# if there was a 'global' option set...
|
359
|
+
xml.TestMode(@options[:test_mode].upcase) if !@options[:test_mode].blank?
|
360
|
+
# allow the global option to be overridden...
|
361
|
+
xml.TestMode(options[:test_mode].upcase) if !options[:test_mode].blank?
|
362
|
+
xml.SendCustomerEmail(options[:send_customer_email].upcase) unless options[:send_customer_email].blank?
|
363
|
+
xml.SendMerchantEmail(options[:send_merchant_email].upcase) unless options[:send_merchant_email].blank?
|
364
|
+
xml.EmailText {
|
365
|
+
options[:email_text].each do |item|
|
366
|
+
xml.EmailTextItem(item)
|
367
|
+
end
|
368
|
+
} if options[:email_text]
|
369
|
+
}
|
370
|
+
end
|
371
|
+
|
372
|
+
def add_vendor_data(xml, options)
|
373
|
+
return if options[:vendor_data].blank?
|
374
|
+
xml.VendorData {
|
375
|
+
options[:vendor_data].each do |k,v|
|
376
|
+
xml.Element {
|
377
|
+
xml.Name(k)
|
378
|
+
xml.Key(v)
|
379
|
+
}
|
380
|
+
end
|
381
|
+
}
|
382
|
+
end
|
383
|
+
|
384
|
+
def commit(payload)
|
385
|
+
# Set the Content-Type header -- otherwise the URL decoding messes up
|
386
|
+
# the Base64 encoded payload signature!
|
387
|
+
response = parse(ssl_post(self.live_url, post_data(payload), 'Content-Type' => 'text/xml'))
|
388
|
+
|
389
|
+
Response.new(successful?(response), response[:error_message], response,
|
390
|
+
:test => test?,
|
391
|
+
:authorization => response[:xid],
|
392
|
+
:avs_result => { :code => response[:avs_response] },
|
393
|
+
:cvv_result => response[:cvv_response])
|
394
|
+
end
|
395
|
+
|
396
|
+
def post_data(payload)
|
397
|
+
payload_xml = payload.root.to_xml(:indent => 0)
|
398
|
+
|
399
|
+
payload_signature = sign_payload(payload_xml)
|
400
|
+
|
401
|
+
request = Nokogiri::XML::Builder.new do |xml|
|
402
|
+
xml.GatewayInterface {
|
403
|
+
xml.APICredentials {
|
404
|
+
xml.Username(@options[:login])
|
405
|
+
xml.PayloadSignature(payload_signature)
|
406
|
+
xml.TargetGateway(@options[:gateway_id])
|
407
|
+
}
|
408
|
+
}
|
409
|
+
end.doc
|
410
|
+
|
411
|
+
request.root.children.first.after payload.root
|
412
|
+
request.to_xml(:indent => 0)
|
413
|
+
end
|
414
|
+
|
415
|
+
def parse(raw_xml)
|
416
|
+
doc = REXML::Document.new(raw_xml)
|
417
|
+
response = Hash.new
|
418
|
+
transaction_result = doc.root.get_elements('TransactionResponse/TransactionResult/*')
|
419
|
+
transaction_result.each do |e|
|
420
|
+
response[e.name.to_s.underscore.to_sym] = e.text unless e.text.blank?
|
421
|
+
end
|
422
|
+
response
|
423
|
+
end
|
424
|
+
|
425
|
+
def successful?(response)
|
426
|
+
# Turns out the PaymentClearing gateway is not consistent...
|
427
|
+
response[:status].downcase =='ok'
|
428
|
+
end
|
429
|
+
|
430
|
+
def test_mode?(response)
|
431
|
+
# The '1' is a legacy thing; most of the time it should be 'TRUE'...
|
432
|
+
response[:test_mode] == 'TRUE' || response[:test_mode] == '1'
|
433
|
+
end
|
434
|
+
|
435
|
+
def message_from(response)
|
436
|
+
response[:error_message]
|
437
|
+
end
|
438
|
+
|
439
|
+
def sign_payload(payload)
|
440
|
+
key = @options[:password].to_s
|
441
|
+
digest=OpenSSL::HMAC.digest(OpenSSL::Digest::SHA1.new(key), key, payload)
|
442
|
+
signature = Base64.encode64(digest)
|
443
|
+
signature.chomp!
|
444
|
+
end
|
445
|
+
end
|
446
|
+
end
|
447
|
+
end
|
448
|
+
|
@@ -0,0 +1,275 @@
|
|
1
|
+
module ActiveMerchant #:nodoc:
|
2
|
+
module Billing #:nodoc:
|
3
|
+
class JetpayGateway < Gateway
|
4
|
+
self.test_url = 'https://test1.jetpay.com/jetpay'
|
5
|
+
self.live_url = 'https://gateway17.jetpay.com/jetpay'
|
6
|
+
|
7
|
+
# The countries the gateway supports merchants from as 2 digit ISO country codes
|
8
|
+
self.supported_countries = ['US']
|
9
|
+
|
10
|
+
# The card types supported by the payment gateway
|
11
|
+
self.supported_cardtypes = [:visa, :master, :american_express, :discover]
|
12
|
+
|
13
|
+
# The homepage URL of the gateway
|
14
|
+
self.homepage_url = 'http://www.jetpay.com/'
|
15
|
+
|
16
|
+
# The name of the gateway
|
17
|
+
self.display_name = 'JetPay'
|
18
|
+
|
19
|
+
# all transactions are in cents
|
20
|
+
self.money_format = :cents
|
21
|
+
|
22
|
+
ACTION_CODE_MESSAGES = {
|
23
|
+
"001" => "Refer to card issuer.",
|
24
|
+
"002" => "Refer to card issuer, special condition.",
|
25
|
+
"003" => "Pick up card.",
|
26
|
+
"200" => "Deny - Pick up card.",
|
27
|
+
"005" => "Do not honor.",
|
28
|
+
"100" => "Deny.",
|
29
|
+
"006" => "Error.",
|
30
|
+
"181" => "Format error.",
|
31
|
+
"007" => "Pickup card, special condition.",
|
32
|
+
"104" => "Deny - New card issued.",
|
33
|
+
"110" => "Invalid amount.",
|
34
|
+
"014" => "Invalid account number (no such number).",
|
35
|
+
"111" => "Invalid account.",
|
36
|
+
"015" => "No such issuer.",
|
37
|
+
"103" => "Deny - Invalid manual Entry 4DBC.",
|
38
|
+
"182" => "Please wait.",
|
39
|
+
"109" => "Invalid merchant.",
|
40
|
+
"041" => "Pick up card (lost card).",
|
41
|
+
"043" => "Pick up card (stolen card).",
|
42
|
+
"051" => "Insufficient funds.",
|
43
|
+
"052" => "No checking account.",
|
44
|
+
"105" => "Deny - Account Cancelled.",
|
45
|
+
"054" => "Expired Card.",
|
46
|
+
"101" => "Expired Card.",
|
47
|
+
"183" => "Invalid currency code.",
|
48
|
+
"057" => "Transaction not permitted to cardholder.",
|
49
|
+
"115" => "Service not permitted.",
|
50
|
+
"062" => "Restricted card.",
|
51
|
+
"189" => "Deny - Cancelled or Closed Merchant/SE.",
|
52
|
+
"188" => "Deny - Expiration date required.",
|
53
|
+
"125" => "Invalid effective date.",
|
54
|
+
"122" => "Invalid card (CID) security code.",
|
55
|
+
"400" => "Reversal accepted.",
|
56
|
+
"992" => "DECLINE/TIMEOUT.",
|
57
|
+
"107" => "Please Call Issuer.",
|
58
|
+
"025" => "Transaction Not Found.",
|
59
|
+
"981" => "AVS Error.",
|
60
|
+
"913" => "Invalid Card Type.",
|
61
|
+
"996" => "Terminal ID Not Found.",
|
62
|
+
nil => "No response returned (missing credentials?)."
|
63
|
+
}
|
64
|
+
|
65
|
+
def initialize(options = {})
|
66
|
+
requires!(options, :login)
|
67
|
+
super
|
68
|
+
end
|
69
|
+
|
70
|
+
def purchase(money, credit_card, options = {})
|
71
|
+
commit(money, build_sale_request(money, credit_card, options))
|
72
|
+
end
|
73
|
+
|
74
|
+
def authorize(money, credit_card, options = {})
|
75
|
+
commit(money, build_authonly_request(money, credit_card, options))
|
76
|
+
end
|
77
|
+
|
78
|
+
def capture(money, reference, options = {})
|
79
|
+
commit(money, build_capture_request('CAPT', reference.split(";").first))
|
80
|
+
end
|
81
|
+
|
82
|
+
def void(reference, options = {})
|
83
|
+
transaction_id, approval, amount = reference.split(";")
|
84
|
+
commit(amount.to_i, build_void_request(amount.to_i, transaction_id, approval))
|
85
|
+
end
|
86
|
+
|
87
|
+
def credit(money, transaction_id_or_card, options = {})
|
88
|
+
if transaction_id_or_card.is_a?(String)
|
89
|
+
ActiveMerchant.deprecated CREDIT_DEPRECATION_MESSAGE
|
90
|
+
refund(money, transaction_id_or_card, options)
|
91
|
+
else
|
92
|
+
commit(money, build_credit_request('CREDIT', money, nil, transaction_id_or_card))
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def refund(money, reference, options = {})
|
97
|
+
transaction_id = reference.split(";").first
|
98
|
+
credit_card = options[:credit_card]
|
99
|
+
commit(money, build_credit_request('CREDIT', money, transaction_id, credit_card))
|
100
|
+
end
|
101
|
+
|
102
|
+
|
103
|
+
private
|
104
|
+
|
105
|
+
def build_xml_request(transaction_type, transaction_id = nil, &block)
|
106
|
+
xml = Builder::XmlMarkup.new
|
107
|
+
xml.tag! 'JetPay' do
|
108
|
+
# The basic values needed for any request
|
109
|
+
xml.tag! 'TerminalID', @options[:login]
|
110
|
+
xml.tag! 'TransactionType', transaction_type
|
111
|
+
xml.tag! 'TransactionID', transaction_id.nil? ? generate_unique_id.slice(0, 18) : transaction_id
|
112
|
+
|
113
|
+
if block_given?
|
114
|
+
yield xml
|
115
|
+
else
|
116
|
+
xml.target!
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def build_sale_request(money, credit_card, options)
|
122
|
+
build_xml_request('SALE') do |xml|
|
123
|
+
add_credit_card(xml, credit_card)
|
124
|
+
add_addresses(xml, options)
|
125
|
+
add_customer_data(xml, options)
|
126
|
+
add_invoice_data(xml, options)
|
127
|
+
xml.tag! 'TotalAmount', amount(money)
|
128
|
+
|
129
|
+
xml.target!
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
def build_authonly_request(money, credit_card, options)
|
134
|
+
build_xml_request('AUTHONLY') do |xml|
|
135
|
+
add_credit_card(xml, credit_card)
|
136
|
+
add_addresses(xml, options)
|
137
|
+
add_customer_data(xml, options)
|
138
|
+
add_invoice_data(xml, options)
|
139
|
+
xml.tag! 'TotalAmount', amount(money)
|
140
|
+
|
141
|
+
xml.target!
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
def build_capture_request(transaction_type, transaction_id)
|
146
|
+
build_xml_request(transaction_type, transaction_id)
|
147
|
+
end
|
148
|
+
|
149
|
+
def build_void_request(money, transaction_id, approval)
|
150
|
+
build_xml_request('VOID', transaction_id) do |xml|
|
151
|
+
xml.tag! 'Approval', approval
|
152
|
+
xml.tag! 'TotalAmount', amount(money)
|
153
|
+
|
154
|
+
xml.target!
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
# `transaction_id` may be nil for unlinked credit transactions.
|
159
|
+
def build_credit_request(transaction_type, money, transaction_id, card)
|
160
|
+
build_xml_request(transaction_type, transaction_id) do |xml|
|
161
|
+
add_credit_card(xml, card) if card
|
162
|
+
xml.tag! 'TotalAmount', amount(money)
|
163
|
+
|
164
|
+
xml.target!
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
def commit(money, request)
|
169
|
+
response = parse(ssl_post(test? ? self.test_url : self.live_url, request))
|
170
|
+
|
171
|
+
success = success?(response)
|
172
|
+
Response.new(success,
|
173
|
+
success ? 'APPROVED' : message_from(response),
|
174
|
+
response,
|
175
|
+
:test => test?,
|
176
|
+
:authorization => authorization_from(response, money),
|
177
|
+
:avs_result => { :code => response[:avs] },
|
178
|
+
:cvv_result => response[:cvv2]
|
179
|
+
)
|
180
|
+
end
|
181
|
+
|
182
|
+
def parse(body)
|
183
|
+
return {} if body.blank?
|
184
|
+
|
185
|
+
xml = REXML::Document.new(body)
|
186
|
+
|
187
|
+
response = {}
|
188
|
+
xml.root.elements.to_a.each do |node|
|
189
|
+
parse_element(response, node)
|
190
|
+
end
|
191
|
+
response
|
192
|
+
end
|
193
|
+
|
194
|
+
def parse_element(response, node)
|
195
|
+
if node.has_elements?
|
196
|
+
node.elements.each{|element| parse_element(response, element) }
|
197
|
+
else
|
198
|
+
response[node.name.underscore.to_sym] = node.text
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
def format_exp(value)
|
203
|
+
format(value, :two_digits)
|
204
|
+
end
|
205
|
+
|
206
|
+
def success?(response)
|
207
|
+
response[:action_code] == "000"
|
208
|
+
end
|
209
|
+
|
210
|
+
def message_from(response)
|
211
|
+
ACTION_CODE_MESSAGES[response[:action_code]]
|
212
|
+
end
|
213
|
+
|
214
|
+
def authorization_from(response, money)
|
215
|
+
original_amount = amount(money) if money
|
216
|
+
[ response[:transaction_id], response[:approval], original_amount ].join(";")
|
217
|
+
end
|
218
|
+
|
219
|
+
def add_credit_card(xml, credit_card)
|
220
|
+
xml.tag! 'CardNum', credit_card.number
|
221
|
+
xml.tag! 'CardExpMonth', format_exp(credit_card.month)
|
222
|
+
xml.tag! 'CardExpYear', format_exp(credit_card.year)
|
223
|
+
|
224
|
+
if credit_card.first_name || credit_card.last_name
|
225
|
+
xml.tag! 'CardName', [credit_card.first_name,credit_card.last_name].compact.join(' ')
|
226
|
+
end
|
227
|
+
|
228
|
+
unless credit_card.verification_value.nil? || (credit_card.verification_value.length == 0)
|
229
|
+
xml.tag! 'CVV2', credit_card.verification_value
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
def add_addresses(xml, options)
|
234
|
+
if billing_address = options[:billing_address] || options[:address]
|
235
|
+
xml.tag! 'BillingAddress', [billing_address[:address1], billing_address[:address2]].compact.join(" ")
|
236
|
+
xml.tag! 'BillingCity', billing_address[:city]
|
237
|
+
xml.tag! 'BillingStateProv', billing_address[:state]
|
238
|
+
xml.tag! 'BillingPostalCode', billing_address[:zip]
|
239
|
+
xml.tag! 'BillingCountry', lookup_country_code(billing_address[:country])
|
240
|
+
xml.tag! 'BillingPhone', billing_address[:phone]
|
241
|
+
end
|
242
|
+
|
243
|
+
if shipping_address = options[:shipping_address]
|
244
|
+
xml.tag! 'ShippingInfo' do
|
245
|
+
xml.tag! 'ShippingName', shipping_address[:name]
|
246
|
+
|
247
|
+
xml.tag! 'ShippingAddr' do
|
248
|
+
xml.tag! 'Address', [shipping_address[:address1], shipping_address[:address2]].compact.join(" ")
|
249
|
+
xml.tag! 'City', shipping_address[:city]
|
250
|
+
xml.tag! 'StateProv', shipping_address[:state]
|
251
|
+
xml.tag! 'PostalCode', shipping_address[:zip]
|
252
|
+
xml.tag! 'Country', lookup_country_code(shipping_address[:country])
|
253
|
+
end
|
254
|
+
end
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
258
|
+
def add_customer_data(xml, options)
|
259
|
+
xml.tag! 'Email', options[:email] if options[:email]
|
260
|
+
xml.tag! 'UserIPAddress', options[:ip] if options[:ip]
|
261
|
+
end
|
262
|
+
|
263
|
+
def add_invoice_data(xml, options)
|
264
|
+
xml.tag! 'OrderNumber', options[:order_id] if options[:order_id]
|
265
|
+
xml.tag! 'TaxAmount', amount(options[:tax]) if options[:tax]
|
266
|
+
end
|
267
|
+
|
268
|
+
def lookup_country_code(code)
|
269
|
+
country = Country.find(code) rescue nil
|
270
|
+
country && country.code(:alpha3)
|
271
|
+
end
|
272
|
+
end
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|