gonow-activemerchant 1.15.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.
- data/CHANGELOG +690 -0
- data/CONTRIBUTORS +237 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +165 -0
- data/gem-public_cert.pem +20 -0
- data/lib/active_merchant.rb +47 -0
- data/lib/active_merchant/billing.rb +9 -0
- data/lib/active_merchant/billing/avs_result.rb +98 -0
- data/lib/active_merchant/billing/base.rb +57 -0
- data/lib/active_merchant/billing/check.rb +68 -0
- data/lib/active_merchant/billing/credit_card.rb +178 -0
- data/lib/active_merchant/billing/credit_card_formatting.rb +21 -0
- data/lib/active_merchant/billing/credit_card_methods.rb +125 -0
- data/lib/active_merchant/billing/cvv_result.rb +38 -0
- data/lib/active_merchant/billing/expiry_date.rb +34 -0
- data/lib/active_merchant/billing/gateway.rb +170 -0
- data/lib/active_merchant/billing/gateways.rb +18 -0
- data/lib/active_merchant/billing/gateways/authorize_net.rb +664 -0
- data/lib/active_merchant/billing/gateways/authorize_net_cim.rb +858 -0
- data/lib/active_merchant/billing/gateways/barclays_epdq.rb +308 -0
- data/lib/active_merchant/billing/gateways/beanstream.rb +139 -0
- data/lib/active_merchant/billing/gateways/beanstream/beanstream_core.rb +282 -0
- data/lib/active_merchant/billing/gateways/beanstream_interac.rb +54 -0
- data/lib/active_merchant/billing/gateways/blue_pay.rb +11 -0
- data/lib/active_merchant/billing/gateways/bogus.rb +132 -0
- data/lib/active_merchant/billing/gateways/braintree.rb +17 -0
- data/lib/active_merchant/billing/gateways/braintree/braintree_common.rb +9 -0
- data/lib/active_merchant/billing/gateways/braintree_blue.rb +293 -0
- data/lib/active_merchant/billing/gateways/braintree_orange.rb +17 -0
- data/lib/active_merchant/billing/gateways/braspag.rb +188 -0
- data/lib/active_merchant/billing/gateways/card_stream.rb +230 -0
- data/lib/active_merchant/billing/gateways/cyber_source.rb +430 -0
- data/lib/active_merchant/billing/gateways/data_cash.rb +597 -0
- data/lib/active_merchant/billing/gateways/efsnet.rb +235 -0
- data/lib/active_merchant/billing/gateways/elavon.rb +134 -0
- data/lib/active_merchant/billing/gateways/epay.rb +268 -0
- data/lib/active_merchant/billing/gateways/eway.rb +277 -0
- data/lib/active_merchant/billing/gateways/eway_managed.rb +231 -0
- data/lib/active_merchant/billing/gateways/exact.rb +222 -0
- data/lib/active_merchant/billing/gateways/federated_canada.rb +168 -0
- data/lib/active_merchant/billing/gateways/first_pay.rb +177 -0
- data/lib/active_merchant/billing/gateways/garanti.rb +262 -0
- data/lib/active_merchant/billing/gateways/ideal/ideal_base.rb +250 -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 +55 -0
- data/lib/active_merchant/billing/gateways/inspire.rb +221 -0
- data/lib/active_merchant/billing/gateways/instapay.rb +164 -0
- data/lib/active_merchant/billing/gateways/iridium.rb +258 -0
- data/lib/active_merchant/billing/gateways/jetpay.rb +276 -0
- data/lib/active_merchant/billing/gateways/linkpoint.rb +454 -0
- data/lib/active_merchant/billing/gateways/merchant_e_solutions.rb +156 -0
- data/lib/active_merchant/billing/gateways/merchant_ware.rb +289 -0
- data/lib/active_merchant/billing/gateways/modern_payments.rb +36 -0
- data/lib/active_merchant/billing/gateways/modern_payments_cim.rb +220 -0
- data/lib/active_merchant/billing/gateways/moneris.rb +209 -0
- data/lib/active_merchant/billing/gateways/net_registry.rb +189 -0
- data/lib/active_merchant/billing/gateways/netaxept.rb +239 -0
- data/lib/active_merchant/billing/gateways/netbilling.rb +168 -0
- data/lib/active_merchant/billing/gateways/nmi.rb +13 -0
- data/lib/active_merchant/billing/gateways/ogone.rb +292 -0
- data/lib/active_merchant/billing/gateways/orbital.rb +321 -0
- data/lib/active_merchant/billing/gateways/orbital/orbital_soft_descriptors.rb +46 -0
- data/lib/active_merchant/billing/gateways/pay_junction.rb +392 -0
- data/lib/active_merchant/billing/gateways/pay_secure.rb +120 -0
- data/lib/active_merchant/billing/gateways/paybox_direct.rb +207 -0
- data/lib/active_merchant/billing/gateways/payflow.rb +253 -0
- data/lib/active_merchant/billing/gateways/payflow/payflow_common_api.rb +207 -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 +222 -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 +235 -0
- data/lib/active_merchant/billing/gateways/paypal.rb +121 -0
- data/lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb +351 -0
- data/lib/active_merchant/billing/gateways/paypal/paypal_express_response.rb +49 -0
- data/lib/active_merchant/billing/gateways/paypal_ca.rb +13 -0
- data/lib/active_merchant/billing/gateways/paypal_express.rb +177 -0
- data/lib/active_merchant/billing/gateways/paypal_express_common.rb +25 -0
- data/lib/active_merchant/billing/gateways/plugnpay.rb +298 -0
- data/lib/active_merchant/billing/gateways/psigate.rb +219 -0
- data/lib/active_merchant/billing/gateways/psl_card.rb +304 -0
- data/lib/active_merchant/billing/gateways/qbms.rb +295 -0
- data/lib/active_merchant/billing/gateways/quantum.rb +282 -0
- data/lib/active_merchant/billing/gateways/quickpay.rb +218 -0
- data/lib/active_merchant/billing/gateways/realex.rb +311 -0
- data/lib/active_merchant/billing/gateways/sage.rb +146 -0
- data/lib/active_merchant/billing/gateways/sage/sage_bankcard.rb +88 -0
- data/lib/active_merchant/billing/gateways/sage/sage_core.rb +116 -0
- data/lib/active_merchant/billing/gateways/sage/sage_virtual_check.rb +97 -0
- data/lib/active_merchant/billing/gateways/sage_pay.rb +320 -0
- data/lib/active_merchant/billing/gateways/sallie_mae.rb +144 -0
- data/lib/active_merchant/billing/gateways/secure_net.rb +330 -0
- data/lib/active_merchant/billing/gateways/secure_pay.rb +31 -0
- data/lib/active_merchant/billing/gateways/secure_pay_au.rb +193 -0
- data/lib/active_merchant/billing/gateways/secure_pay_tech.rb +113 -0
- data/lib/active_merchant/billing/gateways/skip_jack.rb +453 -0
- data/lib/active_merchant/billing/gateways/smart_ps.rb +271 -0
- data/lib/active_merchant/billing/gateways/stripe.rb +212 -0
- data/lib/active_merchant/billing/gateways/trans_first.rb +127 -0
- data/lib/active_merchant/billing/gateways/transax.rb +25 -0
- data/lib/active_merchant/billing/gateways/trust_commerce.rb +423 -0
- data/lib/active_merchant/billing/gateways/usa_epay.rb +194 -0
- data/lib/active_merchant/billing/gateways/verifi.rb +233 -0
- data/lib/active_merchant/billing/gateways/viaklix.rb +189 -0
- data/lib/active_merchant/billing/gateways/wirecard.rb +318 -0
- data/lib/active_merchant/billing/gateways/worldpay.rb +280 -0
- data/lib/active_merchant/billing/integrations.rb +17 -0
- data/lib/active_merchant/billing/integrations/action_view_helper.rb +68 -0
- data/lib/active_merchant/billing/integrations/bogus.rb +23 -0
- data/lib/active_merchant/billing/integrations/bogus/helper.rb +17 -0
- data/lib/active_merchant/billing/integrations/bogus/notification.rb +11 -0
- data/lib/active_merchant/billing/integrations/bogus/return.rb +10 -0
- data/lib/active_merchant/billing/integrations/chronopay.rb +23 -0
- data/lib/active_merchant/billing/integrations/chronopay/helper.rb +120 -0
- data/lib/active_merchant/billing/integrations/chronopay/notification.rb +158 -0
- data/lib/active_merchant/billing/integrations/chronopay/return.rb +10 -0
- data/lib/active_merchant/billing/integrations/direc_pay.rb +41 -0
- data/lib/active_merchant/billing/integrations/direc_pay/helper.rb +200 -0
- data/lib/active_merchant/billing/integrations/direc_pay/notification.rb +76 -0
- data/lib/active_merchant/billing/integrations/direc_pay/return.rb +32 -0
- data/lib/active_merchant/billing/integrations/direc_pay/status.rb +37 -0
- data/lib/active_merchant/billing/integrations/directebanking.rb +47 -0
- data/lib/active_merchant/billing/integrations/directebanking/helper.rb +90 -0
- data/lib/active_merchant/billing/integrations/directebanking/notification.rb +120 -0
- data/lib/active_merchant/billing/integrations/directebanking/return.rb +11 -0
- data/lib/active_merchant/billing/integrations/e_payment_plans.rb +48 -0
- data/lib/active_merchant/billing/integrations/e_payment_plans/helper.rb +34 -0
- data/lib/active_merchant/billing/integrations/e_payment_plans/notification.rb +84 -0
- data/lib/active_merchant/billing/integrations/gestpay.rb +25 -0
- data/lib/active_merchant/billing/integrations/gestpay/common.rb +42 -0
- data/lib/active_merchant/billing/integrations/gestpay/helper.rb +70 -0
- data/lib/active_merchant/billing/integrations/gestpay/notification.rb +85 -0
- data/lib/active_merchant/billing/integrations/gestpay/return.rb +10 -0
- data/lib/active_merchant/billing/integrations/helper.rb +96 -0
- data/lib/active_merchant/billing/integrations/hi_trust.rb +27 -0
- data/lib/active_merchant/billing/integrations/hi_trust/helper.rb +58 -0
- data/lib/active_merchant/billing/integrations/hi_trust/notification.rb +59 -0
- data/lib/active_merchant/billing/integrations/hi_trust/return.rb +67 -0
- data/lib/active_merchant/billing/integrations/moneybookers.rb +26 -0
- data/lib/active_merchant/billing/integrations/moneybookers/helper.rb +59 -0
- data/lib/active_merchant/billing/integrations/moneybookers/notification.rb +129 -0
- data/lib/active_merchant/billing/integrations/nochex.rb +88 -0
- data/lib/active_merchant/billing/integrations/nochex/helper.rb +68 -0
- data/lib/active_merchant/billing/integrations/nochex/notification.rb +94 -0
- data/lib/active_merchant/billing/integrations/nochex/return.rb +10 -0
- data/lib/active_merchant/billing/integrations/notification.rb +62 -0
- data/lib/active_merchant/billing/integrations/paypal.rb +39 -0
- data/lib/active_merchant/billing/integrations/paypal/helper.rb +119 -0
- data/lib/active_merchant/billing/integrations/paypal/notification.rb +154 -0
- data/lib/active_merchant/billing/integrations/paypal/return.rb +10 -0
- data/lib/active_merchant/billing/integrations/quickpay.rb +21 -0
- data/lib/active_merchant/billing/integrations/quickpay/helper.rb +72 -0
- data/lib/active_merchant/billing/integrations/quickpay/notification.rb +74 -0
- data/lib/active_merchant/billing/integrations/return.rb +42 -0
- data/lib/active_merchant/billing/integrations/sage_pay_form.rb +37 -0
- data/lib/active_merchant/billing/integrations/sage_pay_form/encryption.rb +33 -0
- data/lib/active_merchant/billing/integrations/sage_pay_form/helper.rb +111 -0
- data/lib/active_merchant/billing/integrations/sage_pay_form/notification.rb +210 -0
- data/lib/active_merchant/billing/integrations/sage_pay_form/return.rb +31 -0
- data/lib/active_merchant/billing/integrations/two_checkout.rb +23 -0
- data/lib/active_merchant/billing/integrations/two_checkout/helper.rb +59 -0
- data/lib/active_merchant/billing/integrations/two_checkout/notification.rb +114 -0
- data/lib/active_merchant/billing/integrations/two_checkout/return.rb +17 -0
- data/lib/active_merchant/billing/integrations/valitor.rb +33 -0
- data/lib/active_merchant/billing/integrations/valitor/helper.rb +86 -0
- data/lib/active_merchant/billing/integrations/valitor/notification.rb +13 -0
- data/lib/active_merchant/billing/integrations/valitor/response_fields.rb +97 -0
- data/lib/active_merchant/billing/integrations/valitor/return.rb +13 -0
- data/lib/active_merchant/billing/integrations/world_pay.rb +27 -0
- data/lib/active_merchant/billing/integrations/world_pay/helper.rb +100 -0
- data/lib/active_merchant/billing/integrations/world_pay/notification.rb +160 -0
- data/lib/active_merchant/billing/response.rb +32 -0
- data/lib/active_merchant/common.rb +14 -0
- data/lib/active_merchant/common/connection.rb +177 -0
- data/lib/active_merchant/common/country.rb +328 -0
- data/lib/active_merchant/common/error.rb +26 -0
- data/lib/active_merchant/common/post_data.rb +24 -0
- data/lib/active_merchant/common/posts_data.rb +63 -0
- data/lib/active_merchant/common/requires_parameters.rb +16 -0
- data/lib/active_merchant/common/utils.rb +22 -0
- data/lib/active_merchant/common/validateable.rb +81 -0
- data/lib/active_merchant/version.rb +3 -0
- data/lib/activemerchant.rb +1 -0
- data/lib/certs/cacert.pem +7815 -0
- data/lib/support/gateway_support.rb +58 -0
- data/lib/support/outbound_hosts.rb +25 -0
- metadata +276 -0
@@ -0,0 +1,321 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/orbital/orbital_soft_descriptors.rb'
|
2
|
+
require "rexml/document"
|
3
|
+
|
4
|
+
module ActiveMerchant #:nodoc:
|
5
|
+
module Billing #:nodoc:
|
6
|
+
# For more information on Orbital, visit the {integration center}[http://download.chasepaymentech.com]
|
7
|
+
#
|
8
|
+
# ==== Authentication Options
|
9
|
+
#
|
10
|
+
# The Orbital Gateway supports two methods of authenticating incoming requests:
|
11
|
+
# Source IP authentication and Connection Username/Password authentication
|
12
|
+
#
|
13
|
+
# In addition, these IP addresses/Connection Usernames must be affiliated with the Merchant IDs
|
14
|
+
# for which the client should be submitting transactions.
|
15
|
+
#
|
16
|
+
# This does allow Third Party Hosting service organizations presenting on behalf of other
|
17
|
+
# merchants to submit transactions. However, each time a new customer is added, the
|
18
|
+
# merchant or Third-Party hosting organization needs to ensure that the new Merchant IDs
|
19
|
+
# or Chain IDs are affiliated with the hosting companies IPs or Connection Usernames.
|
20
|
+
#
|
21
|
+
# If the merchant expects to have more than one merchant account with the Orbital
|
22
|
+
# Gateway, it should have its IP addresses/Connection Usernames affiliated at the Chain
|
23
|
+
# level hierarchy within the Orbital Gateway. Each time a new merchant ID is added, as
|
24
|
+
# long as it is placed within the same Chain, it will simply work. Otherwise, the additional
|
25
|
+
# MIDs will need to be affiliated with the merchant IPs or Connection Usernames respectively.
|
26
|
+
# For example, we generally affiliate all Salem accounts [BIN 000001] with
|
27
|
+
# their Company Number [formerly called MA #] number so all MIDs or Divisions under that
|
28
|
+
# Company will automatically be affiliated.
|
29
|
+
|
30
|
+
class OrbitalGateway < Gateway
|
31
|
+
API_VERSION = "4.6"
|
32
|
+
|
33
|
+
POST_HEADERS = {
|
34
|
+
"MIME-Version" => "1.0",
|
35
|
+
"Content-Type" => "Application/PTI46",
|
36
|
+
"Content-transfer-encoding" => "text",
|
37
|
+
"Request-number" => '1',
|
38
|
+
"Document-type" => "Request",
|
39
|
+
"Interface-Version" => "Ruby|ActiveMerchant|Proprietary Gateway"
|
40
|
+
}
|
41
|
+
|
42
|
+
SUCCESS, APPROVED = '0', '00'
|
43
|
+
|
44
|
+
class_attribute :primary_test_url, :secondary_test_url, :primary_live_url, :secondary_live_url
|
45
|
+
|
46
|
+
self.primary_test_url = "https://orbitalvar1.paymentech.net/authorize"
|
47
|
+
self.secondary_test_url = "https://orbitalvar2.paymentech.net/authorize"
|
48
|
+
|
49
|
+
self.primary_live_url = "https://orbital1.paymentech.net/authorize"
|
50
|
+
self.secondary_live_url = "https://orbital2.paymentech.net/authorize"
|
51
|
+
|
52
|
+
self.supported_countries = ["US", "CA"]
|
53
|
+
self.default_currency = "CAD"
|
54
|
+
self.supported_cardtypes = [:visa, :master, :american_express, :discover, :diners_club, :jcb]
|
55
|
+
|
56
|
+
self.display_name = 'Orbital Paymentech'
|
57
|
+
self.homepage_url = 'http://chasepaymentech.com/'
|
58
|
+
|
59
|
+
self.money_format = :cents
|
60
|
+
|
61
|
+
CURRENCY_CODES = {
|
62
|
+
"AUD" => '036',
|
63
|
+
"CAD" => '124',
|
64
|
+
"CZK" => '203',
|
65
|
+
"DKK" => '208',
|
66
|
+
"HKD" => '344',
|
67
|
+
"ICK" => '352',
|
68
|
+
"JPY" => '392',
|
69
|
+
"MXN" => '484',
|
70
|
+
"NZD" => '554',
|
71
|
+
"NOK" => '578',
|
72
|
+
"SGD" => '702',
|
73
|
+
"SEK" => '752',
|
74
|
+
"CHF" => '756',
|
75
|
+
"GBP" => '826',
|
76
|
+
"USD" => '840',
|
77
|
+
"EUR" => '978'
|
78
|
+
}
|
79
|
+
|
80
|
+
def initialize(options = {})
|
81
|
+
unless options[:ip_authentication] == true
|
82
|
+
requires!(options, :login, :password, :merchant_id)
|
83
|
+
@options = options
|
84
|
+
end
|
85
|
+
super
|
86
|
+
end
|
87
|
+
|
88
|
+
# A – Authorization request
|
89
|
+
def authorize(money, creditcard, options = {})
|
90
|
+
order = build_new_order_xml('A', money, options) do |xml|
|
91
|
+
add_creditcard(xml, creditcard, options[:currency])
|
92
|
+
add_address(xml, creditcard, options)
|
93
|
+
end
|
94
|
+
commit(order)
|
95
|
+
end
|
96
|
+
|
97
|
+
# AC – Authorization and Capture
|
98
|
+
def purchase(money, creditcard, options = {})
|
99
|
+
order = build_new_order_xml('AC', money, options) do |xml|
|
100
|
+
add_creditcard(xml, creditcard, options[:currency])
|
101
|
+
add_address(xml, creditcard, options)
|
102
|
+
end
|
103
|
+
commit(order)
|
104
|
+
end
|
105
|
+
|
106
|
+
# MFC - Mark For Capture
|
107
|
+
def capture(money, authorization, options = {})
|
108
|
+
commit(build_mark_for_capture_xml(money, authorization, options))
|
109
|
+
end
|
110
|
+
|
111
|
+
# R – Refund request
|
112
|
+
def refund(money, authorization, options = {})
|
113
|
+
order = build_new_order_xml('R', money, options.merge(:authorization => authorization)) do |xml|
|
114
|
+
add_refund(xml, options[:currency])
|
115
|
+
end
|
116
|
+
commit(order)
|
117
|
+
end
|
118
|
+
|
119
|
+
def credit(money, authorization, options= {})
|
120
|
+
deprecated CREDIT_DEPRECATION_MESSAGE
|
121
|
+
refund(money, authorization, options)
|
122
|
+
end
|
123
|
+
|
124
|
+
# setting money to nil will perform a full void
|
125
|
+
def void(money, authorization, options = {})
|
126
|
+
order = build_void_request_xml(money, authorization, options)
|
127
|
+
commit(order)
|
128
|
+
end
|
129
|
+
|
130
|
+
private
|
131
|
+
|
132
|
+
def add_customer_data(xml, options)
|
133
|
+
if options[:customer_ref_num]
|
134
|
+
xml.tag! :CustomerProfileFromOrderInd, 'S'
|
135
|
+
xml.tag! :CustomerRefNum, options[:customer_ref_num]
|
136
|
+
else
|
137
|
+
xml.tag! :CustomerProfileFromOrderInd, 'A'
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
def add_soft_descriptors(xml, soft_desc)
|
142
|
+
xml.tag! :SDMerchantName, soft_desc.merchant_name
|
143
|
+
xml.tag! :SDProductDescription, soft_desc.product_description
|
144
|
+
xml.tag! :SDMerchantCity, soft_desc.merchant_city
|
145
|
+
xml.tag! :SDMerchantPhone, soft_desc.merchant_phone
|
146
|
+
xml.tag! :SDMerchantURL, soft_desc.merchant_url
|
147
|
+
xml.tag! :SDMerchantEmail, soft_desc.merchant_email
|
148
|
+
end
|
149
|
+
|
150
|
+
def add_address(xml, creditcard, options)
|
151
|
+
if address = options[:billing_address] || options[:address]
|
152
|
+
xml.tag! :AVSzip, address[:zip]
|
153
|
+
xml.tag! :AVSaddress1, address[:address1]
|
154
|
+
xml.tag! :AVSaddress2, address[:address2]
|
155
|
+
xml.tag! :AVScity, address[:city]
|
156
|
+
xml.tag! :AVSstate, address[:state]
|
157
|
+
xml.tag! :AVSphoneNum, address[:phone] ? address[:phone].scan(/\d/).to_s : nil
|
158
|
+
xml.tag! :AVSname, creditcard.name
|
159
|
+
xml.tag! :AVScountryCode, address[:country]
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
def add_creditcard(xml, creditcard, currency=nil)
|
164
|
+
xml.tag! :AccountNum, creditcard.number
|
165
|
+
xml.tag! :Exp, expiry_date(creditcard)
|
166
|
+
|
167
|
+
xml.tag! :CurrencyCode, currency_code(currency)
|
168
|
+
xml.tag! :CurrencyExponent, '2' # Will need updating to support currencies such as the Yen.
|
169
|
+
|
170
|
+
xml.tag! :CardSecVal, creditcard.verification_value if creditcard.verification_value?
|
171
|
+
end
|
172
|
+
|
173
|
+
def add_refund(xml, currency=nil)
|
174
|
+
xml.tag! :AccountNum, nil
|
175
|
+
|
176
|
+
xml.tag! :CurrencyCode, currency_code(currency)
|
177
|
+
xml.tag! :CurrencyExponent, '2' # Will need updating to support currencies such as the Yen.
|
178
|
+
end
|
179
|
+
|
180
|
+
def parse(body)
|
181
|
+
response = {}
|
182
|
+
xml = REXML::Document.new(body)
|
183
|
+
root = REXML::XPath.first(xml, "//Response") ||
|
184
|
+
REXML::XPath.first(xml, "//ErrorResponse")
|
185
|
+
if root
|
186
|
+
root.elements.to_a.each do |node|
|
187
|
+
recurring_parse_element(response, node)
|
188
|
+
end
|
189
|
+
end
|
190
|
+
response
|
191
|
+
end
|
192
|
+
|
193
|
+
def recurring_parse_element(response, node)
|
194
|
+
if node.has_elements?
|
195
|
+
node.elements.each{|e| recurring_parse_element(response, e) }
|
196
|
+
else
|
197
|
+
response[node.name.underscore.to_sym] = node.text
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
def commit(order)
|
202
|
+
headers = POST_HEADERS.merge("Content-length" => order.size.to_s)
|
203
|
+
request = lambda {return parse(ssl_post(remote_url, order, headers))}
|
204
|
+
|
205
|
+
# Failover URL will be used in the event of a connection error
|
206
|
+
begin response = request.call; rescue ConnectionError; retry end
|
207
|
+
|
208
|
+
Response.new(success?(response), message_from(response), response,
|
209
|
+
{:authorization => "#{response[:tx_ref_num]};#{response[:order_id]}",
|
210
|
+
:test => self.test?,
|
211
|
+
:avs_result => {:code => response[:avs_resp_code]},
|
212
|
+
:cvv_result => response[:cvv2_resp_code]
|
213
|
+
}
|
214
|
+
)
|
215
|
+
end
|
216
|
+
|
217
|
+
def remote_url
|
218
|
+
unless $!.class == ActiveMerchant::ConnectionError
|
219
|
+
self.test? ? self.primary_test_url : self.primary_live_url
|
220
|
+
else
|
221
|
+
self.test? ? self.secondary_test_url : self.secondary_live_url
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
def success?(response)
|
226
|
+
if response[:message_type] == "R"
|
227
|
+
response[:proc_status] == SUCCESS
|
228
|
+
else
|
229
|
+
response[:proc_status] == SUCCESS &&
|
230
|
+
response[:resp_code] == APPROVED
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
def message_from(response)
|
235
|
+
success?(response) ? 'APPROVED' : response[:resp_msg] || response[:status_msg]
|
236
|
+
end
|
237
|
+
|
238
|
+
def ip_authentication?
|
239
|
+
@options[:ip_authentication] == true
|
240
|
+
end
|
241
|
+
|
242
|
+
def build_new_order_xml(action, money, parameters = {})
|
243
|
+
requires!(parameters, :order_id)
|
244
|
+
xml = Builder::XmlMarkup.new(:indent => 2)
|
245
|
+
xml.instruct!(:xml, :version => '1.0', :encoding => 'UTF-8')
|
246
|
+
xml.tag! :Request do
|
247
|
+
xml.tag! :NewOrder do
|
248
|
+
xml.tag! :OrbitalConnectionUsername, @options[:login] unless ip_authentication?
|
249
|
+
xml.tag! :OrbitalConnectionPassword, @options[:password] unless ip_authentication?
|
250
|
+
xml.tag! :IndustryType, "EC" # E-Commerce transaction
|
251
|
+
xml.tag! :MessageType, action
|
252
|
+
xml.tag! :BIN, '000002' # PNS Tampa
|
253
|
+
xml.tag! :MerchantID, @options[:merchant_id]
|
254
|
+
xml.tag! :TerminalID, parameters[:terminal_id] || '001'
|
255
|
+
|
256
|
+
yield xml if block_given?
|
257
|
+
|
258
|
+
xml.tag! :Comments, parameters[:comments] if parameters[:comments]
|
259
|
+
xml.tag! :OrderID, parameters[:order_id].to_s[0...22]
|
260
|
+
xml.tag! :Amount, amount(money)
|
261
|
+
|
262
|
+
# Append Transaction Reference Number at the end for Refund transactions
|
263
|
+
if action == "R"
|
264
|
+
tx_ref_num, _ = parameters[:authorization].split(';')
|
265
|
+
xml.tag! :TxRefNum, tx_ref_num
|
266
|
+
end
|
267
|
+
end
|
268
|
+
end
|
269
|
+
xml.target!
|
270
|
+
end
|
271
|
+
|
272
|
+
def build_mark_for_capture_xml(money, authorization, parameters = {})
|
273
|
+
tx_ref_num, order_id = authorization.split(';')
|
274
|
+
xml = Builder::XmlMarkup.new(:indent => 2)
|
275
|
+
xml.instruct!(:xml, :version => '1.0', :encoding => 'UTF-8')
|
276
|
+
xml.tag! :Request do
|
277
|
+
xml.tag! :MarkForCapture do
|
278
|
+
xml.tag! :OrbitalConnectionUsername, @options[:login] unless ip_authentication?
|
279
|
+
xml.tag! :OrbitalConnectionPassword, @options[:password] unless ip_authentication?
|
280
|
+
xml.tag! :OrderID, order_id
|
281
|
+
xml.tag! :Amount, amount(money)
|
282
|
+
xml.tag! :BIN, '000002' # PNS Tampa
|
283
|
+
xml.tag! :MerchantID, @options[:merchant_id]
|
284
|
+
xml.tag! :TerminalID, parameters[:terminal_id] || '001'
|
285
|
+
xml.tag! :TxRefNum, tx_ref_num
|
286
|
+
end
|
287
|
+
end
|
288
|
+
xml.target!
|
289
|
+
end
|
290
|
+
|
291
|
+
def build_void_request_xml(money, authorization, parameters = {})
|
292
|
+
requires!(parameters, :transaction_index)
|
293
|
+
tx_ref_num, order_id = authorization.split(';')
|
294
|
+
xml = Builder::XmlMarkup.new(:indent => 2)
|
295
|
+
xml.instruct!(:xml, :version => '1.0', :encoding => 'UTF-8')
|
296
|
+
xml.tag! :Request do
|
297
|
+
xml.tag! :Reversal do
|
298
|
+
xml.tag! :OrbitalConnectionUsername, @options[:login] unless ip_authentication?
|
299
|
+
xml.tag! :OrbitalConnectionPassword, @options[:password] unless ip_authentication?
|
300
|
+
xml.tag! :TxRefNum, tx_ref_num
|
301
|
+
xml.tag! :TxRefIdx, parameters[:transaction_index]
|
302
|
+
xml.tag! :AdjustedAmt, amount(money)
|
303
|
+
xml.tag! :OrderID, order_id
|
304
|
+
xml.tag! :BIN, '000002' # PNS Tampa
|
305
|
+
xml.tag! :MerchantID, @options[:merchant_id]
|
306
|
+
xml.tag! :TerminalID, parameters[:terminal_id] || '001'
|
307
|
+
end
|
308
|
+
end
|
309
|
+
xml.target!
|
310
|
+
end
|
311
|
+
|
312
|
+
def currency_code(currency)
|
313
|
+
CURRENCY_CODES[(currency || self.default_currency)].to_s
|
314
|
+
end
|
315
|
+
|
316
|
+
def expiry_date(credit_card)
|
317
|
+
"#{format(credit_card.month, :two_digits)}#{format(credit_card.year, :two_digits)}"
|
318
|
+
end
|
319
|
+
end
|
320
|
+
end
|
321
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module ActiveMerchant #:nodoc:
|
2
|
+
module Billing #:nodoc:
|
3
|
+
class OrbitalSoftDescriptors
|
4
|
+
include Validateable
|
5
|
+
|
6
|
+
PHONE_FORMAT_1 = /\A\d{3}-\d{3}-\d{4}\z/
|
7
|
+
PHONE_FORMAT_2 = /\A\d{3}-\w{7}\z/
|
8
|
+
|
9
|
+
# ==== Tampa PNS Soft Descriptors
|
10
|
+
# The support for Soft Descriptors via the PNS Host is only for customers processing through Chase
|
11
|
+
# Paymentech Canada.
|
12
|
+
|
13
|
+
# Unlike Salem, the only value that gets passed on the cardholder statement is the Merchant Name field.
|
14
|
+
# And for these customers, it is a maximum of 25 bytes of data.
|
15
|
+
#
|
16
|
+
# All other Soft Descriptor fields can optionally be sent, but will not be submitted to the settlement host
|
17
|
+
# and will not display on the cardholder statement.
|
18
|
+
|
19
|
+
attr_accessor :merchant_name, :product_description, :merchant_city, :merchant_phone, :merchant_url, :merchant_email
|
20
|
+
|
21
|
+
def initialize(options = {})
|
22
|
+
self.merchant_name = options[:merchant_name]
|
23
|
+
self.merchant_city = options[:merchant_city]
|
24
|
+
self.merchant_phone = options[:merchant_phone]
|
25
|
+
self.merchant_url = options[:merchant_url]
|
26
|
+
self.merchant_email = options[:merchant_email]
|
27
|
+
end
|
28
|
+
|
29
|
+
def validate
|
30
|
+
errors.add(:merchant_name, "is required") if self.merchant_name.blank?
|
31
|
+
errors.add(:merchant_name, "is required to be 25 bytes or less") if self.merchant_name.bytesize > 25
|
32
|
+
|
33
|
+
unless self.merchant_phone.blank? || self.merchant_phone.match(PHONE_FORMAT_1) || self.merchant_phone.match(PHONE_FORMAT_2)
|
34
|
+
errors.add(:merchant_phone, "is required to follow \"NNN-NNN-NNNN\" or \"NNN-AAAAAAA\" format")
|
35
|
+
end
|
36
|
+
|
37
|
+
[:merchant_email, :merchant_url].each do |attr|
|
38
|
+
unless self.send(attr).blank?
|
39
|
+
errors.add(attr, "is required to be 13 bytes or less") if self.send(attr).bytesize > 13
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,392 @@
|
|
1
|
+
module ActiveMerchant #:nodoc:
|
2
|
+
module Billing #:nodoc:
|
3
|
+
# PayJunction Gateway
|
4
|
+
#
|
5
|
+
# This gateway accepts the following arguments:
|
6
|
+
# :login => your PayJunction username
|
7
|
+
# :password => your PayJunction pass
|
8
|
+
#
|
9
|
+
# Example use:
|
10
|
+
#
|
11
|
+
# gateway = ActiveMerchant::Billing::Base.gateway(:pay_junction).new(
|
12
|
+
# :login => "my_account",
|
13
|
+
# :password => "my_pass"
|
14
|
+
# )
|
15
|
+
#
|
16
|
+
# # set up credit card obj as in main ActiveMerchant example
|
17
|
+
# creditcard = ActiveMerchant::Billing::CreditCard.new(
|
18
|
+
# :type => 'visa',
|
19
|
+
# :number => '4242424242424242',
|
20
|
+
# :month => 8,
|
21
|
+
# :year => 2009,
|
22
|
+
# :first_name => 'Bob',
|
23
|
+
# :last_name => 'Bobsen'
|
24
|
+
# )
|
25
|
+
#
|
26
|
+
# # optionally specify address if using AVS
|
27
|
+
# address = { :address1 => '101 Test Ave', :city => 'Test', :state => 'TS',
|
28
|
+
# :zip => '10101', :country => 'US' }
|
29
|
+
#
|
30
|
+
# # run request
|
31
|
+
# response = gateway.purchase(1000, creditcard, :address => address) # charge 10 dollars
|
32
|
+
#
|
33
|
+
# 1) Check whether the transaction was successful
|
34
|
+
#
|
35
|
+
# response.success?
|
36
|
+
#
|
37
|
+
# 2) Retrieve the message returned by PayJunction
|
38
|
+
#
|
39
|
+
# response.message
|
40
|
+
#
|
41
|
+
# 3) Retrieve the unique transaction ID returned by PayJunction
|
42
|
+
#
|
43
|
+
# response.authorization
|
44
|
+
#
|
45
|
+
# This gateway supports "instant" transactions. These transactions allow you
|
46
|
+
# to execute an operation on a previously run card without card information
|
47
|
+
# provided you have the transaction id from a previous transaction with the
|
48
|
+
# same card. All functions that take a credit card object for this gateway
|
49
|
+
# can take a transaction id string instead.
|
50
|
+
#
|
51
|
+
# Test Transactions
|
52
|
+
#
|
53
|
+
# See the source for initialize() for test account information. Note that
|
54
|
+
# PayJunction does not allow test transactions on your account, so if the
|
55
|
+
# gateway is running in :test mode your transaction will be run against
|
56
|
+
# PayJunction's global test account and will not show up in your account.
|
57
|
+
#
|
58
|
+
# Transactions ran on this account go through a test processor, so there is no
|
59
|
+
# need to void or otherwise cancel transactions. However, for further safety,
|
60
|
+
# please use the special card numbers 4433221111223344 or 4444333322221111 and
|
61
|
+
# keep transaction amounts below $4.00 when testing.
|
62
|
+
#
|
63
|
+
# Also note, transactions ran for an amount between $0.00 and $1.99 will likely
|
64
|
+
# result in denial. To demonstrate approvals, use amounts between $2.00 and $4.00.
|
65
|
+
#
|
66
|
+
# Test transactions can be checked by logging into
|
67
|
+
# PayJunction Web Login with username 'pj-cm-01' and password 'pj-cm-01p'
|
68
|
+
#
|
69
|
+
# Usage Details
|
70
|
+
#
|
71
|
+
# Below is a map of values accepted by PayJunction and how you should submit
|
72
|
+
# each to ActiveMerchant
|
73
|
+
#
|
74
|
+
# PayJunction Field ActiveMerchant Use
|
75
|
+
#
|
76
|
+
# dc_logon provide as :login value to gateway instantation
|
77
|
+
# dc_password provide as :password value to gateway instantiation
|
78
|
+
#
|
79
|
+
# dc_name will be retrieved from credit_card.name
|
80
|
+
# dc_first_name :first_name on CreditCard object instantation
|
81
|
+
# dc_last_name :last_name on CreditCard object instantation
|
82
|
+
# dc_number :number on CreditCard object instantation
|
83
|
+
# dc_expiration_month :month on CreditCard object instantation
|
84
|
+
# dc_expiration_year :year on CreditCard object instantation
|
85
|
+
# dc_verification_number :verification_value on CC object instantation
|
86
|
+
#
|
87
|
+
# dc_transaction_amount include as argument to method for your transaction type
|
88
|
+
# dc_transaction_type do nothing, set by your transaction type
|
89
|
+
# dc_version do nothing, always "1.2"
|
90
|
+
#
|
91
|
+
# dc_transaction_id submit as a string in place of CreditCard obj for
|
92
|
+
# "instant" transactions.
|
93
|
+
#
|
94
|
+
# dc_invoice :order_id in options for transaction method
|
95
|
+
# dc_notes :description in options for transaction method
|
96
|
+
#
|
97
|
+
# See example use above for address AVS fields
|
98
|
+
# See #recurring for periodic transaction fields
|
99
|
+
class PayJunctionGateway < Gateway
|
100
|
+
API_VERSION = '1.2'
|
101
|
+
|
102
|
+
class_attribute :test_url, :live_url
|
103
|
+
|
104
|
+
self.test_url = "https://www.payjunctionlabs.com/quick_link"
|
105
|
+
self.live_url = "https://payjunction.com/quick_link"
|
106
|
+
|
107
|
+
TEST_LOGIN = 'pj-ql-01'
|
108
|
+
TEST_PASSWORD = 'pj-ql-01p'
|
109
|
+
|
110
|
+
SUCCESS_CODES = ["00", "85"]
|
111
|
+
SUCCESS_MESSAGE = 'The transaction was approved.'
|
112
|
+
|
113
|
+
FAILURE_MESSAGE = 'The transaction was declined.'
|
114
|
+
|
115
|
+
DECLINE_CODES = {
|
116
|
+
"AE" => 'Address verification failed because address did not match.',
|
117
|
+
'ZE' => 'Address verification failed because zip did not match.',
|
118
|
+
'XE' => 'Address verification failed because zip and address did not match.',
|
119
|
+
'YE' => 'Address verification failed because zip and address did not match.',
|
120
|
+
'OE' => 'Address verification failed because address or zip did not match.',
|
121
|
+
'UE' => 'Address verification failed because cardholder address unavailable.',
|
122
|
+
'RE' => 'Address verification failed because address verification system is not working.',
|
123
|
+
'SE' => 'Address verification failed because address verification system is unavailable.',
|
124
|
+
'EE' => 'Address verification failed because transaction is not a mail or phone order.',
|
125
|
+
'GE' => 'Address verification failed because international support is unavailable.',
|
126
|
+
'CE' => 'Declined because CVV2/CVC2 code did not match.',
|
127
|
+
'04' => 'Declined. Pick up card.',
|
128
|
+
'07' => 'Declined. Pick up card (Special Condition).',
|
129
|
+
'41' => 'Declined. Pick up card (Lost).',
|
130
|
+
'43' => 'Declined. Pick up card (Stolen).',
|
131
|
+
'13' => 'Declined because of the amount is invalid.',
|
132
|
+
'14' => 'Declined because the card number is invalid.',
|
133
|
+
'80' => 'Declined because of an invalid date.',
|
134
|
+
'05' => 'Declined. Do not honor.',
|
135
|
+
'51' => 'Declined because of insufficient funds.',
|
136
|
+
'N4' => 'Declined because the amount exceeds issuer withdrawal limit.',
|
137
|
+
'61' => 'Declined because the amount exceeds withdrawal limit.',
|
138
|
+
'62' => 'Declined because of an invalid service code (restricted).',
|
139
|
+
'65' => 'Declined because the card activity limit exceeded.',
|
140
|
+
'93' => 'Declined because there a violation (the transaction could not be completed).',
|
141
|
+
'06' => 'Declined because address verification failed.',
|
142
|
+
'54' => 'Declined because the card has expired.',
|
143
|
+
'15' => 'Declined because there is no such issuer.',
|
144
|
+
'96' => 'Declined because of a system error.',
|
145
|
+
'N7' => 'Declined because of a CVV2/CVC2 mismatch.',
|
146
|
+
'M4' => 'Declined.',
|
147
|
+
"FE" => "There was a format error with your Trinity Gateway Service (API) request.",
|
148
|
+
"LE" => "Could not log you in (problem with dc_logon and/or dc_password).",
|
149
|
+
'NL' => 'Aborted because of a system error, please try again later. ',
|
150
|
+
'AB' => 'Aborted because of an upstream system error, please try again later.'
|
151
|
+
}
|
152
|
+
|
153
|
+
self.supported_cardtypes = [:visa, :master, :american_express, :discover]
|
154
|
+
self.supported_countries = ['US']
|
155
|
+
self.homepage_url = 'http://www.payjunction.com/'
|
156
|
+
self.display_name = 'PayJunction'
|
157
|
+
|
158
|
+
def initialize(options = {})
|
159
|
+
requires!(options, :login, :password)
|
160
|
+
@options = options
|
161
|
+
super
|
162
|
+
end
|
163
|
+
|
164
|
+
# The first half of the preauth(authorize)/postauth(capture) model.
|
165
|
+
# Checks to make sure funds are available for a transaction, and returns a
|
166
|
+
# transaction_id that can be used later to postauthorize (capture) the funds.
|
167
|
+
def authorize(money, payment_source, options = {})
|
168
|
+
parameters = {
|
169
|
+
:transaction_amount => amount(money),
|
170
|
+
}
|
171
|
+
|
172
|
+
add_payment_source(parameters, payment_source)
|
173
|
+
add_address(parameters, options)
|
174
|
+
add_optional_fields(parameters, options)
|
175
|
+
commit('AUTHORIZATION', parameters)
|
176
|
+
end
|
177
|
+
|
178
|
+
# A simple sale, capturing funds immediately.
|
179
|
+
# Execute authorization and capture in a single step.
|
180
|
+
def purchase(money, payment_source, options = {})
|
181
|
+
parameters = {
|
182
|
+
:transaction_amount => amount(money),
|
183
|
+
}
|
184
|
+
|
185
|
+
add_payment_source(parameters, payment_source)
|
186
|
+
add_address(parameters, options)
|
187
|
+
add_optional_fields(parameters, options)
|
188
|
+
commit('AUTHORIZATION_CAPTURE', parameters)
|
189
|
+
end
|
190
|
+
|
191
|
+
# The second half of the preauth(authorize)/postauth(capture) model.
|
192
|
+
# Retrieve funds that have been previously authorized with _authorization_
|
193
|
+
def capture(money, authorization, options = {})
|
194
|
+
parameters = {
|
195
|
+
:transaction_id => authorization,
|
196
|
+
:posture => 'capture'
|
197
|
+
}
|
198
|
+
|
199
|
+
add_optional_fields(parameters, options)
|
200
|
+
commit('update', parameters)
|
201
|
+
end
|
202
|
+
|
203
|
+
# Return money to a card that was previously billed.
|
204
|
+
# _authorization_ should be the transaction id of the transaction we are returning.
|
205
|
+
def credit(money, authorization, options = {})
|
206
|
+
parameters = {
|
207
|
+
:transaction_amount => amount(money),
|
208
|
+
:transaction_id => authorization
|
209
|
+
}
|
210
|
+
|
211
|
+
commit('CREDIT', parameters)
|
212
|
+
end
|
213
|
+
|
214
|
+
# Cancel a transaction that has been charged but has not yet made it
|
215
|
+
# through the batch process.
|
216
|
+
def void(authorization, options = {})
|
217
|
+
parameters = {
|
218
|
+
:transaction_id => authorization,
|
219
|
+
:posture => 'void'
|
220
|
+
}
|
221
|
+
|
222
|
+
add_optional_fields(parameters, options)
|
223
|
+
commit('update', parameters)
|
224
|
+
end
|
225
|
+
|
226
|
+
# Set up a sale that will be made on a regular basis for the same amount
|
227
|
+
# (ex. $20 a month for 12 months)
|
228
|
+
#
|
229
|
+
# The parameter :periodicity should be specified as either :monthly, :weekly, or :daily
|
230
|
+
# The parameter :payments should be the number of payments to be made
|
231
|
+
#
|
232
|
+
# gateway.recurring('2000', creditcard, :periodicity => :monthly, :payments => 12)
|
233
|
+
#
|
234
|
+
# The optional parameter :starting_at takes a date or time argument or a string in
|
235
|
+
# YYYYMMDD format and can be used to specify when the first charge will be made.
|
236
|
+
# If omitted the first charge will be immediate.
|
237
|
+
def recurring(money, payment_source, options = {})
|
238
|
+
requires!(options, [:periodicity, :monthly, :weekly, :daily], :payments)
|
239
|
+
|
240
|
+
periodic_type = case options[:periodicity]
|
241
|
+
when :monthly
|
242
|
+
'month'
|
243
|
+
when :weekly
|
244
|
+
'week'
|
245
|
+
when :daily
|
246
|
+
'day'
|
247
|
+
end
|
248
|
+
|
249
|
+
if options[:starting_at].nil?
|
250
|
+
start_date = Time.now.strftime('%Y-%m-%d')
|
251
|
+
elsif options[:starting_at].is_a?(String)
|
252
|
+
sa = options[:starting_at]
|
253
|
+
start_date = "#{sa[0..3]}-#{sa[4..5]}-#{sa[6..7]}"
|
254
|
+
else
|
255
|
+
start_date = options[:starting_at].strftime('%Y-%m-%d')
|
256
|
+
end
|
257
|
+
|
258
|
+
parameters = {
|
259
|
+
:transaction_amount => amount(money),
|
260
|
+
:schedule_periodic_type => periodic_type,
|
261
|
+
:schedule_create => 'true',
|
262
|
+
:schedule_limit => options[:payments].to_i > 1 ? options[:payments] : 1,
|
263
|
+
:schedule_periodic_number => 1,
|
264
|
+
:schedule_start => start_date
|
265
|
+
}
|
266
|
+
|
267
|
+
add_payment_source(parameters, payment_source)
|
268
|
+
add_optional_fields(parameters, options)
|
269
|
+
add_address(parameters, options)
|
270
|
+
commit('AUTHORIZATION_CAPTURE', parameters)
|
271
|
+
end
|
272
|
+
|
273
|
+
def test?
|
274
|
+
test_login? || @options[:test] || super
|
275
|
+
end
|
276
|
+
|
277
|
+
private
|
278
|
+
|
279
|
+
def test_login?
|
280
|
+
@options[:login] == TEST_LOGIN && @options[:password] == TEST_PASSWORD
|
281
|
+
end
|
282
|
+
|
283
|
+
# add fields depending on payment source selected (cc or transaction id)
|
284
|
+
def add_payment_source(params, source)
|
285
|
+
if source.is_a?(String)
|
286
|
+
add_billing_id(params, source)
|
287
|
+
else
|
288
|
+
add_creditcard(params, source)
|
289
|
+
end
|
290
|
+
end
|
291
|
+
|
292
|
+
# add fields for credit card
|
293
|
+
def add_creditcard(params, creditcard)
|
294
|
+
params[:name] = creditcard.name
|
295
|
+
params[:number] = creditcard.number
|
296
|
+
params[:expiration_month] = creditcard.month
|
297
|
+
params[:expiration_year] = creditcard.year
|
298
|
+
params[:verification_number] = creditcard.verification_value if creditcard.verification_value?
|
299
|
+
end
|
300
|
+
|
301
|
+
# add field for "instant" transaction, using previous transaction id
|
302
|
+
def add_billing_id(params, billingid)
|
303
|
+
params[:transaction_id] = billingid
|
304
|
+
end
|
305
|
+
|
306
|
+
# add address fields if present
|
307
|
+
def add_address(params, options)
|
308
|
+
address = options[:billing_address] || options[:address]
|
309
|
+
|
310
|
+
if address
|
311
|
+
params[:address] = address[:address1] unless address[:address1].blank?
|
312
|
+
params[:city] = address[:city] unless address[:city].blank?
|
313
|
+
params[:state] = address[:state] unless address[:state].blank?
|
314
|
+
params[:zipcode] = address[:zip] unless address[:zip].blank?
|
315
|
+
params[:country] = address[:country] unless address[:country].blank?
|
316
|
+
end
|
317
|
+
end
|
318
|
+
|
319
|
+
def add_optional_fields(params, options)
|
320
|
+
params[:notes] = options[:description] unless options[:description].blank?
|
321
|
+
params[:invoice] = options[:order_id].to_s.gsub(/[^-\/\w.,']/, '') unless options[:order_id].blank?
|
322
|
+
end
|
323
|
+
|
324
|
+
def commit(action, parameters)
|
325
|
+
url = test? ? self.test_url : self.live_url
|
326
|
+
|
327
|
+
response = parse( ssl_post(url, post_data(action, parameters)) )
|
328
|
+
|
329
|
+
Response.new(successful?(response), message_from(response), response,
|
330
|
+
:test => test?,
|
331
|
+
:authorization => response[:transaction_id] || parameters[:transaction_id]
|
332
|
+
)
|
333
|
+
end
|
334
|
+
|
335
|
+
def successful?(response)
|
336
|
+
SUCCESS_CODES.include?(response[:response_code]) || response[:query_status] == true
|
337
|
+
end
|
338
|
+
|
339
|
+
def message_from(response)
|
340
|
+
if successful?(response)
|
341
|
+
SUCCESS_MESSAGE
|
342
|
+
else
|
343
|
+
DECLINE_CODES[response[:response_code]] || FAILURE_MESSAGE
|
344
|
+
end
|
345
|
+
end
|
346
|
+
|
347
|
+
def post_data(action, params)
|
348
|
+
if test?
|
349
|
+
# test requests must use global test account
|
350
|
+
params[:logon] = TEST_LOGIN
|
351
|
+
params[:password] = TEST_PASSWORD
|
352
|
+
else
|
353
|
+
params[:logon] = @options[:login]
|
354
|
+
params[:password] = @options[:password]
|
355
|
+
end
|
356
|
+
params[:version] = API_VERSION
|
357
|
+
params[:transaction_type] = action
|
358
|
+
|
359
|
+
params.reject{|k,v| v.blank?}.collect{ |k, v| "dc_#{k.to_s}=#{CGI.escape(v.to_s)}" }.join("&")
|
360
|
+
end
|
361
|
+
|
362
|
+
def parse(body)
|
363
|
+
# PayJunction uses the Field Separator ASCII character to separate key/val
|
364
|
+
# pairs in the response. The <FS> character's octal value is 034.
|
365
|
+
#
|
366
|
+
# Sample response:
|
367
|
+
#
|
368
|
+
# transaction_id=44752<FS>response_code=M4<FS>response_message=Declined (INV TEST CARD).
|
369
|
+
|
370
|
+
pairs = body.chomp.split("\034")
|
371
|
+
response = {}
|
372
|
+
pairs.each do |pair|
|
373
|
+
key, val = pair.split('=')
|
374
|
+
response[key[3..-1].to_sym] = val ? normalize(val) : nil
|
375
|
+
end
|
376
|
+
response
|
377
|
+
end
|
378
|
+
|
379
|
+
# Make a ruby type out of the response string
|
380
|
+
def normalize(field)
|
381
|
+
case field
|
382
|
+
when "true" then true
|
383
|
+
when "false" then false
|
384
|
+
when "" then nil
|
385
|
+
when "null" then nil
|
386
|
+
else field
|
387
|
+
end
|
388
|
+
end
|
389
|
+
|
390
|
+
end
|
391
|
+
end
|
392
|
+
end
|