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,15 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/payflow_express'
|
2
|
+
|
3
|
+
module ActiveMerchant #:nodoc:
|
4
|
+
module Billing #:nodoc:
|
5
|
+
class PayflowExpressUkGateway < PayflowExpressGateway
|
6
|
+
self.default_currency = 'GBP'
|
7
|
+
self.partner = 'PayPalUk'
|
8
|
+
|
9
|
+
self.supported_countries = ['GB']
|
10
|
+
self.homepage_url = 'https://www.paypal.com/uk/cgi-bin/webscr?cmd=_additional-payment-overview-outside'
|
11
|
+
self.display_name = 'PayPal Express Checkout (UK)'
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/payflow'
|
2
|
+
require File.dirname(__FILE__) + '/payflow_express_uk'
|
3
|
+
|
4
|
+
module ActiveMerchant #:nodoc:
|
5
|
+
module Billing #:nodoc:
|
6
|
+
class PayflowUkGateway < PayflowGateway
|
7
|
+
self.default_currency = 'GBP'
|
8
|
+
self.partner = 'PayPalUk'
|
9
|
+
|
10
|
+
def express
|
11
|
+
@express ||= PayflowExpressUkGateway.new(@options)
|
12
|
+
end
|
13
|
+
|
14
|
+
self.supported_cardtypes = [:visa, :master, :american_express, :discover, :solo, :switch]
|
15
|
+
self.supported_countries = ['GB']
|
16
|
+
self.homepage_url = 'https://www.paypal.com/uk/cgi-bin/webscr?cmd=_wp-pro-overview-outside'
|
17
|
+
self.display_name = 'PayPal Website Payments Pro (UK)'
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
@@ -0,0 +1,235 @@
|
|
1
|
+
require 'rexml/document'
|
2
|
+
|
3
|
+
module ActiveMerchant #:nodoc:
|
4
|
+
module Billing #:nodoc:
|
5
|
+
|
6
|
+
# In NZ DPS supports ANZ, Westpac, National Bank, ASB and BNZ.
|
7
|
+
# In Australia DPS supports ANZ, NAB, Westpac, CBA, St George and Bank of South Australia.
|
8
|
+
# The Maybank in Malaysia is supported and the Citibank for Singapore.
|
9
|
+
class PaymentExpressGateway < Gateway
|
10
|
+
self.default_currency = 'NZD'
|
11
|
+
# PS supports all major credit cards; Visa, Mastercard, Amex, Diners, BankCard & JCB.
|
12
|
+
# Various white label cards can be accepted as well; Farmers, AirNZCard and Elders etc.
|
13
|
+
# Please note that not all acquirers and Eftpos networks can support some of these card types.
|
14
|
+
# VISA, Mastercard, Diners Club and Farmers cards are supported
|
15
|
+
#
|
16
|
+
# However, regular accounts with DPS only support VISA and Mastercard
|
17
|
+
self.supported_cardtypes = [ :visa, :master, :american_express, :diners_club, :jcb ]
|
18
|
+
|
19
|
+
self.supported_countries = [ 'AU', 'MY', 'NZ', 'SG', 'ZA', 'GB', 'US' ]
|
20
|
+
|
21
|
+
self.homepage_url = 'http://www.paymentexpress.com/'
|
22
|
+
self.display_name = 'PaymentExpress'
|
23
|
+
|
24
|
+
URL = 'https://sec.paymentexpress.com/pxpost.aspx'
|
25
|
+
|
26
|
+
APPROVED = '1'
|
27
|
+
|
28
|
+
TRANSACTIONS = {
|
29
|
+
:purchase => 'Purchase',
|
30
|
+
:credit => 'Refund',
|
31
|
+
:authorization => 'Auth',
|
32
|
+
:capture => 'Complete',
|
33
|
+
:validate => 'Validate'
|
34
|
+
}
|
35
|
+
|
36
|
+
# We require the DPS gateway username and password when the object is created.
|
37
|
+
def initialize(options = {})
|
38
|
+
# A DPS username and password must exist
|
39
|
+
requires!(options, :login, :password)
|
40
|
+
# Make the options an instance variable
|
41
|
+
@options = options
|
42
|
+
super
|
43
|
+
end
|
44
|
+
|
45
|
+
# Funds are transferred immediately.
|
46
|
+
def purchase(money, payment_source, options = {})
|
47
|
+
request = build_purchase_or_authorization_request(money, payment_source, options)
|
48
|
+
commit(:purchase, request)
|
49
|
+
end
|
50
|
+
|
51
|
+
# NOTE: Perhaps in options we allow a transaction note to be inserted
|
52
|
+
# Verifies that funds are available for the requested card and amount and reserves the specified amount.
|
53
|
+
# See: http://www.paymentexpress.com/technical_resources/ecommerce_nonhosted/pxpost.html#Authcomplete
|
54
|
+
def authorize(money, payment_source, options = {})
|
55
|
+
request = build_purchase_or_authorization_request(money, payment_source, options)
|
56
|
+
commit(:authorization, request)
|
57
|
+
end
|
58
|
+
|
59
|
+
# Transfer pre-authorized funds immediately
|
60
|
+
# See: http://www.paymentexpress.com/technical_resources/ecommerce_nonhosted/pxpost.html#Authcomplete
|
61
|
+
def capture(money, identification, options = {})
|
62
|
+
request = build_capture_or_credit_request(money, identification, options)
|
63
|
+
commit(:capture, request)
|
64
|
+
end
|
65
|
+
|
66
|
+
# Refund funds to the card holder
|
67
|
+
def refund(money, identification, options = {})
|
68
|
+
requires!(options, :description)
|
69
|
+
|
70
|
+
request = build_capture_or_credit_request(money, identification, options)
|
71
|
+
commit(:credit, request)
|
72
|
+
end
|
73
|
+
|
74
|
+
def credit(money, identification, options = {})
|
75
|
+
deprecated CREDIT_DEPRECATION_MESSAGE
|
76
|
+
refund(money, identification, options)
|
77
|
+
end
|
78
|
+
|
79
|
+
# token based billing
|
80
|
+
|
81
|
+
# initiates a "Validate" transcation to store card data on payment express servers
|
82
|
+
# returns a "token" that can be used to rebill this card
|
83
|
+
# see: http://www.paymentexpress.com/technical_resources/ecommerce_nonhosted/pxpost.html#Tokenbilling
|
84
|
+
# PaymentExpress does not support unstoring a stored card.
|
85
|
+
def store(credit_card, options = {})
|
86
|
+
request = build_token_request(credit_card, options)
|
87
|
+
commit(:validate, request)
|
88
|
+
end
|
89
|
+
|
90
|
+
private
|
91
|
+
|
92
|
+
def build_purchase_or_authorization_request(money, payment_source, options)
|
93
|
+
result = new_transaction
|
94
|
+
|
95
|
+
if payment_source.is_a?(String)
|
96
|
+
add_billing_token(result, payment_source)
|
97
|
+
else
|
98
|
+
add_credit_card(result, payment_source)
|
99
|
+
end
|
100
|
+
|
101
|
+
add_amount(result, money, options)
|
102
|
+
add_invoice(result, options)
|
103
|
+
add_address_verification_data(result, options)
|
104
|
+
result
|
105
|
+
end
|
106
|
+
|
107
|
+
def build_capture_or_credit_request(money, identification, options)
|
108
|
+
result = new_transaction
|
109
|
+
|
110
|
+
add_amount(result, money, options)
|
111
|
+
add_invoice(result, options)
|
112
|
+
add_reference(result, identification)
|
113
|
+
result
|
114
|
+
end
|
115
|
+
|
116
|
+
def build_token_request(credit_card, options)
|
117
|
+
result = new_transaction
|
118
|
+
add_credit_card(result, credit_card)
|
119
|
+
add_amount(result, 100, options) #need to make an auth request for $1
|
120
|
+
add_token_request(result, options)
|
121
|
+
result
|
122
|
+
end
|
123
|
+
|
124
|
+
def add_credentials(xml)
|
125
|
+
xml.add_element("PostUsername").text = @options[:login]
|
126
|
+
xml.add_element("PostPassword").text = @options[:password]
|
127
|
+
end
|
128
|
+
|
129
|
+
def add_reference(xml, identification)
|
130
|
+
xml.add_element("DpsTxnRef").text = identification
|
131
|
+
end
|
132
|
+
|
133
|
+
def add_credit_card(xml, credit_card)
|
134
|
+
xml.add_element("CardHolderName").text = credit_card.name
|
135
|
+
xml.add_element("CardNumber").text = credit_card.number
|
136
|
+
xml.add_element("DateExpiry").text = format_date(credit_card.month, credit_card.year)
|
137
|
+
|
138
|
+
if credit_card.verification_value?
|
139
|
+
xml.add_element("Cvc2").text = credit_card.verification_value
|
140
|
+
end
|
141
|
+
|
142
|
+
if requires_start_date_or_issue_number?(credit_card)
|
143
|
+
xml.add_element("DateStart").text = format_date(credit_card.start_month, credit_card.start_year) unless credit_card.start_month.blank? || credit_card.start_year.blank?
|
144
|
+
xml.add_element("IssueNumber").text = credit_card.issue_number unless credit_card.issue_number.blank?
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
def add_billing_token(xml, token)
|
149
|
+
xml.add_element("DpsBillingId").text = token
|
150
|
+
end
|
151
|
+
|
152
|
+
def add_token_request(xml, options)
|
153
|
+
xml.add_element("BillingId").text = options[:billing_id] if options[:billing_id]
|
154
|
+
xml.add_element("EnableAddBillCard").text = 1
|
155
|
+
end
|
156
|
+
|
157
|
+
def add_amount(xml, money, options)
|
158
|
+
xml.add_element("Amount").text = amount(money)
|
159
|
+
xml.add_element("InputCurrency").text = options[:currency] || currency(money)
|
160
|
+
end
|
161
|
+
|
162
|
+
def add_transaction_type(xml, action)
|
163
|
+
xml.add_element("TxnType").text = TRANSACTIONS[action]
|
164
|
+
end
|
165
|
+
|
166
|
+
def add_invoice(xml, options)
|
167
|
+
xml.add_element("TxnId").text = options[:order_id].to_s.slice(0, 16) unless options[:order_id].blank?
|
168
|
+
xml.add_element("MerchantReference").text = options[:description] unless options[:description].blank?
|
169
|
+
end
|
170
|
+
|
171
|
+
def add_address_verification_data(xml, options)
|
172
|
+
address = options[:billing_address] || options[:address]
|
173
|
+
return if address.nil?
|
174
|
+
|
175
|
+
xml.add_element("EnableAvsData").text = 1
|
176
|
+
xml.add_element("AvsAction").text = 1
|
177
|
+
|
178
|
+
xml.add_element("AvsStreetAddress").text = address[:address1]
|
179
|
+
xml.add_element("AvsPostCode").text = address[:zip]
|
180
|
+
end
|
181
|
+
|
182
|
+
def new_transaction
|
183
|
+
REXML::Document.new.add_element("Txn")
|
184
|
+
end
|
185
|
+
|
186
|
+
# Take in the request and post it to DPS
|
187
|
+
def commit(action, request)
|
188
|
+
add_credentials(request)
|
189
|
+
add_transaction_type(request, action)
|
190
|
+
|
191
|
+
# Parse the XML response
|
192
|
+
response = parse( ssl_post(URL, request.to_s) )
|
193
|
+
|
194
|
+
# Return a response
|
195
|
+
PaymentExpressResponse.new(response[:success] == APPROVED, response[:card_holder_help_text], response,
|
196
|
+
:test => response[:test_mode] == '1',
|
197
|
+
:authorization => response[:dps_txn_ref]
|
198
|
+
)
|
199
|
+
end
|
200
|
+
|
201
|
+
# Response XML documentation: http://www.paymentexpress.com/technical_resources/ecommerce_nonhosted/pxpost.html#XMLTxnOutput
|
202
|
+
def parse(xml_string)
|
203
|
+
response = {}
|
204
|
+
|
205
|
+
xml = REXML::Document.new(xml_string)
|
206
|
+
|
207
|
+
# Gather all root elements such as HelpText
|
208
|
+
xml.elements.each('Txn/*') do |element|
|
209
|
+
response[element.name.underscore.to_sym] = element.text unless element.name == 'Transaction'
|
210
|
+
end
|
211
|
+
|
212
|
+
# Gather all transaction elements and prefix with "account_"
|
213
|
+
# So we could access the MerchantResponseText by going
|
214
|
+
# response[account_merchant_response_text]
|
215
|
+
xml.elements.each('Txn/Transaction/*') do |element|
|
216
|
+
response[element.name.underscore.to_sym] = element.text
|
217
|
+
end
|
218
|
+
|
219
|
+
response
|
220
|
+
end
|
221
|
+
|
222
|
+
def format_date(month, year)
|
223
|
+
"#{format(month, :two_digits)}#{format(year, :two_digits)}"
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
class PaymentExpressResponse < Response
|
228
|
+
# add a method to response so we can easily get the token
|
229
|
+
# for Validate transactions
|
230
|
+
def token
|
231
|
+
@params["billing_id"] || @params["dps_billing_id"]
|
232
|
+
end
|
233
|
+
end
|
234
|
+
end
|
235
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/paypal/paypal_common_api'
|
2
|
+
require File.dirname(__FILE__) + '/paypal_express'
|
3
|
+
|
4
|
+
module ActiveMerchant #:nodoc:
|
5
|
+
module Billing #:nodoc:
|
6
|
+
class PaypalGateway < Gateway
|
7
|
+
include PaypalCommonAPI
|
8
|
+
|
9
|
+
self.supported_cardtypes = [:visa, :master, :american_express, :discover]
|
10
|
+
self.supported_countries = ['US']
|
11
|
+
self.homepage_url = 'https://www.paypal.com/cgi-bin/webscr?cmd=_wp-pro-overview-outside'
|
12
|
+
self.display_name = 'PayPal Website Payments Pro (US)'
|
13
|
+
|
14
|
+
def authorize(money, credit_card_or_referenced_id, options = {})
|
15
|
+
requires!(options, :ip)
|
16
|
+
commit define_transaction_type(credit_card_or_referenced_id), build_sale_or_authorization_request('Authorization', money, credit_card_or_referenced_id, options)
|
17
|
+
end
|
18
|
+
|
19
|
+
def purchase(money, credit_card_or_referenced_id, options = {})
|
20
|
+
requires!(options, :ip)
|
21
|
+
commit define_transaction_type(credit_card_or_referenced_id), build_sale_or_authorization_request('Sale', money, credit_card_or_referenced_id, options)
|
22
|
+
end
|
23
|
+
|
24
|
+
def express
|
25
|
+
@express ||= PaypalExpressGateway.new(@options)
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def define_transaction_type(transaction_arg)
|
31
|
+
if transaction_arg.is_a?(String)
|
32
|
+
return 'DoReferenceTransaction'
|
33
|
+
else
|
34
|
+
return 'DoDirectPayment'
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def build_sale_or_authorization_request(action, money, credit_card_or_referenced_id, options)
|
39
|
+
transaction_type = define_transaction_type(credit_card_or_referenced_id)
|
40
|
+
reference_id = credit_card_or_referenced_id if transaction_type == "DoReferenceTransaction"
|
41
|
+
|
42
|
+
billing_address = options[:billing_address] || options[:address]
|
43
|
+
currency_code = options[:currency] || currency(money)
|
44
|
+
|
45
|
+
xml = Builder::XmlMarkup.new :indent => 2
|
46
|
+
xml.tag! transaction_type + 'Req', 'xmlns' => PAYPAL_NAMESPACE do
|
47
|
+
xml.tag! transaction_type + 'Request', 'xmlns:n2' => EBAY_NAMESPACE do
|
48
|
+
xml.tag! 'n2:Version', API_VERSION
|
49
|
+
xml.tag! 'n2:' + transaction_type + 'RequestDetails' do
|
50
|
+
xml.tag! 'n2:ReferenceID', reference_id if transaction_type == 'DoReferenceTransaction'
|
51
|
+
xml.tag! 'n2:PaymentAction', action
|
52
|
+
xml.tag! 'n2:PaymentDetails' do
|
53
|
+
xml.tag! 'n2:OrderTotal', localized_amount(money, currency_code), 'currencyID' => currency_code
|
54
|
+
|
55
|
+
# All of the values must be included together and add up to the order total
|
56
|
+
if [:subtotal, :shipping, :handling, :tax].all?{ |o| options.has_key?(o) }
|
57
|
+
xml.tag! 'n2:ItemTotal', localized_amount(options[:subtotal], currency_code), 'currencyID' => currency_code
|
58
|
+
xml.tag! 'n2:ShippingTotal', localized_amount(options[:shipping], currency_code),'currencyID' => currency_code
|
59
|
+
xml.tag! 'n2:HandlingTotal', localized_amount(options[:handling], currency_code),'currencyID' => currency_code
|
60
|
+
xml.tag! 'n2:TaxTotal', localized_amount(options[:tax], currency_code), 'currencyID' => currency_code
|
61
|
+
end
|
62
|
+
|
63
|
+
xml.tag! 'n2:NotifyURL', options[:notify_url]
|
64
|
+
xml.tag! 'n2:OrderDescription', options[:description]
|
65
|
+
xml.tag! 'n2:InvoiceID', options[:order_id]
|
66
|
+
xml.tag! 'n2:ButtonSource', application_id.to_s.slice(0,32) unless application_id.blank?
|
67
|
+
|
68
|
+
add_address(xml, 'n2:ShipToAddress', options[:shipping_address]) if options[:shipping_address]
|
69
|
+
end
|
70
|
+
add_credit_card(xml, credit_card_or_referenced_id, billing_address, options) unless transaction_type == 'DoReferenceTransaction'
|
71
|
+
xml.tag! 'n2:IPAddress', options[:ip]
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
xml.target!
|
77
|
+
end
|
78
|
+
|
79
|
+
def add_credit_card(xml, credit_card, address, options)
|
80
|
+
xml.tag! 'n2:CreditCard' do
|
81
|
+
xml.tag! 'n2:CreditCardType', credit_card_type(card_brand(credit_card))
|
82
|
+
xml.tag! 'n2:CreditCardNumber', credit_card.number
|
83
|
+
xml.tag! 'n2:ExpMonth', format(credit_card.month, :two_digits)
|
84
|
+
xml.tag! 'n2:ExpYear', format(credit_card.year, :four_digits)
|
85
|
+
xml.tag! 'n2:CVV2', credit_card.verification_value
|
86
|
+
|
87
|
+
if [ 'switch', 'solo' ].include?(card_brand(credit_card).to_s)
|
88
|
+
xml.tag! 'n2:StartMonth', format(credit_card.start_month, :two_digits) unless credit_card.start_month.blank?
|
89
|
+
xml.tag! 'n2:StartYear', format(credit_card.start_year, :four_digits) unless credit_card.start_year.blank?
|
90
|
+
xml.tag! 'n2:IssueNumber', format(credit_card.issue_number, :two_digits) unless credit_card.issue_number.blank?
|
91
|
+
end
|
92
|
+
|
93
|
+
xml.tag! 'n2:CardOwner' do
|
94
|
+
xml.tag! 'n2:PayerName' do
|
95
|
+
xml.tag! 'n2:FirstName', credit_card.first_name
|
96
|
+
xml.tag! 'n2:LastName', credit_card.last_name
|
97
|
+
end
|
98
|
+
|
99
|
+
xml.tag! 'n2:Payer', options[:email]
|
100
|
+
add_address(xml, 'n2:Address', address)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def credit_card_type(type)
|
106
|
+
case type
|
107
|
+
when 'visa' then 'Visa'
|
108
|
+
when 'master' then 'MasterCard'
|
109
|
+
when 'discover' then 'Discover'
|
110
|
+
when 'american_express' then 'Amex'
|
111
|
+
when 'switch' then 'Switch'
|
112
|
+
when 'solo' then 'Solo'
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def build_response(success, message, response, options = {})
|
117
|
+
Response.new(success, message, response, options)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
@@ -0,0 +1,354 @@
|
|
1
|
+
module ActiveMerchant #:nodoc:
|
2
|
+
module Billing #:nodoc:
|
3
|
+
# This module is included in both PaypalGateway and PaypalExpressGateway
|
4
|
+
module PaypalCommonAPI
|
5
|
+
def self.included(base)
|
6
|
+
base.default_currency = 'USD'
|
7
|
+
base.cattr_accessor :pem_file
|
8
|
+
base.cattr_accessor :signature
|
9
|
+
end
|
10
|
+
|
11
|
+
API_VERSION = '62.0'
|
12
|
+
|
13
|
+
URLS = {
|
14
|
+
:test => { :certificate => 'https://api.sandbox.paypal.com/2.0/',
|
15
|
+
:signature => 'https://api-3t.sandbox.paypal.com/2.0/' },
|
16
|
+
:live => { :certificate => 'https://api-aa.paypal.com/2.0/',
|
17
|
+
:signature => 'https://api-3t.paypal.com/2.0/' }
|
18
|
+
}
|
19
|
+
|
20
|
+
PAYPAL_NAMESPACE = 'urn:ebay:api:PayPalAPI'
|
21
|
+
EBAY_NAMESPACE = 'urn:ebay:apis:eBLBaseComponents'
|
22
|
+
|
23
|
+
ENVELOPE_NAMESPACES = { 'xmlns:xsd' => 'http://www.w3.org/2001/XMLSchema',
|
24
|
+
'xmlns:env' => 'http://schemas.xmlsoap.org/soap/envelope/',
|
25
|
+
'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance'
|
26
|
+
}
|
27
|
+
CREDENTIALS_NAMESPACES = { 'xmlns' => PAYPAL_NAMESPACE,
|
28
|
+
'xmlns:n1' => EBAY_NAMESPACE,
|
29
|
+
'env:mustUnderstand' => '0'
|
30
|
+
}
|
31
|
+
|
32
|
+
AUSTRALIAN_STATES = {
|
33
|
+
'ACT' => 'Australian Capital Territory',
|
34
|
+
'NSW' => 'New South Wales',
|
35
|
+
'NT' => 'Northern Territory',
|
36
|
+
'QLD' => 'Queensland',
|
37
|
+
'SA' => 'South Australia',
|
38
|
+
'TAS' => 'Tasmania',
|
39
|
+
'VIC' => 'Victoria',
|
40
|
+
'WA' => 'Western Australia'
|
41
|
+
}
|
42
|
+
|
43
|
+
SUCCESS_CODES = [ 'Success', 'SuccessWithWarning' ]
|
44
|
+
|
45
|
+
FRAUD_REVIEW_CODE = "11610"
|
46
|
+
|
47
|
+
# The gateway must be configured with either your PayPal PEM file
|
48
|
+
# or your PayPal API Signature. Only one is required.
|
49
|
+
#
|
50
|
+
# <tt>:pem</tt> The text of your PayPal PEM file. Note
|
51
|
+
# this is not the path to file, but its
|
52
|
+
# contents. If you are only using one PEM
|
53
|
+
# file on your site you can declare it
|
54
|
+
# globally and then you won't need to
|
55
|
+
# include this option
|
56
|
+
#
|
57
|
+
# <tt>:signature</tt> The text of your PayPal signature.
|
58
|
+
# If you are only using one API Signature
|
59
|
+
# on your site you can declare it
|
60
|
+
# globally and then you won't need to
|
61
|
+
# include this option
|
62
|
+
|
63
|
+
def initialize(options = {})
|
64
|
+
requires!(options, :login, :password)
|
65
|
+
|
66
|
+
headers = {'X-PP-AUTHORIZATION' => options.delete(:auth_signature), 'X-PAYPAL-MESSAGE-PROTOCOL' => 'SOAP11'} if options[:auth_signature]
|
67
|
+
@options = {
|
68
|
+
:pem => pem_file,
|
69
|
+
:signature => signature,
|
70
|
+
:headers => headers || {}
|
71
|
+
}.update(options)
|
72
|
+
|
73
|
+
|
74
|
+
if @options[:pem].blank? && @options[:signature].blank?
|
75
|
+
raise ArgumentError, "An API Certificate or API Signature is required to make requests to PayPal"
|
76
|
+
end
|
77
|
+
|
78
|
+
super
|
79
|
+
end
|
80
|
+
|
81
|
+
def test?
|
82
|
+
@options[:test] || Base.gateway_mode == :test
|
83
|
+
end
|
84
|
+
|
85
|
+
def reauthorize(money, authorization, options = {})
|
86
|
+
commit 'DoReauthorization', build_reauthorize_request(money, authorization, options)
|
87
|
+
end
|
88
|
+
|
89
|
+
def capture(money, authorization, options = {})
|
90
|
+
commit 'DoCapture', build_capture_request(money, authorization, options)
|
91
|
+
end
|
92
|
+
|
93
|
+
# Transfer money to one or more recipients.
|
94
|
+
#
|
95
|
+
# gateway.transfer 1000, 'bob@example.com',
|
96
|
+
# :subject => "The money I owe you", :note => "Sorry it's so late"
|
97
|
+
#
|
98
|
+
# gateway.transfer [1000, 'fred@example.com'],
|
99
|
+
# [2450, 'wilma@example.com', :note => 'You will receive another payment on 3/24'],
|
100
|
+
# [2000, 'barney@example.com'],
|
101
|
+
# :subject => "Your Earnings", :note => "Thanks for your business."
|
102
|
+
#
|
103
|
+
def transfer(*args)
|
104
|
+
commit 'MassPay', build_mass_pay_request(*args)
|
105
|
+
end
|
106
|
+
|
107
|
+
def void(authorization, options = {})
|
108
|
+
commit 'DoVoid', build_void_request(authorization, options)
|
109
|
+
end
|
110
|
+
|
111
|
+
def refund(money, identification, options = {})
|
112
|
+
commit 'RefundTransaction', build_refund_request(money, identification, options)
|
113
|
+
end
|
114
|
+
|
115
|
+
def credit(money, identification, options = {})
|
116
|
+
deprecated Gateway::CREDIT_DEPRECATION_MESSAGE
|
117
|
+
refund(money, identification, options)
|
118
|
+
end
|
119
|
+
|
120
|
+
private
|
121
|
+
def build_reauthorize_request(money, authorization, options)
|
122
|
+
xml = Builder::XmlMarkup.new
|
123
|
+
|
124
|
+
xml.tag! 'DoReauthorizationReq', 'xmlns' => PAYPAL_NAMESPACE do
|
125
|
+
xml.tag! 'DoReauthorizationRequest', 'xmlns:n2' => EBAY_NAMESPACE do
|
126
|
+
xml.tag! 'n2:Version', API_VERSION
|
127
|
+
xml.tag! 'AuthorizationID', authorization
|
128
|
+
xml.tag! 'Amount', amount(money), 'currencyID' => options[:currency] || currency(money)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
xml.target!
|
133
|
+
end
|
134
|
+
|
135
|
+
def build_capture_request(money, authorization, options)
|
136
|
+
xml = Builder::XmlMarkup.new
|
137
|
+
|
138
|
+
xml.tag! 'DoCaptureReq', 'xmlns' => PAYPAL_NAMESPACE do
|
139
|
+
xml.tag! 'DoCaptureRequest', 'xmlns:n2' => EBAY_NAMESPACE do
|
140
|
+
xml.tag! 'n2:Version', API_VERSION
|
141
|
+
xml.tag! 'AuthorizationID', authorization
|
142
|
+
xml.tag! 'Amount', amount(money), 'currencyID' => options[:currency] || currency(money)
|
143
|
+
xml.tag! 'CompleteType', 'Complete'
|
144
|
+
xml.tag! 'InvoiceID', options[:order_id] unless options[:order_id].blank?
|
145
|
+
xml.tag! 'Note', options[:description]
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
xml.target!
|
150
|
+
end
|
151
|
+
|
152
|
+
def build_refund_request(money, identification, options)
|
153
|
+
xml = Builder::XmlMarkup.new
|
154
|
+
|
155
|
+
xml.tag! 'RefundTransactionReq', 'xmlns' => PAYPAL_NAMESPACE do
|
156
|
+
xml.tag! 'RefundTransactionRequest', 'xmlns:n2' => EBAY_NAMESPACE do
|
157
|
+
xml.tag! 'n2:Version', API_VERSION
|
158
|
+
xml.tag! 'TransactionID', identification
|
159
|
+
xml.tag! 'Amount', amount(money), 'currencyID' => options[:currency] || currency(money)
|
160
|
+
xml.tag! 'RefundType', 'Partial'
|
161
|
+
xml.tag! 'Memo', options[:note] unless options[:note].blank?
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
xml.target!
|
166
|
+
end
|
167
|
+
|
168
|
+
def build_void_request(authorization, options)
|
169
|
+
xml = Builder::XmlMarkup.new
|
170
|
+
|
171
|
+
xml.tag! 'DoVoidReq', 'xmlns' => PAYPAL_NAMESPACE do
|
172
|
+
xml.tag! 'DoVoidRequest', 'xmlns:n2' => EBAY_NAMESPACE do
|
173
|
+
xml.tag! 'n2:Version', API_VERSION
|
174
|
+
xml.tag! 'AuthorizationID', authorization
|
175
|
+
xml.tag! 'Note', options[:description]
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
xml.target!
|
180
|
+
end
|
181
|
+
|
182
|
+
def build_mass_pay_request(*args)
|
183
|
+
default_options = args.last.is_a?(Hash) ? args.pop : {}
|
184
|
+
recipients = args.first.is_a?(Array) ? args : [args]
|
185
|
+
|
186
|
+
xml = Builder::XmlMarkup.new
|
187
|
+
|
188
|
+
xml.tag! 'MassPayReq', 'xmlns' => PAYPAL_NAMESPACE do
|
189
|
+
xml.tag! 'MassPayRequest', 'xmlns:n2' => EBAY_NAMESPACE do
|
190
|
+
xml.tag! 'n2:Version', API_VERSION
|
191
|
+
xml.tag! 'EmailSubject', default_options[:subject] if default_options[:subject]
|
192
|
+
recipients.each do |money, recipient, options|
|
193
|
+
options ||= default_options
|
194
|
+
xml.tag! 'MassPayItem' do
|
195
|
+
xml.tag! 'ReceiverEmail', recipient
|
196
|
+
xml.tag! 'Amount', amount(money), 'currencyID' => options[:currency] || currency(money)
|
197
|
+
xml.tag! 'Note', options[:note] if options[:note]
|
198
|
+
xml.tag! 'UniqueId', options[:unique_id] if options[:unique_id]
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
xml.target!
|
205
|
+
end
|
206
|
+
|
207
|
+
def parse(action, xml)
|
208
|
+
legacy_hash = legacy_parse(action, xml)
|
209
|
+
xml = strip_attributes(xml)
|
210
|
+
hash = Hash.from_xml(xml)
|
211
|
+
hash = hash.fetch('Envelope').fetch('Body').fetch("#{action}Response")
|
212
|
+
hash = hash["#{action}ResponseDetails"] if hash["#{action}ResponseDetails"]
|
213
|
+
|
214
|
+
legacy_hash.merge(hash)
|
215
|
+
rescue IndexError
|
216
|
+
legacy_hash.merge(hash['Envelope']['Body'])
|
217
|
+
end
|
218
|
+
|
219
|
+
def strip_attributes(xml)
|
220
|
+
xml = REXML::Document.new(xml)
|
221
|
+
REXML::XPath.each(xml, '//SOAP-ENV:Envelope//*[@*]') do |el|
|
222
|
+
el.attributes.each_attribute { |a| a.remove }
|
223
|
+
end
|
224
|
+
xml.to_s
|
225
|
+
end
|
226
|
+
|
227
|
+
def legacy_parse(action, xml)
|
228
|
+
response = {}
|
229
|
+
|
230
|
+
error_messages = []
|
231
|
+
error_codes = []
|
232
|
+
|
233
|
+
xml = REXML::Document.new(xml)
|
234
|
+
if root = REXML::XPath.first(xml, "//#{action}Response")
|
235
|
+
root.elements.each do |node|
|
236
|
+
case node.name
|
237
|
+
when 'Errors'
|
238
|
+
short_message = nil
|
239
|
+
long_message = nil
|
240
|
+
|
241
|
+
node.elements.each do |child|
|
242
|
+
case child.name
|
243
|
+
when "LongMessage"
|
244
|
+
long_message = child.text unless child.text.blank?
|
245
|
+
when "ShortMessage"
|
246
|
+
short_message = child.text unless child.text.blank?
|
247
|
+
when "ErrorCode"
|
248
|
+
error_codes << child.text unless child.text.blank?
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
252
|
+
if message = long_message || short_message
|
253
|
+
error_messages << message
|
254
|
+
end
|
255
|
+
else
|
256
|
+
legacy_parse_element(response, node)
|
257
|
+
end
|
258
|
+
end
|
259
|
+
response[:message] = error_messages.uniq.join(". ") unless error_messages.empty?
|
260
|
+
response[:error_codes] = error_codes.uniq.join(",") unless error_codes.empty?
|
261
|
+
elsif root = REXML::XPath.first(xml, "//SOAP-ENV:Fault")
|
262
|
+
legacy_parse_element(response, root)
|
263
|
+
response[:message] = "#{response[:faultcode]}: #{response[:faultstring]} - #{response[:detail]}"
|
264
|
+
end
|
265
|
+
|
266
|
+
response
|
267
|
+
end
|
268
|
+
|
269
|
+
def legacy_parse_element(response, node)
|
270
|
+
if node.has_elements?
|
271
|
+
node.elements.each{|e| legacy_parse_element(response, e) }
|
272
|
+
else
|
273
|
+
response[node.name.underscore.to_sym] = node.text
|
274
|
+
node.attributes.each do |k, v|
|
275
|
+
response["#{node.name.underscore}_#{k.underscore}".to_sym] = v if k == 'currencyID'
|
276
|
+
end
|
277
|
+
end
|
278
|
+
end
|
279
|
+
|
280
|
+
def build_request(body)
|
281
|
+
xml = Builder::XmlMarkup.new
|
282
|
+
|
283
|
+
xml.instruct!
|
284
|
+
xml.tag! 'env:Envelope', ENVELOPE_NAMESPACES do
|
285
|
+
xml.tag! 'env:Header' do
|
286
|
+
add_credentials(xml) unless @options[:headers] && @options[:headers]['X-PP-AUTHORIZATION']
|
287
|
+
end
|
288
|
+
|
289
|
+
xml.tag! 'env:Body' do
|
290
|
+
xml << body
|
291
|
+
end
|
292
|
+
end
|
293
|
+
xml.target!
|
294
|
+
end
|
295
|
+
|
296
|
+
def add_credentials(xml)
|
297
|
+
xml.tag! 'RequesterCredentials', CREDENTIALS_NAMESPACES do
|
298
|
+
xml.tag! 'n1:Credentials' do
|
299
|
+
xml.tag! 'Username', @options[:login]
|
300
|
+
xml.tag! 'Password', @options[:password]
|
301
|
+
xml.tag! 'Subject', @options[:subject]
|
302
|
+
xml.tag! 'Signature', @options[:signature] unless @options[:signature].blank?
|
303
|
+
end
|
304
|
+
end
|
305
|
+
end
|
306
|
+
|
307
|
+
def add_address(xml, element, address)
|
308
|
+
return if address.nil?
|
309
|
+
xml.tag! element do
|
310
|
+
xml.tag! 'n2:Name', address[:name]
|
311
|
+
xml.tag! 'n2:Street1', address[:address1]
|
312
|
+
xml.tag! 'n2:Street2', address[:address2]
|
313
|
+
xml.tag! 'n2:CityName', address[:city]
|
314
|
+
xml.tag! 'n2:StateOrProvince', address[:state].blank? ? 'N/A' : address[:state]
|
315
|
+
xml.tag! 'n2:Country', address[:country]
|
316
|
+
xml.tag! 'n2:PostalCode', address[:zip]
|
317
|
+
xml.tag! 'n2:Phone', address[:phone]
|
318
|
+
end
|
319
|
+
end
|
320
|
+
|
321
|
+
def endpoint_url
|
322
|
+
URLS[test? ? :test : :live][@options[:signature].blank? ? :certificate : :signature]
|
323
|
+
end
|
324
|
+
|
325
|
+
def commit(action, request)
|
326
|
+
response = parse(action, ssl_post(endpoint_url, build_request(request), @options[:headers]))
|
327
|
+
|
328
|
+
build_response(successful?(response), message_from(response), response,
|
329
|
+
:test => test?,
|
330
|
+
:authorization => authorization_from(response),
|
331
|
+
:fraud_review => fraud_review?(response),
|
332
|
+
:avs_result => { :code => response[:avs_code] },
|
333
|
+
:cvv_result => response[:cvv2_code]
|
334
|
+
)
|
335
|
+
end
|
336
|
+
|
337
|
+
def fraud_review?(response)
|
338
|
+
response[:error_codes] == FRAUD_REVIEW_CODE
|
339
|
+
end
|
340
|
+
|
341
|
+
def authorization_from(response)
|
342
|
+
response[:transaction_id] || response[:authorization_id] || response[:refund_transaction_id] # middle one is from reauthorization
|
343
|
+
end
|
344
|
+
|
345
|
+
def successful?(response)
|
346
|
+
SUCCESS_CODES.include?(response[:ack])
|
347
|
+
end
|
348
|
+
|
349
|
+
def message_from(response)
|
350
|
+
response[:message] || response[:ack]
|
351
|
+
end
|
352
|
+
end
|
353
|
+
end
|
354
|
+
end
|