fishman-activemerchant 1.18.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 +733 -0
- data/CONTRIBUTORS +257 -0
- data/MIT-LICENSE +20 -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 +260 -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 +693 -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 +142 -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 +303 -0
- data/lib/active_merchant/billing/gateways/braintree_orange.rb +17 -0
- data/lib/active_merchant/billing/gateways/card_save.rb +23 -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 +274 -0
- data/lib/active_merchant/billing/gateways/eway.rb +277 -0
- data/lib/active_merchant/billing/gateways/eway_managed.rb +264 -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/optimal_payment.rb +274 -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 +354 -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 +184 -0
- data/lib/active_merchant/billing/gateways/paypal_express_common.rb +25 -0
- data/lib/active_merchant/billing/gateways/paypal_express_de.rb +14 -0
- data/lib/active_merchant/billing/gateways/paystation.rb +201 -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 +297 -0
- data/lib/active_merchant/billing/gateways/quantum.rb +282 -0
- data/lib/active_merchant/billing/gateways/quickpay.rb +297 -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/dwolla.rb +30 -0
- data/lib/active_merchant/billing/integrations/dwolla/helper.rb +28 -0
- data/lib/active_merchant/billing/integrations/dwolla/notification.rb +50 -0
- data/lib/active_merchant/billing/integrations/dwolla/return.rb +38 -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/payflow_link.rb +21 -0
- data/lib/active_merchant/billing/integrations/payflow_link/helper.rb +58 -0
- data/lib/active_merchant/billing/integrations/payflow_link/notification.rb +78 -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/version.rb +3 -0
- data/lib/activemerchant.rb +1 -0
- data/lib/support/gateway_support.rb +58 -0
- data/lib/support/outbound_hosts.rb +25 -0
- metadata +335 -0
@@ -0,0 +1,274 @@
|
|
1
|
+
module ActiveMerchant #:nodoc:
|
2
|
+
module Billing #:nodoc:
|
3
|
+
class OptimalPaymentGateway < Gateway
|
4
|
+
TEST_URL = 'https://webservices.test.optimalpayments.com/creditcardWS/CreditCardServlet/v1'
|
5
|
+
LIVE_URL = 'https://webservices.optimalpayments.com/creditcardWS/CreditCardServlet/v1'
|
6
|
+
|
7
|
+
# The countries the gateway supports merchants from as 2 digit ISO country codes
|
8
|
+
self.supported_countries = ['CA', 'US', 'GB']
|
9
|
+
|
10
|
+
# The card types supported by the payment gateway
|
11
|
+
self.supported_cardtypes = [:visa, :master, :american_express, :discover, :diners_club, :solo] # :switch?
|
12
|
+
|
13
|
+
# The homepage URL of the gateway
|
14
|
+
self.homepage_url = 'http://www.optimalpayments.com/'
|
15
|
+
|
16
|
+
# The name of the gateway
|
17
|
+
self.display_name = 'Optimal Payments'
|
18
|
+
|
19
|
+
def initialize(options = {})
|
20
|
+
#requires!(options, :login, :password)
|
21
|
+
@options = options
|
22
|
+
super
|
23
|
+
end
|
24
|
+
|
25
|
+
def authorize(money, card_or_auth, options = {})
|
26
|
+
parse_card_or_auth(card_or_auth, options)
|
27
|
+
commit("cc#{@stored_data}Authorize", money, options)
|
28
|
+
end
|
29
|
+
alias stored_authorize authorize # back-compat
|
30
|
+
|
31
|
+
def purchase(money, card_or_auth, options = {})
|
32
|
+
parse_card_or_auth(card_or_auth, options)
|
33
|
+
commit("cc#{@stored_data}Purchase", money, options)
|
34
|
+
end
|
35
|
+
alias stored_purchase purchase # back-compat
|
36
|
+
|
37
|
+
def refund(money, authorization, options = {})
|
38
|
+
options[:confirmationNumber] = authorization
|
39
|
+
commit('ccCredit', money, options)
|
40
|
+
end
|
41
|
+
|
42
|
+
def void(authorization, options = {})
|
43
|
+
options[:confirmationNumber] = authorization
|
44
|
+
commit('ccAuthorizeReversal', nil, options)
|
45
|
+
end
|
46
|
+
|
47
|
+
def capture(money, authorization, options = {})
|
48
|
+
options[:confirmationNumber] = authorization
|
49
|
+
commit('ccSettlement', money, options)
|
50
|
+
end
|
51
|
+
|
52
|
+
def test?
|
53
|
+
super || @options[:test]
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def parse_card_or_auth(card_or_auth, options)
|
59
|
+
if card_or_auth.respond_to?(:number)
|
60
|
+
@credit_card = card_or_auth
|
61
|
+
@stored_data = ""
|
62
|
+
else
|
63
|
+
options[:confirmationNumber] = card_or_auth
|
64
|
+
@stored_data = "StoredData"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def parse(body)
|
69
|
+
REXML::Document.new(body || '')
|
70
|
+
end
|
71
|
+
|
72
|
+
def commit(action, money, post)
|
73
|
+
post[:order_id] ||= 'order_id'
|
74
|
+
|
75
|
+
xml = case action
|
76
|
+
when 'ccAuthorize', 'ccPurchase', 'ccVerification'
|
77
|
+
cc_auth_request(money, post)
|
78
|
+
when 'ccCredit', 'ccSettlement'
|
79
|
+
cc_post_auth_request(money, post)
|
80
|
+
when 'ccStoredDataAuthorize', 'ccStoredDataPurchase'
|
81
|
+
cc_stored_data_request(money, post)
|
82
|
+
when 'ccAuthorizeReversal'
|
83
|
+
cc_auth_reversal_request(post)
|
84
|
+
#when 'ccCancelSettle', 'ccCancelCredit', 'ccCancelPayment'
|
85
|
+
# cc_cancel_request(money, post)
|
86
|
+
#when 'ccPayment'
|
87
|
+
# cc_payment_request(money, post)
|
88
|
+
#when 'ccAuthenticate'
|
89
|
+
# cc_authenticate_request(money, post)
|
90
|
+
else
|
91
|
+
raise 'Unknown Action'
|
92
|
+
end
|
93
|
+
txnRequest = URI.encode(xml)
|
94
|
+
response = parse(ssl_post(test? ? TEST_URL : LIVE_URL, "txnMode=#{action}&txnRequest=#{txnRequest}"))
|
95
|
+
|
96
|
+
Response.new(successful?(response), message_from(response), hash_from_xml(response),
|
97
|
+
:test => test?,
|
98
|
+
:authorization => authorization_from(response)
|
99
|
+
)
|
100
|
+
end
|
101
|
+
|
102
|
+
def successful?(response)
|
103
|
+
REXML::XPath.first(response, '//decision').text == 'ACCEPTED' rescue false
|
104
|
+
end
|
105
|
+
|
106
|
+
def message_from(response)
|
107
|
+
REXML::XPath.each(response, '//detail') do |detail|
|
108
|
+
if detail.is_a?(REXML::Element) && detail.elements['tag'].text == 'InternalResponseDescription'
|
109
|
+
return detail.elements['value'].text
|
110
|
+
end
|
111
|
+
end
|
112
|
+
nil
|
113
|
+
end
|
114
|
+
|
115
|
+
def authorization_from(response)
|
116
|
+
REXML::XPath.first(response, '//confirmationNumber').text rescue nil
|
117
|
+
end
|
118
|
+
|
119
|
+
def hash_from_xml(response)
|
120
|
+
hsh = {}
|
121
|
+
%w(confirmationNumber authCode
|
122
|
+
decision code description
|
123
|
+
actionCode avsResponse cvdResponse
|
124
|
+
txnTime duplicateFound
|
125
|
+
).each do |tag|
|
126
|
+
node = REXML::XPath.first(response, "//#{tag}")
|
127
|
+
hsh[tag] = node.text if node
|
128
|
+
end
|
129
|
+
REXML::XPath.each(response, '//detail') do |detail|
|
130
|
+
next unless detail.is_a?(REXML::Element)
|
131
|
+
tag = detail.elements['tag'].text
|
132
|
+
value = detail.elements['value'].text
|
133
|
+
hsh[tag] = value
|
134
|
+
end
|
135
|
+
hsh
|
136
|
+
end
|
137
|
+
|
138
|
+
def xml_document(root_tag)
|
139
|
+
xml = Builder::XmlMarkup.new :indent => 2
|
140
|
+
xml.tag!(root_tag, schema) do
|
141
|
+
yield xml
|
142
|
+
end
|
143
|
+
xml.target!
|
144
|
+
end
|
145
|
+
|
146
|
+
def cc_auth_request(money, opts)
|
147
|
+
xml_document('ccAuthRequestV1') do |xml|
|
148
|
+
build_merchant_account(xml, @options)
|
149
|
+
xml.merchantRefNum opts[:order_id]
|
150
|
+
xml.amount(money/100.0)
|
151
|
+
build_card(xml, opts)
|
152
|
+
build_billing_details(xml, opts)
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
def cc_auth_reversal_request(opts)
|
157
|
+
xml_document('ccAuthReversalRequestV1') do |xml|
|
158
|
+
build_merchant_account(xml, @options)
|
159
|
+
xml.confirmationNumber opts[:confirmationNumber]
|
160
|
+
xml.merchantRefNum opts[:order_id]
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
def cc_post_auth_request(money, opts)
|
165
|
+
xml_document('ccPostAuthRequestV1') do |xml|
|
166
|
+
build_merchant_account(xml, @options)
|
167
|
+
xml.confirmationNumber opts[:confirmationNumber]
|
168
|
+
xml.merchantRefNum opts[:order_id]
|
169
|
+
xml.amount(money/100.0)
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
def cc_stored_data_request(money, opts)
|
174
|
+
xml_document('ccStoredDataRequestV1') do |xml|
|
175
|
+
build_merchant_account(xml, @options)
|
176
|
+
xml.merchantRefNum opts[:order_id]
|
177
|
+
xml.confirmationNumber opts[:confirmationNumber]
|
178
|
+
xml.amount(money/100.0)
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
# untested
|
183
|
+
#
|
184
|
+
# def cc_cancel_request(opts)
|
185
|
+
# xml_document('ccCancelRequestV1') do |xml|
|
186
|
+
# build_merchant_account(xml, @options)
|
187
|
+
# xml.confirmationNumber opts[:confirmationNumber]
|
188
|
+
# end
|
189
|
+
# end
|
190
|
+
#
|
191
|
+
# def cc_payment_request(money, opts)
|
192
|
+
# xml_document('ccPaymentRequestV1') do |xml|
|
193
|
+
# build_merchant_account(xml, @options)
|
194
|
+
# xml.merchantRefNum opts[:order_id]
|
195
|
+
# xml.amount(money/100.0)
|
196
|
+
# build_card(xml, opts)
|
197
|
+
# build_billing_details(xml, opts)
|
198
|
+
# end
|
199
|
+
# end
|
200
|
+
#
|
201
|
+
# def cc_authenticate_request(opts)
|
202
|
+
# xml_document('ccAuthenticateRequestV1') do |xml|
|
203
|
+
# build_merchant_account(xml, @options)
|
204
|
+
# xml.confirmationNumber opts[:confirmationNumber]
|
205
|
+
# xml.paymentResponse 'myPaymentResponse'
|
206
|
+
# end
|
207
|
+
# end
|
208
|
+
|
209
|
+
def schema
|
210
|
+
{ 'xmlns' => 'http://www.optimalpayments.com/creditcard/xmlschema/v1',
|
211
|
+
'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
|
212
|
+
'xsi:schemaLocation' => 'http://www.optimalpayments.com/creditcard/xmlschema/v1'
|
213
|
+
}
|
214
|
+
end
|
215
|
+
|
216
|
+
def build_merchant_account(xml, opts)
|
217
|
+
xml.tag! 'merchantAccount' do
|
218
|
+
xml.tag! 'accountNum' , opts[:account]
|
219
|
+
xml.tag! 'storeID' , opts[:login]
|
220
|
+
xml.tag! 'storePwd' , opts[:password]
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
def build_card(xml, opts)
|
225
|
+
xml.tag! 'card' do
|
226
|
+
xml.tag! 'cardNum' , @credit_card.number
|
227
|
+
xml.tag! 'cardExpiry' do
|
228
|
+
xml.tag! 'month' , @credit_card.month
|
229
|
+
xml.tag! 'year' , @credit_card.year
|
230
|
+
end
|
231
|
+
if type = card_type(@credit_card.type)
|
232
|
+
xml.tag! 'cardType' , type
|
233
|
+
end
|
234
|
+
if @credit_card.verification_value
|
235
|
+
xml.tag! 'cvdIndicator' , '1' # Value Provided
|
236
|
+
xml.tag! 'cvd' , @credit_card.verification_value
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
def build_billing_details(xml, opts)
|
242
|
+
xml.tag! 'billingDetails' do
|
243
|
+
addr = opts[:billing_address]
|
244
|
+
xml.tag! 'cardPayMethod', 'WEB'
|
245
|
+
if addr[:name]
|
246
|
+
xml.tag! 'firstName', CGI.escape(addr[:name].split(' ').first) # TODO: parse properly
|
247
|
+
xml.tag! 'lastName' , CGI.escape(addr[:name].split(' ').last )
|
248
|
+
end
|
249
|
+
xml.tag! 'street' , CGI.escape(addr[:address1]) if addr[:address1] && !addr[:address1].empty?
|
250
|
+
xml.tag! 'street2', CGI.escape(addr[:address2]) if addr[:address2] && !addr[:address2].empty?
|
251
|
+
xml.tag! 'city' , CGI.escape(addr[:city] ) if addr[:city] && !addr[:city].empty?
|
252
|
+
xml.tag! 'state' , CGI.escape(addr[:state] ) if addr[:state] && !addr[:state].empty?
|
253
|
+
xml.tag! 'country', CGI.escape(addr[:country] ) if addr[:country] && !addr[:country].empty?
|
254
|
+
xml.tag! 'zip' , CGI.escape(addr[:zip] ) # this one's actually required
|
255
|
+
xml.tag! 'phone' , CGI.escape(addr[:phone] ) if addr[:phone] && !addr[:phone].empty?
|
256
|
+
#xml.tag! 'email' , ''
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
def card_type(key)
|
261
|
+
{ 'visa' => 'VI',
|
262
|
+
'master' => 'MC',
|
263
|
+
'american_express'=> 'AM',
|
264
|
+
'discover' => 'DI',
|
265
|
+
'diners_club' => 'DC',
|
266
|
+
#'switch' => '',
|
267
|
+
'solo' => 'SO'
|
268
|
+
}[key]
|
269
|
+
end
|
270
|
+
|
271
|
+
end
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
@@ -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
|
+
end
|
84
|
+
@options = options
|
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/).join.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! :CardSecValInd, 1 if creditcard.verification_value? && %w( visa discover ).include?(creditcard.type)
|
171
|
+
xml.tag! :CardSecVal, creditcard.verification_value if creditcard.verification_value?
|
172
|
+
end
|
173
|
+
|
174
|
+
def add_refund(xml, currency=nil)
|
175
|
+
xml.tag! :AccountNum, nil
|
176
|
+
|
177
|
+
xml.tag! :CurrencyCode, currency_code(currency)
|
178
|
+
xml.tag! :CurrencyExponent, '2' # Will need updating to support currencies such as the Yen.
|
179
|
+
end
|
180
|
+
|
181
|
+
def parse(body)
|
182
|
+
response = {}
|
183
|
+
xml = REXML::Document.new(body)
|
184
|
+
root = REXML::XPath.first(xml, "//Response") ||
|
185
|
+
REXML::XPath.first(xml, "//ErrorResponse")
|
186
|
+
if root
|
187
|
+
root.elements.to_a.each do |node|
|
188
|
+
recurring_parse_element(response, node)
|
189
|
+
end
|
190
|
+
end
|
191
|
+
response
|
192
|
+
end
|
193
|
+
|
194
|
+
def recurring_parse_element(response, node)
|
195
|
+
if node.has_elements?
|
196
|
+
node.elements.each{|e| recurring_parse_element(response, e) }
|
197
|
+
else
|
198
|
+
response[node.name.underscore.to_sym] = node.text
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
def commit(order)
|
203
|
+
headers = POST_HEADERS.merge("Content-length" => order.size.to_s)
|
204
|
+
request = lambda {return parse(ssl_post(remote_url, order, headers))}
|
205
|
+
|
206
|
+
# Failover URL will be used in the event of a connection error
|
207
|
+
begin response = request.call; rescue ConnectionError; retry end
|
208
|
+
|
209
|
+
Response.new(success?(response), message_from(response), response,
|
210
|
+
{:authorization => "#{response[:tx_ref_num]};#{response[:order_id]}",
|
211
|
+
:test => self.test?,
|
212
|
+
:avs_result => {:code => response[:avs_resp_code]},
|
213
|
+
:cvv_result => response[:cvv2_resp_code]
|
214
|
+
}
|
215
|
+
)
|
216
|
+
end
|
217
|
+
|
218
|
+
def remote_url
|
219
|
+
unless $!.class == ActiveMerchant::ConnectionError
|
220
|
+
self.test? ? self.primary_test_url : self.primary_live_url
|
221
|
+
else
|
222
|
+
self.test? ? self.secondary_test_url : self.secondary_live_url
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
def success?(response)
|
227
|
+
if response[:message_type].nil? || response[:message_type] == "R"
|
228
|
+
response[:proc_status] == SUCCESS
|
229
|
+
else
|
230
|
+
response[:proc_status] == SUCCESS &&
|
231
|
+
response[:resp_code] == APPROVED
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
def message_from(response)
|
236
|
+
success?(response) ? 'APPROVED' : response[:resp_msg] || response[:status_msg]
|
237
|
+
end
|
238
|
+
|
239
|
+
def ip_authentication?
|
240
|
+
@options[:ip_authentication] == true
|
241
|
+
end
|
242
|
+
|
243
|
+
def build_new_order_xml(action, money, parameters = {})
|
244
|
+
requires!(parameters, :order_id)
|
245
|
+
xml = Builder::XmlMarkup.new(:indent => 2)
|
246
|
+
xml.instruct!(:xml, :version => '1.0', :encoding => 'UTF-8')
|
247
|
+
xml.tag! :Request do
|
248
|
+
xml.tag! :NewOrder do
|
249
|
+
xml.tag! :OrbitalConnectionUsername, @options[:login] unless ip_authentication?
|
250
|
+
xml.tag! :OrbitalConnectionPassword, @options[:password] unless ip_authentication?
|
251
|
+
xml.tag! :IndustryType, parameters[:industry_type] || "EC"
|
252
|
+
xml.tag! :MessageType, action
|
253
|
+
xml.tag! :BIN, '000002' # PNS Tampa
|
254
|
+
xml.tag! :MerchantID, @options[:merchant_id]
|
255
|
+
xml.tag! :TerminalID, parameters[:terminal_id] || '001'
|
256
|
+
|
257
|
+
yield xml if block_given?
|
258
|
+
|
259
|
+
xml.tag! :Comments, parameters[:comments] if parameters[:comments]
|
260
|
+
xml.tag! :OrderID, parameters[:order_id].to_s[0...22]
|
261
|
+
xml.tag! :Amount, amount(money)
|
262
|
+
|
263
|
+
# Append Transaction Reference Number at the end for Refund transactions
|
264
|
+
if action == "R"
|
265
|
+
tx_ref_num, _ = parameters[:authorization].split(';')
|
266
|
+
xml.tag! :TxRefNum, tx_ref_num
|
267
|
+
end
|
268
|
+
end
|
269
|
+
end
|
270
|
+
xml.target!
|
271
|
+
end
|
272
|
+
|
273
|
+
def build_mark_for_capture_xml(money, authorization, parameters = {})
|
274
|
+
tx_ref_num, order_id = authorization.split(';')
|
275
|
+
xml = Builder::XmlMarkup.new(:indent => 2)
|
276
|
+
xml.instruct!(:xml, :version => '1.0', :encoding => 'UTF-8')
|
277
|
+
xml.tag! :Request do
|
278
|
+
xml.tag! :MarkForCapture do
|
279
|
+
xml.tag! :OrbitalConnectionUsername, @options[:login] unless ip_authentication?
|
280
|
+
xml.tag! :OrbitalConnectionPassword, @options[:password] unless ip_authentication?
|
281
|
+
xml.tag! :OrderID, order_id
|
282
|
+
xml.tag! :Amount, amount(money)
|
283
|
+
xml.tag! :BIN, '000002' # PNS Tampa
|
284
|
+
xml.tag! :MerchantID, @options[:merchant_id]
|
285
|
+
xml.tag! :TerminalID, parameters[:terminal_id] || '001'
|
286
|
+
xml.tag! :TxRefNum, tx_ref_num
|
287
|
+
end
|
288
|
+
end
|
289
|
+
xml.target!
|
290
|
+
end
|
291
|
+
|
292
|
+
def build_void_request_xml(money, authorization, parameters = {})
|
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
|