activemerchant-nsp 1.27.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +952 -0
- data/CONTRIBUTORS +347 -0
- data/MIT-LICENSE +20 -0
- data/README.md +204 -0
- data/gem-public_cert.pem +20 -0
- data/lib/active_merchant.rb +63 -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 +56 -0
- data/lib/active_merchant/billing/check.rb +68 -0
- data/lib/active_merchant/billing/credit_card.rb +274 -0
- data/lib/active_merchant/billing/credit_card_formatting.rb +21 -0
- data/lib/active_merchant/billing/credit_card_methods.rb +143 -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 +176 -0
- data/lib/active_merchant/billing/gateways.rb +18 -0
- data/lib/active_merchant/billing/gateways/authorize_net.rb +695 -0
- data/lib/active_merchant/billing/gateways/authorize_net_cim.rb +943 -0
- data/lib/active_merchant/billing/gateways/balanced.rb +462 -0
- data/lib/active_merchant/billing/gateways/barclays_epdq.rb +308 -0
- data/lib/active_merchant/billing/gateways/beanstream.rb +167 -0
- data/lib/active_merchant/billing/gateways/beanstream/beanstream_core.rb +389 -0
- data/lib/active_merchant/billing/gateways/beanstream_interac.rb +54 -0
- data/lib/active_merchant/billing/gateways/blue_pay.rb +492 -0
- data/lib/active_merchant/billing/gateways/bogus.rb +142 -0
- data/lib/active_merchant/billing/gateways/braintree.rb +19 -0
- data/lib/active_merchant/billing/gateways/braintree/braintree_common.rb +9 -0
- data/lib/active_merchant/billing/gateways/braintree_blue.rb +389 -0
- data/lib/active_merchant/billing/gateways/braintree_orange.rb +19 -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/certo_direct.rb +278 -0
- data/lib/active_merchant/billing/gateways/cyber_source.rb +576 -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 +137 -0
- data/lib/active_merchant/billing/gateways/epay.rb +276 -0
- data/lib/active_merchant/billing/gateways/eway.rb +287 -0
- data/lib/active_merchant/billing/gateways/eway_managed.rb +265 -0
- data/lib/active_merchant/billing/gateways/exact.rb +227 -0
- data/lib/active_merchant/billing/gateways/fat_zebra.rb +152 -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 +252 -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 +257 -0
- data/lib/active_merchant/billing/gateways/itransact.rb +450 -0
- data/lib/active_merchant/billing/gateways/jetpay.rb +276 -0
- data/lib/active_merchant/billing/gateways/linkpoint.rb +451 -0
- data/lib/active_merchant/billing/gateways/litle.rb +290 -0
- data/lib/active_merchant/billing/gateways/merchant_e_solutions.rb +157 -0
- data/lib/active_merchant/billing/gateways/merchant_ware.rb +289 -0
- data/lib/active_merchant/billing/gateways/metrics_global.rb +323 -0
- data/lib/active_merchant/billing/gateways/migs.rb +263 -0
- data/lib/active_merchant/billing/gateways/migs/migs_codes.rb +100 -0
- data/lib/active_merchant/billing/gateways/modern_payments.rb +38 -0
- data/lib/active_merchant/billing/gateways/modern_payments_cim.rb +220 -0
- data/lib/active_merchant/billing/gateways/moneris.rb +250 -0
- data/lib/active_merchant/billing/gateways/moneris_us.rb +211 -0
- data/lib/active_merchant/billing/gateways/nab_transact.rb +257 -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 +196 -0
- data/lib/active_merchant/billing/gateways/nmi.rb +13 -0
- data/lib/active_merchant/billing/gateways/ogone.rb +427 -0
- data/lib/active_merchant/billing/gateways/optimal_payment.rb +277 -0
- data/lib/active_merchant/billing/gateways/orbital.rb +351 -0
- data/lib/active_merchant/billing/gateways/orbital/orbital_soft_descriptors.rb +46 -0
- data/lib/active_merchant/billing/gateways/pay_gate_xml.rb +266 -0
- data/lib/active_merchant/billing/gateways/pay_junction.rb +397 -0
- data/lib/active_merchant/billing/gateways/pay_secure.rb +120 -0
- data/lib/active_merchant/billing/gateways/paybox_direct.rb +201 -0
- data/lib/active_merchant/billing/gateways/payflow.rb +268 -0
- data/lib/active_merchant/billing/gateways/payflow/payflow_common_api.rb +212 -0
- data/lib/active_merchant/billing/gateways/payflow/payflow_express_response.rb +39 -0
- data/lib/active_merchant/billing/gateways/payflow/payflow_response.rb +13 -0
- data/lib/active_merchant/billing/gateways/payflow_express.rb +224 -0
- data/lib/active_merchant/billing/gateways/payflow_express_uk.rb +15 -0
- data/lib/active_merchant/billing/gateways/payflow_uk.rb +21 -0
- data/lib/active_merchant/billing/gateways/payment_express.rb +282 -0
- data/lib/active_merchant/billing/gateways/paypal.rb +106 -0
- data/lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb +653 -0
- data/lib/active_merchant/billing/gateways/paypal/paypal_express_response.rb +49 -0
- data/lib/active_merchant/billing/gateways/paypal/paypal_recurring_api.rb +245 -0
- data/lib/active_merchant/billing/gateways/paypal_ca.rb +13 -0
- data/lib/active_merchant/billing/gateways/paypal_digital_goods.rb +43 -0
- data/lib/active_merchant/billing/gateways/paypal_express.rb +178 -0
- data/lib/active_merchant/billing/gateways/paypal_express_common.rb +30 -0
- data/lib/active_merchant/billing/gateways/paystation.rb +201 -0
- data/lib/active_merchant/billing/gateways/payway.rb +214 -0
- data/lib/active_merchant/billing/gateways/plugnpay.rb +295 -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 +298 -0
- data/lib/active_merchant/billing/gateways/realex.rb +313 -0
- data/lib/active_merchant/billing/gateways/sage.rb +148 -0
- data/lib/active_merchant/billing/gateways/sage/sage_bankcard.rb +88 -0
- data/lib/active_merchant/billing/gateways/sage/sage_core.rb +115 -0
- data/lib/active_merchant/billing/gateways/sage/sage_virtual_check.rb +97 -0
- data/lib/active_merchant/billing/gateways/sage_pay.rb +322 -0
- data/lib/active_merchant/billing/gateways/sallie_mae.rb +144 -0
- data/lib/active_merchant/billing/gateways/samurai.rb +121 -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 +284 -0
- data/lib/active_merchant/billing/gateways/secure_pay_tech.rb +113 -0
- data/lib/active_merchant/billing/gateways/skip_jack.rb +458 -0
- data/lib/active_merchant/billing/gateways/smart_ps.rb +273 -0
- data/lib/active_merchant/billing/gateways/stripe.rb +236 -0
- data/lib/active_merchant/billing/gateways/trans_first.rb +127 -0
- data/lib/active_merchant/billing/gateways/transax.rb +23 -0
- data/lib/active_merchant/billing/gateways/trust_commerce.rb +423 -0
- data/lib/active_merchant/billing/gateways/usa_epay.rb +25 -0
- data/lib/active_merchant/billing/gateways/usa_epay_advanced.rb +1497 -0
- data/lib/active_merchant/billing/gateways/usa_epay_transaction.rb +206 -0
- data/lib/active_merchant/billing/gateways/verifi.rb +233 -0
- data/lib/active_merchant/billing/gateways/viaklix.rb +194 -0
- data/lib/active_merchant/billing/gateways/vindicia.rb +359 -0
- data/lib/active_merchant/billing/gateways/wirecard.rb +313 -0
- data/lib/active_merchant/billing/gateways/worldpay.rb +271 -0
- data/lib/active_merchant/billing/integrations.rb +17 -0
- data/lib/active_merchant/billing/integrations/action_view_helper.rb +73 -0
- data/lib/active_merchant/billing/integrations/authorize_net_sim.rb +38 -0
- data/lib/active_merchant/billing/integrations/authorize_net_sim/helper.rb +228 -0
- data/lib/active_merchant/billing/integrations/authorize_net_sim/notification.rb +340 -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/dotpay.rb +22 -0
- data/lib/active_merchant/billing/integrations/dotpay/helper.rb +77 -0
- data/lib/active_merchant/billing/integrations/dotpay/notification.rb +86 -0
- data/lib/active_merchant/billing/integrations/dotpay/return.rb +11 -0
- data/lib/active_merchant/billing/integrations/dwolla.rb +30 -0
- data/lib/active_merchant/billing/integrations/dwolla/helper.rb +31 -0
- data/lib/active_merchant/billing/integrations/dwolla/notification.rb +55 -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/easy_pay.rb +30 -0
- data/lib/active_merchant/billing/integrations/easy_pay/common.rb +40 -0
- data/lib/active_merchant/billing/integrations/easy_pay/helper.rb +40 -0
- data/lib/active_merchant/billing/integrations/easy_pay/notification.rb +51 -0
- data/lib/active_merchant/billing/integrations/epay.rb +21 -0
- data/lib/active_merchant/billing/integrations/epay/helper.rb +55 -0
- data/lib/active_merchant/billing/integrations/epay/notification.rb +110 -0
- data/lib/active_merchant/billing/integrations/first_data.rb +38 -0
- data/lib/active_merchant/billing/integrations/first_data/helper.rb +63 -0
- data/lib/active_merchant/billing/integrations/first_data/notification.rb +56 -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 +117 -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/maksuturva.rb +86 -0
- data/lib/active_merchant/billing/integrations/maksuturva/helper.rb +119 -0
- data/lib/active_merchant/billing/integrations/maksuturva/notification.rb +48 -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/nelnet.rb +40 -0
- data/lib/active_merchant/billing/integrations/nelnet/helper.rb +34 -0
- data/lib/active_merchant/billing/integrations/nelnet/notification.rb +100 -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/paxum.rb +44 -0
- data/lib/active_merchant/billing/integrations/paxum/common.rb +24 -0
- data/lib/active_merchant/billing/integrations/paxum/helper.rb +42 -0
- data/lib/active_merchant/billing/integrations/paxum/notification.rb +33 -0
- data/lib/active_merchant/billing/integrations/payflow_link.rb +21 -0
- data/lib/active_merchant/billing/integrations/payflow_link/helper.rb +100 -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 +155 -0
- data/lib/active_merchant/billing/integrations/paypal/return.rb +10 -0
- data/lib/active_merchant/billing/integrations/paypal_payments_advanced.rb +20 -0
- data/lib/active_merchant/billing/integrations/paypal_payments_advanced/helper.rb +15 -0
- data/lib/active_merchant/billing/integrations/pxpay.rb +31 -0
- data/lib/active_merchant/billing/integrations/pxpay/helper.rb +110 -0
- data/lib/active_merchant/billing/integrations/pxpay/notification.rb +157 -0
- data/lib/active_merchant/billing/integrations/pxpay/return.rb +25 -0
- data/lib/active_merchant/billing/integrations/quickpay.rb +21 -0
- data/lib/active_merchant/billing/integrations/quickpay/helper.rb +71 -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/robokassa.rb +49 -0
- data/lib/active_merchant/billing/integrations/robokassa/common.rb +19 -0
- data/lib/active_merchant/billing/integrations/robokassa/helper.rb +50 -0
- data/lib/active_merchant/billing/integrations/robokassa/notification.rb +55 -0
- data/lib/active_merchant/billing/integrations/robokassa/return.rb +17 -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 +129 -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 +44 -0
- data/lib/active_merchant/billing/integrations/two_checkout/helper.rb +91 -0
- data/lib/active_merchant/billing/integrations/two_checkout/notification.rb +139 -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/verkkomaksut.rb +20 -0
- data/lib/active_merchant/billing/integrations/verkkomaksut/helper.rb +87 -0
- data/lib/active_merchant/billing/integrations/verkkomaksut/notification.rb +59 -0
- data/lib/active_merchant/billing/integrations/web_pay.rb +45 -0
- data/lib/active_merchant/billing/integrations/web_pay/common.rb +50 -0
- data/lib/active_merchant/billing/integrations/web_pay/helper.rb +68 -0
- data/lib/active_merchant/billing/integrations/web_pay/notification.rb +51 -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 +64 -0
- data/lib/active_merchant/version.rb +3 -0
- data/lib/activemerchant.rb +1 -0
- data/lib/support/gateway_support.rb +65 -0
- data/lib/support/outbound_hosts.rb +25 -0
- data/lib/support/ssl_verify.rb +93 -0
- metadata +482 -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,282 @@
|
|
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 = %w[ AU MY NZ SG ZA GB US ]
|
20
|
+
|
21
|
+
self.homepage_url = 'http://www.paymentexpress.com/'
|
22
|
+
self.display_name = 'PaymentExpress'
|
23
|
+
|
24
|
+
self.live_url = self.test_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
|
+
#
|
38
|
+
# The PaymentExpress gateway also supports a :use_custom_payment_token boolean option.
|
39
|
+
# If set to true the gateway will use BillingId for the Token type. If set to false,
|
40
|
+
# then the token will be sent as the DPS specified "DpsBillingId". This is per the documentation at
|
41
|
+
# http://www.paymentexpress.com/technical_resources/ecommerce_nonhosted/pxpost.html#Tokenbilling
|
42
|
+
def initialize(options = {})
|
43
|
+
# A DPS username and password must exist
|
44
|
+
requires!(options, :login, :password)
|
45
|
+
# Make the options an instance variable
|
46
|
+
@options = options
|
47
|
+
super
|
48
|
+
end
|
49
|
+
|
50
|
+
# Funds are transferred immediately.
|
51
|
+
#
|
52
|
+
# `payment_source` can be a usual ActiveMerchant credit_card object, or can also
|
53
|
+
# be a string of the `DpsBillingId` or `BillingId` which can be gotten through the
|
54
|
+
# store method. If you are using a `BillingId` instead of `DpsBillingId` you must
|
55
|
+
# also set the instance method `#use_billing_id_for_token` to true, see the `#store`
|
56
|
+
# method for an example of how to do this.
|
57
|
+
def purchase(money, payment_source, options = {})
|
58
|
+
request = build_purchase_or_authorization_request(money, payment_source, options)
|
59
|
+
commit(:purchase, request)
|
60
|
+
end
|
61
|
+
|
62
|
+
# NOTE: Perhaps in options we allow a transaction note to be inserted
|
63
|
+
# Verifies that funds are available for the requested card and amount and reserves the specified amount.
|
64
|
+
# See: http://www.paymentexpress.com/technical_resources/ecommerce_nonhosted/pxpost.html#Authcomplete
|
65
|
+
#
|
66
|
+
# `payment_source` can be a usual ActiveMerchant credit_card object or a token, see #purchased method
|
67
|
+
def authorize(money, payment_source, options = {})
|
68
|
+
request = build_purchase_or_authorization_request(money, payment_source, options)
|
69
|
+
commit(:authorization, request)
|
70
|
+
end
|
71
|
+
|
72
|
+
# Transfer pre-authorized funds immediately
|
73
|
+
# See: http://www.paymentexpress.com/technical_resources/ecommerce_nonhosted/pxpost.html#Authcomplete
|
74
|
+
def capture(money, identification, options = {})
|
75
|
+
request = build_capture_or_credit_request(money, identification, options)
|
76
|
+
commit(:capture, request)
|
77
|
+
end
|
78
|
+
|
79
|
+
# Refund funds to the card holder
|
80
|
+
def refund(money, identification, options = {})
|
81
|
+
requires!(options, :description)
|
82
|
+
|
83
|
+
request = build_capture_or_credit_request(money, identification, options)
|
84
|
+
commit(:credit, request)
|
85
|
+
end
|
86
|
+
|
87
|
+
def credit(money, identification, options = {})
|
88
|
+
deprecated CREDIT_DEPRECATION_MESSAGE
|
89
|
+
refund(money, identification, options)
|
90
|
+
end
|
91
|
+
|
92
|
+
# Token Based Billing
|
93
|
+
#
|
94
|
+
# Instead of storing the credit card details locally, you can store them inside the
|
95
|
+
# Payment Express system and instead bill future transactions against a token.
|
96
|
+
#
|
97
|
+
# This token can either be specified by your code or autogenerated by the PaymentExpress
|
98
|
+
# system. The default is to let PaymentExpress generate the token for you and so use
|
99
|
+
# the `DpsBillingId`. If you do not pass in any option of the `billing_id`, then the store
|
100
|
+
# method will ask PaymentExpress to create a token for you. Additionally, if you are
|
101
|
+
# using the default `DpsBillingId`, you do not have to do anything extra in the
|
102
|
+
# initialization of your gateway object.
|
103
|
+
#
|
104
|
+
# To specify and use your own token, you need to do two things.
|
105
|
+
#
|
106
|
+
# Firstly, pass in a `:billing_id` as an option in the hash of this store method. No
|
107
|
+
# validation is done on this BillingId by PaymentExpress so you must ensure that it is unique.
|
108
|
+
#
|
109
|
+
# gateway.store(credit_card, {:billing_id => 'YourUniqueBillingId'})
|
110
|
+
#
|
111
|
+
# Secondly, you will need to pass in the option `{:use_custom_payment_token => true}` when
|
112
|
+
# initializing your gateway instance, like so:
|
113
|
+
#
|
114
|
+
# gateway = ActiveMerchant::Billing::PaymentExpressGateway.new(
|
115
|
+
# :login => 'USERNAME',
|
116
|
+
# :password => 'PASSWORD',
|
117
|
+
# :use_custom_payment_token => true
|
118
|
+
# )
|
119
|
+
#
|
120
|
+
# see: http://www.paymentexpress.com/technical_resources/ecommerce_nonhosted/pxpost.html#Tokenbilling
|
121
|
+
#
|
122
|
+
# Note, once stored, PaymentExpress does not support unstoring a stored card.
|
123
|
+
def store(credit_card, options = {})
|
124
|
+
request = build_token_request(credit_card, options)
|
125
|
+
commit(:validate, request)
|
126
|
+
end
|
127
|
+
|
128
|
+
private
|
129
|
+
|
130
|
+
def use_custom_payment_token?
|
131
|
+
@options[:use_custom_payment_token]
|
132
|
+
end
|
133
|
+
|
134
|
+
def build_purchase_or_authorization_request(money, payment_source, options)
|
135
|
+
result = new_transaction
|
136
|
+
|
137
|
+
if payment_source.is_a?(String)
|
138
|
+
add_billing_token(result, payment_source)
|
139
|
+
else
|
140
|
+
add_credit_card(result, payment_source)
|
141
|
+
end
|
142
|
+
|
143
|
+
add_amount(result, money, options)
|
144
|
+
add_invoice(result, options)
|
145
|
+
add_address_verification_data(result, options)
|
146
|
+
result
|
147
|
+
end
|
148
|
+
|
149
|
+
def build_capture_or_credit_request(money, identification, options)
|
150
|
+
result = new_transaction
|
151
|
+
|
152
|
+
add_amount(result, money, options)
|
153
|
+
add_invoice(result, options)
|
154
|
+
add_reference(result, identification)
|
155
|
+
result
|
156
|
+
end
|
157
|
+
|
158
|
+
def build_token_request(credit_card, options)
|
159
|
+
result = new_transaction
|
160
|
+
add_credit_card(result, credit_card)
|
161
|
+
add_amount(result, 100, options) #need to make an auth request for $1
|
162
|
+
add_token_request(result, options)
|
163
|
+
result
|
164
|
+
end
|
165
|
+
|
166
|
+
def add_credentials(xml)
|
167
|
+
xml.add_element("PostUsername").text = @options[:login]
|
168
|
+
xml.add_element("PostPassword").text = @options[:password]
|
169
|
+
end
|
170
|
+
|
171
|
+
def add_reference(xml, identification)
|
172
|
+
xml.add_element("DpsTxnRef").text = identification
|
173
|
+
end
|
174
|
+
|
175
|
+
def add_credit_card(xml, credit_card)
|
176
|
+
xml.add_element("CardHolderName").text = credit_card.name
|
177
|
+
xml.add_element("CardNumber").text = credit_card.number
|
178
|
+
xml.add_element("DateExpiry").text = format_date(credit_card.month, credit_card.year)
|
179
|
+
|
180
|
+
if credit_card.verification_value?
|
181
|
+
xml.add_element("Cvc2").text = credit_card.verification_value
|
182
|
+
xml.add_element("Cvc2Presence").text = "1"
|
183
|
+
end
|
184
|
+
|
185
|
+
if requires_start_date_or_issue_number?(credit_card)
|
186
|
+
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?
|
187
|
+
xml.add_element("IssueNumber").text = credit_card.issue_number unless credit_card.issue_number.blank?
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
def add_billing_token(xml, token)
|
192
|
+
if use_custom_payment_token?
|
193
|
+
xml.add_element("BillingId").text = token
|
194
|
+
else
|
195
|
+
xml.add_element("DpsBillingId").text = token
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
def add_token_request(xml, options)
|
200
|
+
xml.add_element("BillingId").text = options[:billing_id] if options[:billing_id]
|
201
|
+
xml.add_element("EnableAddBillCard").text = 1
|
202
|
+
end
|
203
|
+
|
204
|
+
def add_amount(xml, money, options)
|
205
|
+
xml.add_element("Amount").text = amount(money)
|
206
|
+
xml.add_element("InputCurrency").text = options[:currency] || currency(money)
|
207
|
+
end
|
208
|
+
|
209
|
+
def add_transaction_type(xml, action)
|
210
|
+
xml.add_element("TxnType").text = TRANSACTIONS[action]
|
211
|
+
end
|
212
|
+
|
213
|
+
def add_invoice(xml, options)
|
214
|
+
xml.add_element("TxnId").text = options[:order_id].to_s.slice(0, 16) unless options[:order_id].blank?
|
215
|
+
xml.add_element("MerchantReference").text = options[:description] unless options[:description].blank?
|
216
|
+
end
|
217
|
+
|
218
|
+
def add_address_verification_data(xml, options)
|
219
|
+
address = options[:billing_address] || options[:address]
|
220
|
+
return if address.nil?
|
221
|
+
|
222
|
+
xml.add_element("EnableAvsData").text = 1
|
223
|
+
xml.add_element("AvsAction").text = 1
|
224
|
+
|
225
|
+
xml.add_element("AvsStreetAddress").text = address[:address1]
|
226
|
+
xml.add_element("AvsPostCode").text = address[:zip]
|
227
|
+
end
|
228
|
+
|
229
|
+
def new_transaction
|
230
|
+
REXML::Document.new.add_element("Txn")
|
231
|
+
end
|
232
|
+
|
233
|
+
# Take in the request and post it to DPS
|
234
|
+
def commit(action, request)
|
235
|
+
add_credentials(request)
|
236
|
+
add_transaction_type(request, action)
|
237
|
+
|
238
|
+
# Parse the XML response
|
239
|
+
response = parse( ssl_post(self.live_url, request.to_s) )
|
240
|
+
|
241
|
+
# Return a response
|
242
|
+
PaymentExpressResponse.new(response[:success] == APPROVED, response[:card_holder_help_text], response,
|
243
|
+
:test => response[:test_mode] == '1',
|
244
|
+
:authorization => response[:dps_txn_ref]
|
245
|
+
)
|
246
|
+
end
|
247
|
+
|
248
|
+
# Response XML documentation: http://www.paymentexpress.com/technical_resources/ecommerce_nonhosted/pxpost.html#XMLTxnOutput
|
249
|
+
def parse(xml_string)
|
250
|
+
response = {}
|
251
|
+
|
252
|
+
xml = REXML::Document.new(xml_string)
|
253
|
+
|
254
|
+
# Gather all root elements such as HelpText
|
255
|
+
xml.elements.each('Txn/*') do |element|
|
256
|
+
response[element.name.underscore.to_sym] = element.text unless element.name == 'Transaction'
|
257
|
+
end
|
258
|
+
|
259
|
+
# Gather all transaction elements and prefix with "account_"
|
260
|
+
# So we could access the MerchantResponseText by going
|
261
|
+
# response[account_merchant_response_text]
|
262
|
+
xml.elements.each('Txn/Transaction/*') do |element|
|
263
|
+
response[element.name.underscore.to_sym] = element.text
|
264
|
+
end
|
265
|
+
|
266
|
+
response
|
267
|
+
end
|
268
|
+
|
269
|
+
def format_date(month, year)
|
270
|
+
"#{format(month, :two_digits)}#{format(year, :two_digits)}"
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
class PaymentExpressResponse < Response
|
275
|
+
# add a method to response so we can easily get the token
|
276
|
+
# for Validate transactions
|
277
|
+
def token
|
278
|
+
@params["billing_id"] || @params["dps_billing_id"]
|
279
|
+
end
|
280
|
+
end
|
281
|
+
end
|
282
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/paypal/paypal_common_api'
|
2
|
+
require File.dirname(__FILE__) + '/paypal/paypal_recurring_api'
|
3
|
+
require File.dirname(__FILE__) + '/paypal_express'
|
4
|
+
|
5
|
+
module ActiveMerchant #:nodoc:
|
6
|
+
module Billing #:nodoc:
|
7
|
+
class PaypalGateway < Gateway
|
8
|
+
include PaypalCommonAPI
|
9
|
+
include PaypalRecurringApi
|
10
|
+
|
11
|
+
self.supported_cardtypes = [:visa, :master, :american_express, :discover]
|
12
|
+
self.supported_countries = ['US']
|
13
|
+
self.homepage_url = 'https://www.paypal.com/cgi-bin/webscr?cmd=_wp-pro-overview-outside'
|
14
|
+
self.display_name = 'PayPal Website Payments Pro (US)'
|
15
|
+
|
16
|
+
def authorize(money, credit_card_or_referenced_id, options = {})
|
17
|
+
requires!(options, :ip)
|
18
|
+
commit define_transaction_type(credit_card_or_referenced_id), build_sale_or_authorization_request('Authorization', money, credit_card_or_referenced_id, options)
|
19
|
+
end
|
20
|
+
|
21
|
+
def purchase(money, credit_card_or_referenced_id, options = {})
|
22
|
+
requires!(options, :ip)
|
23
|
+
commit define_transaction_type(credit_card_or_referenced_id), build_sale_or_authorization_request('Sale', money, credit_card_or_referenced_id, options)
|
24
|
+
end
|
25
|
+
|
26
|
+
def express
|
27
|
+
@express ||= PaypalExpressGateway.new(@options)
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def define_transaction_type(transaction_arg)
|
33
|
+
if transaction_arg.is_a?(String)
|
34
|
+
return 'DoReferenceTransaction'
|
35
|
+
else
|
36
|
+
return 'DoDirectPayment'
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def build_sale_or_authorization_request(action, money, credit_card_or_referenced_id, options)
|
41
|
+
transaction_type = define_transaction_type(credit_card_or_referenced_id)
|
42
|
+
reference_id = credit_card_or_referenced_id if transaction_type == "DoReferenceTransaction"
|
43
|
+
|
44
|
+
billing_address = options[:billing_address] || options[:address]
|
45
|
+
currency_code = options[:currency] || currency(money)
|
46
|
+
|
47
|
+
xml = Builder::XmlMarkup.new :indent => 2
|
48
|
+
xml.tag! transaction_type + 'Req', 'xmlns' => PAYPAL_NAMESPACE do
|
49
|
+
xml.tag! transaction_type + 'Request', 'xmlns:n2' => EBAY_NAMESPACE do
|
50
|
+
xml.tag! 'n2:Version', API_VERSION
|
51
|
+
xml.tag! 'n2:' + transaction_type + 'RequestDetails' do
|
52
|
+
xml.tag! 'n2:ReferenceID', reference_id if transaction_type == 'DoReferenceTransaction'
|
53
|
+
xml.tag! 'n2:PaymentAction', action
|
54
|
+
add_payment_details(xml, money, currency_code, options)
|
55
|
+
add_credit_card(xml, credit_card_or_referenced_id, billing_address, options) unless transaction_type == 'DoReferenceTransaction'
|
56
|
+
xml.tag! 'n2:IPAddress', options[:ip]
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
xml.target!
|
62
|
+
end
|
63
|
+
|
64
|
+
def add_credit_card(xml, credit_card, address, options)
|
65
|
+
xml.tag! 'n2:CreditCard' do
|
66
|
+
xml.tag! 'n2:CreditCardType', credit_card_type(card_brand(credit_card))
|
67
|
+
xml.tag! 'n2:CreditCardNumber', credit_card.number
|
68
|
+
xml.tag! 'n2:ExpMonth', format(credit_card.month, :two_digits)
|
69
|
+
xml.tag! 'n2:ExpYear', format(credit_card.year, :four_digits)
|
70
|
+
xml.tag! 'n2:CVV2', credit_card.verification_value
|
71
|
+
|
72
|
+
if [ 'switch', 'solo' ].include?(card_brand(credit_card).to_s)
|
73
|
+
xml.tag! 'n2:StartMonth', format(credit_card.start_month, :two_digits) unless credit_card.start_month.blank?
|
74
|
+
xml.tag! 'n2:StartYear', format(credit_card.start_year, :four_digits) unless credit_card.start_year.blank?
|
75
|
+
xml.tag! 'n2:IssueNumber', format(credit_card.issue_number, :two_digits) unless credit_card.issue_number.blank?
|
76
|
+
end
|
77
|
+
|
78
|
+
xml.tag! 'n2:CardOwner' do
|
79
|
+
xml.tag! 'n2:PayerName' do
|
80
|
+
xml.tag! 'n2:FirstName', credit_card.first_name
|
81
|
+
xml.tag! 'n2:LastName', credit_card.last_name
|
82
|
+
end
|
83
|
+
|
84
|
+
xml.tag! 'n2:Payer', options[:email]
|
85
|
+
add_address(xml, 'n2:Address', address)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def credit_card_type(type)
|
91
|
+
case type
|
92
|
+
when 'visa' then 'Visa'
|
93
|
+
when 'master' then 'MasterCard'
|
94
|
+
when 'discover' then 'Discover'
|
95
|
+
when 'american_express' then 'Amex'
|
96
|
+
when 'switch' then 'Switch'
|
97
|
+
when 'solo' then 'Solo'
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def build_response(success, message, response, options = {})
|
102
|
+
Response.new(success, message, response, options)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
@@ -0,0 +1,653 @@
|
|
1
|
+
module ActiveMerchant #:nodoc:
|
2
|
+
module Billing #:nodoc:
|
3
|
+
# This module is included in both PaypalGateway and PaypalExpressGateway
|
4
|
+
module PaypalCommonAPI
|
5
|
+
API_VERSION = '72'
|
6
|
+
|
7
|
+
URLS = {
|
8
|
+
:test => { :certificate => 'https://api.sandbox.paypal.com/2.0/',
|
9
|
+
:signature => 'https://api-3t.sandbox.paypal.com/2.0/' },
|
10
|
+
:live => { :certificate => 'https://api-aa.paypal.com/2.0/',
|
11
|
+
:signature => 'https://api-3t.paypal.com/2.0/' }
|
12
|
+
}
|
13
|
+
|
14
|
+
PAYPAL_NAMESPACE = 'urn:ebay:api:PayPalAPI'
|
15
|
+
EBAY_NAMESPACE = 'urn:ebay:apis:eBLBaseComponents'
|
16
|
+
|
17
|
+
ENVELOPE_NAMESPACES = { 'xmlns:xsd' => 'http://www.w3.org/2001/XMLSchema',
|
18
|
+
'xmlns:env' => 'http://schemas.xmlsoap.org/soap/envelope/',
|
19
|
+
'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance'
|
20
|
+
}
|
21
|
+
CREDENTIALS_NAMESPACES = { 'xmlns' => PAYPAL_NAMESPACE,
|
22
|
+
'xmlns:n1' => EBAY_NAMESPACE,
|
23
|
+
'env:mustUnderstand' => '0'
|
24
|
+
}
|
25
|
+
|
26
|
+
AUSTRALIAN_STATES = {
|
27
|
+
'ACT' => 'Australian Capital Territory',
|
28
|
+
'NSW' => 'New South Wales',
|
29
|
+
'NT' => 'Northern Territory',
|
30
|
+
'QLD' => 'Queensland',
|
31
|
+
'SA' => 'South Australia',
|
32
|
+
'TAS' => 'Tasmania',
|
33
|
+
'VIC' => 'Victoria',
|
34
|
+
'WA' => 'Western Australia'
|
35
|
+
}
|
36
|
+
|
37
|
+
SUCCESS_CODES = [ 'Success', 'SuccessWithWarning' ]
|
38
|
+
|
39
|
+
FRAUD_REVIEW_CODE = "11610"
|
40
|
+
|
41
|
+
def self.included(base)
|
42
|
+
base.default_currency = 'USD'
|
43
|
+
base.cattr_accessor :pem_file
|
44
|
+
base.cattr_accessor :signature
|
45
|
+
base.live_url = URLS[:live][:signature]
|
46
|
+
base.test_url = URLS[:test][:signature]
|
47
|
+
end
|
48
|
+
|
49
|
+
# The gateway must be configured with either your PayPal PEM file
|
50
|
+
# or your PayPal API Signature. Only one is required.
|
51
|
+
#
|
52
|
+
# <tt>:pem</tt> The text of your PayPal PEM file. Note
|
53
|
+
# this is not the path to file, but its
|
54
|
+
# contents. If you are only using one PEM
|
55
|
+
# file on your site you can declare it
|
56
|
+
# globally and then you won't need to
|
57
|
+
# include this option
|
58
|
+
#
|
59
|
+
# <tt>:signature</tt> The text of your PayPal signature.
|
60
|
+
# If you are only using one API Signature
|
61
|
+
# on your site you can declare it
|
62
|
+
# globally and then you won't need to
|
63
|
+
# include this option
|
64
|
+
def initialize(options = {})
|
65
|
+
requires!(options, :login, :password)
|
66
|
+
|
67
|
+
headers = {'X-PP-AUTHORIZATION' => options.delete(:auth_signature), 'X-PAYPAL-MESSAGE-PROTOCOL' => 'SOAP11'} if options[:auth_signature]
|
68
|
+
@options = {
|
69
|
+
:pem => pem_file,
|
70
|
+
:signature => signature,
|
71
|
+
:headers => headers || {}
|
72
|
+
}.update(options)
|
73
|
+
|
74
|
+
|
75
|
+
if @options[:pem].blank? && @options[:signature].blank?
|
76
|
+
raise ArgumentError, "An API Certificate or API Signature is required to make requests to PayPal"
|
77
|
+
end
|
78
|
+
|
79
|
+
super
|
80
|
+
end
|
81
|
+
|
82
|
+
def test?
|
83
|
+
@options[:test] || Base.gateway_mode == :test
|
84
|
+
end
|
85
|
+
|
86
|
+
def reauthorize(money, authorization, options = {})
|
87
|
+
commit 'DoReauthorization', build_reauthorize_request(money, authorization, options)
|
88
|
+
end
|
89
|
+
|
90
|
+
def capture(money, authorization, options = {})
|
91
|
+
commit 'DoCapture', build_capture_request(money, authorization, options)
|
92
|
+
end
|
93
|
+
|
94
|
+
# Transfer money to one or more recipients.
|
95
|
+
#
|
96
|
+
# gateway.transfer 1000, 'bob@example.com',
|
97
|
+
# :subject => "The money I owe you", :note => "Sorry it's so late"
|
98
|
+
#
|
99
|
+
# gateway.transfer [1000, 'fred@example.com'],
|
100
|
+
# [2450, 'wilma@example.com', :note => 'You will receive another payment on 3/24'],
|
101
|
+
# [2000, 'barney@example.com'],
|
102
|
+
# :subject => "Your Earnings", :note => "Thanks for your business."
|
103
|
+
#
|
104
|
+
def transfer(*args)
|
105
|
+
commit 'MassPay', build_mass_pay_request(*args)
|
106
|
+
end
|
107
|
+
|
108
|
+
def void(authorization, options = {})
|
109
|
+
commit 'DoVoid', build_void_request(authorization, options)
|
110
|
+
end
|
111
|
+
|
112
|
+
# Refunds a transaction.
|
113
|
+
#
|
114
|
+
# For a full refund pass nil for the amount:
|
115
|
+
#
|
116
|
+
# gateway.refund nil, 'G39883289DH238'
|
117
|
+
#
|
118
|
+
# This will automatically make the :refund_type be "Full".
|
119
|
+
#
|
120
|
+
# For a partial refund just pass the amount as usual:
|
121
|
+
#
|
122
|
+
# gateway.refund 100, 'UBU83983N920'
|
123
|
+
#
|
124
|
+
def refund(money, identification, options = {})
|
125
|
+
commit 'RefundTransaction', build_refund_request(money, identification, options)
|
126
|
+
end
|
127
|
+
|
128
|
+
def credit(money, identification, options = {})
|
129
|
+
deprecated Gateway::CREDIT_DEPRECATION_MESSAGE
|
130
|
+
refund(money, identification, options)
|
131
|
+
end
|
132
|
+
|
133
|
+
# ==== For full documentation see {Paypal API Reference:}[https://cms.paypal.com/us/cgi-bin/?cmd=_render-content&content_ID=developer/e_howto_api_soap_r_DoReferenceTransaction]
|
134
|
+
# ==== Parameter:
|
135
|
+
# * <tt>:money</tt> -- (Required) The amount of this new transaction,
|
136
|
+
# required fo the payment details portion of this request
|
137
|
+
#
|
138
|
+
# ==== Options:
|
139
|
+
# * <tt>:reference_id</tt> -- (Required) A transaction ID from a previous purchase, such as a credit card charge using the DoDirectPayment API, or a billing agreement ID.
|
140
|
+
# * <tt>:payment_action</tt> -- (Optional) How you want to obtain payment. It is one of the following values:
|
141
|
+
#
|
142
|
+
# Authorization – This payment is a basic authorization subject to settlement with PayPal Authorization and Capture.
|
143
|
+
# Sale – This is a final sale for which you are requesting payment.
|
144
|
+
#
|
145
|
+
# * <tt>:ip_address</tt> -- (Optional) IP address of the buyer’s browser.
|
146
|
+
# Note: PayPal records this IP addresses as a means to detect possible fraud.
|
147
|
+
# * <tt>:req_confirm_shipping</tt> -- Whether you require that the buyer’s shipping address on file with PayPal be a confirmed address. You must have permission from PayPal to not require a confirmed address. It is one of the following values:
|
148
|
+
#
|
149
|
+
# 0 – You do not require that the buyer’s shipping address be a confirmed address.
|
150
|
+
# 1 – You require that the buyer’s shipping address be a confirmed address.
|
151
|
+
#
|
152
|
+
# * <tt>:merchant_session_id</tt> -- (Optional) Your buyer session identification token.
|
153
|
+
# * <tt>:return_fmf_details</tt> -- (Optional) Flag to indicate whether you want the results returned by Fraud Management Filters. By default, you do not receive this information. It is one of the following values:
|
154
|
+
#
|
155
|
+
# 0 – Do not receive FMF details (default)
|
156
|
+
# 1 – Receive FMF details
|
157
|
+
#
|
158
|
+
# * <tt>:soft_descriptor</tt> -- (Optional) Per transaction description of the payment that is passed to the consumer’s credit card statement. If the API request provides a value for the soft descriptor field, the full descriptor displayed on the buyer’s statement has the following format:
|
159
|
+
#
|
160
|
+
# <PP * | PAYPAL *><Merchant descriptor as set in the Payment Receiving Preferences><1 space><soft descriptor>
|
161
|
+
# The soft descriptor can contain only the following characters:
|
162
|
+
#
|
163
|
+
# Alphanumeric characters
|
164
|
+
# - (dash)
|
165
|
+
# * (asterisk)
|
166
|
+
# . (period)
|
167
|
+
# {space}
|
168
|
+
#
|
169
|
+
def reference_transaction(money, options = {})
|
170
|
+
requires!(options, :reference_id)
|
171
|
+
commit 'DoReferenceTransaction', build_reference_transaction_request(money, options)
|
172
|
+
end
|
173
|
+
|
174
|
+
def transaction_details(transaction_id)
|
175
|
+
commit 'GetTransactionDetails', build_get_transaction_details(transaction_id)
|
176
|
+
end
|
177
|
+
|
178
|
+
# ==== For full documentation see {PayPal API Reference}[https://cms.paypal.com/us/cgi-bin/?cmd=_render-content&content_ID=developer/e_howto_api_soap_r_TransactionSearch]
|
179
|
+
# ==== Options:
|
180
|
+
# * <tt>:payer </tt> -- (Optional) Search by the buyer’s email address.
|
181
|
+
# * <tt>:receipt_id </tt> -- (Optional) Search by the PayPal Account Optional receipt ID.
|
182
|
+
# * <tt>:receiver </tt> -- (Optional) Search by the receiver’s email address. If the merchant account has only one email address, this is the primary email. It can also be a non-primary email address.
|
183
|
+
# * <tt>:transaction_id</tt> -- (Optional) Search by the transaction ID. The returned results are from the merchant’s transaction records.
|
184
|
+
# * <tt>:invoice_id</tt> -- (Optional) Search by invoice identification key, as set by you for the original transaction. This field searches the records for items the merchant sells, not the items purchased.
|
185
|
+
# * <tt>:card_number </tt> -- (Optional) Search by credit card number, as set by you for the original transaction. This field searches the records for items the merchant sells, not the items purchased.
|
186
|
+
# * <tt>:auction_item_number </tt> -- (Optional) Search by auction item number of the purchased goods.
|
187
|
+
# * <tt>:transaction_class </tt> -- (Optional) Search by classification of transaction. Some kinds of possible classes of transactions are not searchable with this field. You cannot search for bank transfer withdrawals, for example. It is one of the following values:
|
188
|
+
# All – All transaction classifications
|
189
|
+
# Sent – Only payments sent
|
190
|
+
# Received – Only payments received
|
191
|
+
# MassPay – Only mass payments
|
192
|
+
# MoneyRequest – Only money requests
|
193
|
+
# FundsAdded – Only funds added to balance
|
194
|
+
# FundsWithdrawn – Only funds withdrawn from balance
|
195
|
+
# Referral – Only transactions involving referrals
|
196
|
+
# Fee – Only transactions involving fees
|
197
|
+
# Subscription – Only transactions involving subscriptions
|
198
|
+
# Dividend – Only transactions involving dividends
|
199
|
+
# Billpay – Only transactions involving BillPay Transactions
|
200
|
+
# Refund – Only transactions involving funds
|
201
|
+
# CurrencyConversions – Only transactions involving currency conversions
|
202
|
+
# BalanceTransfer – Only transactions involving balance transfers
|
203
|
+
# Reversal – Only transactions involving BillPay reversals
|
204
|
+
# Shipping – Only transactions involving UPS shipping fees
|
205
|
+
# BalanceAffecting – Only transactions that affect the account balance
|
206
|
+
# ECheck – Only transactions involving eCheck
|
207
|
+
#
|
208
|
+
# * <tt>:currency_code </tt> -- (Optional) Search by currency code.
|
209
|
+
# * <tt>:status</tt> -- (Optional) Search by transaction status. It is one of the following values:
|
210
|
+
# One of:
|
211
|
+
# Pending – The payment is pending. The specific reason the payment is pending is returned by the GetTransactionDetails API PendingReason field.
|
212
|
+
# Processing – The payment is being processed.
|
213
|
+
# Success – The payment has been completed and the funds have been added successfully to your account balance.
|
214
|
+
# Denied – You denied the payment. This happens only if the payment was previously pending.
|
215
|
+
# Reversed – A payment was reversed due to a chargeback or other type of reversal. The funds have been removed from your account balance and returned to the buyer.
|
216
|
+
#
|
217
|
+
def transaction_search(options)
|
218
|
+
requires!(options, :start_date)
|
219
|
+
commit 'TransactionSearch', build_transaction_search(options)
|
220
|
+
end
|
221
|
+
|
222
|
+
# ==== Parameters:
|
223
|
+
# * <tt>:return_all_currencies</tt> -- Either '1' or '0'
|
224
|
+
# 0 – Return only the balance for the primary currency holding.
|
225
|
+
# 1 – Return the balance for each currency holding.
|
226
|
+
#
|
227
|
+
def balance(return_all_currencies = false)
|
228
|
+
clean_currency_argument = case return_all_currencies
|
229
|
+
when 1, '1' , true; '1'
|
230
|
+
else
|
231
|
+
'0'
|
232
|
+
end
|
233
|
+
commit 'GetBalance', build_get_balance(clean_currency_argument)
|
234
|
+
end
|
235
|
+
|
236
|
+
# DoAuthorization takes the transaction_id returned when you call
|
237
|
+
# DoExpressCheckoutPayment with a PaymentAction of 'Order'.
|
238
|
+
# When you did that, you created an order authorization subject to settlement
|
239
|
+
# with PayPal DoAuthorization and DoCapture
|
240
|
+
#
|
241
|
+
# ==== Parameters:
|
242
|
+
# * <tt>:transaction_id</tt> -- The ID returned by DoExpressCheckoutPayment with a PaymentAction of 'Order'.
|
243
|
+
# * <tt>:money</tt> -- The amount of money to be authorized for this purchase.
|
244
|
+
#
|
245
|
+
def authorize_transaction(transaction_id, money, options = {})
|
246
|
+
commit 'DoAuthorization', build_do_authorize(transaction_id, money, options)
|
247
|
+
end
|
248
|
+
|
249
|
+
# The ManagePendingTransactionStatus API operation accepts or denys a
|
250
|
+
# pending transaction held by Fraud Management Filters.
|
251
|
+
#
|
252
|
+
# ==== Parameters:
|
253
|
+
# * <tt>:transaction_id</tt> -- The ID of the transaction held by Fraud Management Filters.
|
254
|
+
# * <tt>:action</tt> -- Either 'Accept' or 'Deny'
|
255
|
+
#
|
256
|
+
def manage_pending_transaction(transaction_id, action)
|
257
|
+
commit 'ManagePendingTransactionStatus', build_manage_pending_transaction_status(transaction_id, action)
|
258
|
+
end
|
259
|
+
|
260
|
+
private
|
261
|
+
def build_request_wrapper(action, options = {})
|
262
|
+
xml = Builder::XmlMarkup.new :indent => 2
|
263
|
+
xml.tag! action + 'Req', 'xmlns' => PAYPAL_NAMESPACE do
|
264
|
+
xml.tag! action + 'Request', 'xmlns:n2' => EBAY_NAMESPACE do
|
265
|
+
xml.tag! 'n2:Version', API_VERSION
|
266
|
+
if options[:request_details]
|
267
|
+
xml.tag! 'n2:' + action + 'RequestDetails' do
|
268
|
+
yield(xml)
|
269
|
+
end
|
270
|
+
else
|
271
|
+
yield(xml)
|
272
|
+
end
|
273
|
+
end
|
274
|
+
end
|
275
|
+
xml.target!
|
276
|
+
end
|
277
|
+
|
278
|
+
def build_do_authorize(transaction_id, money, options = {})
|
279
|
+
build_request_wrapper('DoAuthorization') do |xml|
|
280
|
+
xml.tag! 'TransactionID', transaction_id
|
281
|
+
xml.tag! 'Amount', amount(money), 'currencyID' => options[:currency] || currency(money)
|
282
|
+
end
|
283
|
+
end
|
284
|
+
|
285
|
+
def build_reauthorize_request(money, authorization, options)
|
286
|
+
xml = Builder::XmlMarkup.new
|
287
|
+
|
288
|
+
xml.tag! 'DoReauthorizationReq', 'xmlns' => PAYPAL_NAMESPACE do
|
289
|
+
xml.tag! 'DoReauthorizationRequest', 'xmlns:n2' => EBAY_NAMESPACE do
|
290
|
+
xml.tag! 'n2:Version', API_VERSION
|
291
|
+
xml.tag! 'AuthorizationID', authorization
|
292
|
+
xml.tag! 'Amount', amount(money), 'currencyID' => options[:currency] || currency(money)
|
293
|
+
end
|
294
|
+
end
|
295
|
+
|
296
|
+
xml.target!
|
297
|
+
end
|
298
|
+
|
299
|
+
def build_capture_request(money, authorization, options)
|
300
|
+
xml = Builder::XmlMarkup.new
|
301
|
+
|
302
|
+
xml.tag! 'DoCaptureReq', 'xmlns' => PAYPAL_NAMESPACE do
|
303
|
+
xml.tag! 'DoCaptureRequest', 'xmlns:n2' => EBAY_NAMESPACE do
|
304
|
+
xml.tag! 'n2:Version', API_VERSION
|
305
|
+
xml.tag! 'AuthorizationID', authorization
|
306
|
+
xml.tag! 'Amount', amount(money), 'currencyID' => options[:currency] || currency(money)
|
307
|
+
xml.tag! 'CompleteType', options[:complete_type] || 'Complete'
|
308
|
+
xml.tag! 'InvoiceID', options[:order_id] unless options[:order_id].blank?
|
309
|
+
xml.tag! 'Note', options[:description]
|
310
|
+
end
|
311
|
+
end
|
312
|
+
|
313
|
+
xml.target!
|
314
|
+
end
|
315
|
+
|
316
|
+
def build_refund_request(money, identification, options)
|
317
|
+
xml = Builder::XmlMarkup.new
|
318
|
+
|
319
|
+
xml.tag! 'RefundTransactionReq', 'xmlns' => PAYPAL_NAMESPACE do
|
320
|
+
xml.tag! 'RefundTransactionRequest', 'xmlns:n2' => EBAY_NAMESPACE do
|
321
|
+
xml.tag! 'n2:Version', API_VERSION
|
322
|
+
xml.tag! 'TransactionID', identification
|
323
|
+
xml.tag! 'Amount', amount(money), 'currencyID' => (options[:currency] || currency(money)) if money.present?
|
324
|
+
xml.tag! 'RefundType', (options[:refund_type] || (money.present? ? 'Partial' : 'Full'))
|
325
|
+
xml.tag! 'Memo', options[:note] unless options[:note].blank?
|
326
|
+
end
|
327
|
+
end
|
328
|
+
|
329
|
+
xml.target!
|
330
|
+
end
|
331
|
+
|
332
|
+
def build_void_request(authorization, options)
|
333
|
+
xml = Builder::XmlMarkup.new
|
334
|
+
|
335
|
+
xml.tag! 'DoVoidReq', 'xmlns' => PAYPAL_NAMESPACE do
|
336
|
+
xml.tag! 'DoVoidRequest', 'xmlns:n2' => EBAY_NAMESPACE do
|
337
|
+
xml.tag! 'n2:Version', API_VERSION
|
338
|
+
xml.tag! 'AuthorizationID', authorization
|
339
|
+
xml.tag! 'Note', options[:description]
|
340
|
+
end
|
341
|
+
end
|
342
|
+
|
343
|
+
xml.target!
|
344
|
+
end
|
345
|
+
|
346
|
+
def build_mass_pay_request(*args)
|
347
|
+
default_options = args.last.is_a?(Hash) ? args.pop : {}
|
348
|
+
recipients = args.first.is_a?(Array) ? args : [args]
|
349
|
+
|
350
|
+
xml = Builder::XmlMarkup.new
|
351
|
+
|
352
|
+
xml.tag! 'MassPayReq', 'xmlns' => PAYPAL_NAMESPACE do
|
353
|
+
xml.tag! 'MassPayRequest', 'xmlns:n2' => EBAY_NAMESPACE do
|
354
|
+
xml.tag! 'n2:Version', API_VERSION
|
355
|
+
xml.tag! 'EmailSubject', default_options[:subject] if default_options[:subject]
|
356
|
+
recipients.each do |money, recipient, options|
|
357
|
+
options ||= default_options
|
358
|
+
xml.tag! 'MassPayItem' do
|
359
|
+
xml.tag! 'ReceiverEmail', recipient
|
360
|
+
xml.tag! 'Amount', amount(money), 'currencyID' => options[:currency] || currency(money)
|
361
|
+
xml.tag! 'Note', options[:note] if options[:note]
|
362
|
+
xml.tag! 'UniqueId', options[:unique_id] if options[:unique_id]
|
363
|
+
end
|
364
|
+
end
|
365
|
+
end
|
366
|
+
end
|
367
|
+
|
368
|
+
xml.target!
|
369
|
+
end
|
370
|
+
|
371
|
+
def build_manage_pending_transaction_status(transaction_id, action)
|
372
|
+
build_request_wrapper('ManagePendingTransactionStatus') do |xml|
|
373
|
+
xml.tag! 'TransactionID', transaction_id
|
374
|
+
xml.tag! 'Action', action
|
375
|
+
end
|
376
|
+
end
|
377
|
+
|
378
|
+
def build_reference_transaction_request(money, options)
|
379
|
+
opts = options.dup
|
380
|
+
opts[:ip_address] ||= opts[:ip]
|
381
|
+
currency_code = opts[:currency] || currency(money)
|
382
|
+
reference_transaction_optional_fields = %w{ n2:ReferenceID n2:PaymentAction
|
383
|
+
n2:PaymentType n2:IPAddress
|
384
|
+
n2:ReqConfirmShipping n2:MerchantSessionId
|
385
|
+
n2:ReturnFMFDetails n2:SoftDescriptor }
|
386
|
+
build_request_wrapper('DoReferenceTransaction', :request_details => true) do |xml|
|
387
|
+
add_optional_fields(xml, reference_transaction_optional_fields, opts)
|
388
|
+
add_payment_details(xml, money, currency_code, opts)
|
389
|
+
end
|
390
|
+
end
|
391
|
+
|
392
|
+
def build_get_transaction_details(transaction_id)
|
393
|
+
build_request_wrapper('GetTransactionDetails') do |xml|
|
394
|
+
xml.tag! 'TransactionID', transaction_id
|
395
|
+
end
|
396
|
+
end
|
397
|
+
|
398
|
+
def build_transaction_search(options)
|
399
|
+
currency_code = options[:currency_code]
|
400
|
+
currency_code ||= currency(options[:amount]) if options[:amount]
|
401
|
+
transaction_search_optional_fields = %w{ Payer ReceiptID Receiver
|
402
|
+
TransactionID InvoiceID CardNumber
|
403
|
+
AuctionItemNumber TransactionClass
|
404
|
+
CurrencyCode Status }
|
405
|
+
build_request_wrapper('TransactionSearch') do |xml|
|
406
|
+
xml.tag! 'StartDate', date_to_iso(options[:start_date])
|
407
|
+
xml.tag! 'EndDate', date_to_iso(options[:end_date]) unless options[:end_date].blank?
|
408
|
+
add_optional_fields(xml, transaction_search_optional_fields, options)
|
409
|
+
xml.tag! 'Amount', localized_amount(options[:amount], currency_code), 'currencyID' => currency_code unless options[:amount].blank?
|
410
|
+
end
|
411
|
+
end
|
412
|
+
|
413
|
+
|
414
|
+
def build_get_balance(return_all_currencies)
|
415
|
+
build_request_wrapper('GetBalance') do |xml|
|
416
|
+
xml.tag! 'ReturnAllCurrencies', return_all_currencies unless return_all_currencies.nil?
|
417
|
+
end
|
418
|
+
end
|
419
|
+
|
420
|
+
def parse(action, xml)
|
421
|
+
legacy_hash = legacy_parse(action, xml)
|
422
|
+
xml = strip_attributes(xml)
|
423
|
+
hash = Hash.from_xml(xml)
|
424
|
+
hash = hash.fetch('Envelope').fetch('Body').fetch("#{action}Response")
|
425
|
+
hash = hash["#{action}ResponseDetails"] if hash["#{action}ResponseDetails"]
|
426
|
+
|
427
|
+
legacy_hash.merge(hash)
|
428
|
+
rescue IndexError
|
429
|
+
legacy_hash.merge(hash['Envelope']['Body'])
|
430
|
+
end
|
431
|
+
|
432
|
+
def strip_attributes(xml)
|
433
|
+
xml = REXML::Document.new(xml)
|
434
|
+
REXML::XPath.each(xml, '//SOAP-ENV:Envelope//*[@*]') do |el|
|
435
|
+
el.attributes.each_attribute { |a| a.remove }
|
436
|
+
end
|
437
|
+
xml.to_s
|
438
|
+
end
|
439
|
+
|
440
|
+
def legacy_parse(action, xml)
|
441
|
+
response = {}
|
442
|
+
|
443
|
+
error_messages = []
|
444
|
+
error_codes = []
|
445
|
+
|
446
|
+
xml = REXML::Document.new(xml)
|
447
|
+
if root = REXML::XPath.first(xml, "//#{action}Response")
|
448
|
+
root.elements.each do |node|
|
449
|
+
case node.name
|
450
|
+
when 'Errors'
|
451
|
+
short_message = nil
|
452
|
+
long_message = nil
|
453
|
+
|
454
|
+
node.elements.each do |child|
|
455
|
+
case child.name
|
456
|
+
when "LongMessage"
|
457
|
+
long_message = child.text unless child.text.blank?
|
458
|
+
when "ShortMessage"
|
459
|
+
short_message = child.text unless child.text.blank?
|
460
|
+
when "ErrorCode"
|
461
|
+
error_codes << child.text unless child.text.blank?
|
462
|
+
end
|
463
|
+
end
|
464
|
+
|
465
|
+
if message = long_message || short_message
|
466
|
+
error_messages << message
|
467
|
+
end
|
468
|
+
else
|
469
|
+
legacy_parse_element(response, node)
|
470
|
+
end
|
471
|
+
end
|
472
|
+
response[:message] = error_messages.uniq.join(". ") unless error_messages.empty?
|
473
|
+
response[:error_codes] = error_codes.uniq.join(",") unless error_codes.empty?
|
474
|
+
elsif root = REXML::XPath.first(xml, "//SOAP-ENV:Fault")
|
475
|
+
legacy_parse_element(response, root)
|
476
|
+
response[:message] = "#{response[:faultcode]}: #{response[:faultstring]} - #{response[:detail]}"
|
477
|
+
end
|
478
|
+
|
479
|
+
response
|
480
|
+
end
|
481
|
+
|
482
|
+
def legacy_parse_element(response, node)
|
483
|
+
if node.has_elements?
|
484
|
+
node.elements.each{|e| legacy_parse_element(response, e) }
|
485
|
+
else
|
486
|
+
response[node.name.underscore.to_sym] = node.text
|
487
|
+
node.attributes.each do |k, v|
|
488
|
+
response["#{node.name.underscore}_#{k.underscore}".to_sym] = v if k == 'currencyID'
|
489
|
+
end
|
490
|
+
end
|
491
|
+
end
|
492
|
+
|
493
|
+
def build_request(body)
|
494
|
+
xml = Builder::XmlMarkup.new
|
495
|
+
|
496
|
+
xml.instruct!
|
497
|
+
xml.tag! 'env:Envelope', ENVELOPE_NAMESPACES do
|
498
|
+
xml.tag! 'env:Header' do
|
499
|
+
add_credentials(xml) unless @options[:headers] && @options[:headers]['X-PP-AUTHORIZATION']
|
500
|
+
end
|
501
|
+
|
502
|
+
xml.tag! 'env:Body' do
|
503
|
+
xml << body
|
504
|
+
end
|
505
|
+
end
|
506
|
+
xml.target!
|
507
|
+
end
|
508
|
+
|
509
|
+
def add_credentials(xml)
|
510
|
+
xml.tag! 'RequesterCredentials', CREDENTIALS_NAMESPACES do
|
511
|
+
xml.tag! 'n1:Credentials' do
|
512
|
+
xml.tag! 'Username', @options[:login]
|
513
|
+
xml.tag! 'Password', @options[:password]
|
514
|
+
xml.tag! 'Subject', @options[:subject]
|
515
|
+
xml.tag! 'Signature', @options[:signature] unless @options[:signature].blank?
|
516
|
+
end
|
517
|
+
end
|
518
|
+
end
|
519
|
+
|
520
|
+
def add_address(xml, element, address)
|
521
|
+
return if address.nil?
|
522
|
+
xml.tag! element do
|
523
|
+
xml.tag! 'n2:Name', address[:name]
|
524
|
+
xml.tag! 'n2:Street1', address[:address1]
|
525
|
+
xml.tag! 'n2:Street2', address[:address2]
|
526
|
+
xml.tag! 'n2:CityName', address[:city]
|
527
|
+
xml.tag! 'n2:StateOrProvince', address[:state].blank? ? 'N/A' : address[:state]
|
528
|
+
xml.tag! 'n2:Country', address[:country]
|
529
|
+
xml.tag! 'n2:Phone', address[:phone] unless address[:phone].blank?
|
530
|
+
xml.tag! 'n2:PostalCode', address[:zip]
|
531
|
+
end
|
532
|
+
end
|
533
|
+
|
534
|
+
def add_payment_details_items_xml(xml, options, currency_code)
|
535
|
+
options[:items].each do |item|
|
536
|
+
xml.tag! 'n2:PaymentDetailsItem' do
|
537
|
+
xml.tag! 'n2:Name', item[:name]
|
538
|
+
xml.tag! 'n2:Number', item[:number]
|
539
|
+
xml.tag! 'n2:Quantity', item[:quantity]
|
540
|
+
if item[:amount]
|
541
|
+
xml.tag! 'n2:Amount', localized_amount(item[:amount], currency_code), 'currencyID' => currency_code
|
542
|
+
end
|
543
|
+
xml.tag! 'n2:Description', item[:description]
|
544
|
+
xml.tag! 'n2:ItemURL', item[:url]
|
545
|
+
xml.tag! 'n2:ItemCategory', item[:category] if item[:category]
|
546
|
+
end
|
547
|
+
end
|
548
|
+
end
|
549
|
+
|
550
|
+
def add_payment_details(xml, money, currency_code, options = {})
|
551
|
+
xml.tag! 'n2:PaymentDetails' do
|
552
|
+
xml.tag! 'n2:OrderTotal', localized_amount(money, currency_code), 'currencyID' => currency_code
|
553
|
+
|
554
|
+
# All of the values must be included together and add up to the order total
|
555
|
+
if [:subtotal, :shipping, :handling, :tax].all?{ |o| options.has_key?(o) }
|
556
|
+
xml.tag! 'n2:ItemTotal', localized_amount(options[:subtotal], currency_code), 'currencyID' => currency_code
|
557
|
+
xml.tag! 'n2:ShippingTotal', localized_amount(options[:shipping], currency_code),'currencyID' => currency_code
|
558
|
+
xml.tag! 'n2:HandlingTotal', localized_amount(options[:handling], currency_code),'currencyID' => currency_code
|
559
|
+
xml.tag! 'n2:TaxTotal', localized_amount(options[:tax], currency_code), 'currencyID' => currency_code
|
560
|
+
end
|
561
|
+
|
562
|
+
xml.tag! 'n2:InsuranceTotal', localized_amount(options[:insurance_total], currency_code),'currencyID' => currency_code unless options[:insurance_total].blank?
|
563
|
+
xml.tag! 'n2:ShippingDiscount', localized_amount(options[:shipping_discount], currency_code),'currencyID' => currency_code unless options[:shipping_discount].blank?
|
564
|
+
xml.tag! 'n2:InsuranceOptionOffered', options[:insurance_option_offered] if options.has_key?(:insurance_option_offered)
|
565
|
+
|
566
|
+
xml.tag! 'n2:OrderDescription', options[:description] unless options[:description].blank?
|
567
|
+
|
568
|
+
# Custom field Character length and limitations: 256 single-byte alphanumeric characters
|
569
|
+
xml.tag! 'n2:Custom', options[:custom] unless options[:custom].blank?
|
570
|
+
|
571
|
+
xml.tag! 'n2:InvoiceID', (options[:order_id] || options[:invoice_id]) unless (options[:order_id] || options[:invoice_id]).blank?
|
572
|
+
xml.tag! 'n2:ButtonSource', application_id.to_s.slice(0,32) unless application_id.blank?
|
573
|
+
|
574
|
+
# The notify URL applies only to DoExpressCheckoutPayment.
|
575
|
+
# This value is ignored when set in SetExpressCheckout or GetExpressCheckoutDetails
|
576
|
+
xml.tag! 'n2:NotifyURL', options[:notify_url] unless options[:notify_url].blank?
|
577
|
+
|
578
|
+
add_address(xml, 'n2:ShipToAddress', options[:shipping_address]) unless options[:shipping_address].blank?
|
579
|
+
|
580
|
+
add_payment_details_items_xml(xml, options, currency_code) unless options[:items].blank?
|
581
|
+
|
582
|
+
add_express_only_payment_details(xml, options) if options[:express_request]
|
583
|
+
|
584
|
+
# Any value other than Y – This is not a recurring transaction
|
585
|
+
# To pass Y in this field, you must have established a billing agreement with
|
586
|
+
# the buyer specifying the amount, frequency, and duration of the recurring payment.
|
587
|
+
# requires version 80.0 of the API
|
588
|
+
xml.tag! 'n2:Recurring', options[:recurring] unless options[:recurring].blank?
|
589
|
+
end
|
590
|
+
end
|
591
|
+
|
592
|
+
def add_express_only_payment_details(xml, options = {})
|
593
|
+
add_optional_fields(xml,
|
594
|
+
%w{n2:NoteText n2:SoftDescriptor
|
595
|
+
n2:TransactionId n2:AllowedPaymentMethodType
|
596
|
+
n2:PaymentRequestID n2:PaymentAction},
|
597
|
+
options)
|
598
|
+
end
|
599
|
+
|
600
|
+
def add_optional_fields(xml, optional_fields, options = {})
|
601
|
+
optional_fields.each do |optional_text_field|
|
602
|
+
if optional_text_field =~ /(\w+:)(\w+)/
|
603
|
+
ns = $1
|
604
|
+
field = $2
|
605
|
+
field_as_symbol = field.underscore.to_sym
|
606
|
+
else
|
607
|
+
ns = ''
|
608
|
+
field = optional_text_field
|
609
|
+
field_as_symbol = optional_text_field.underscore.to_sym
|
610
|
+
end
|
611
|
+
xml.tag! ns + field, options[field_as_symbol] unless options[field_as_symbol].blank?
|
612
|
+
end
|
613
|
+
xml
|
614
|
+
end
|
615
|
+
|
616
|
+
def endpoint_url
|
617
|
+
URLS[test? ? :test : :live][@options[:signature].blank? ? :certificate : :signature]
|
618
|
+
end
|
619
|
+
|
620
|
+
def commit(action, request)
|
621
|
+
response = parse(action, ssl_post(endpoint_url, build_request(request), @options[:headers]))
|
622
|
+
|
623
|
+
build_response(successful?(response), message_from(response), response,
|
624
|
+
:test => test?,
|
625
|
+
:authorization => authorization_from(response),
|
626
|
+
:fraud_review => fraud_review?(response),
|
627
|
+
:avs_result => { :code => response[:avs_code] },
|
628
|
+
:cvv_result => response[:cvv2_code]
|
629
|
+
)
|
630
|
+
end
|
631
|
+
|
632
|
+
def fraud_review?(response)
|
633
|
+
response[:error_codes] == FRAUD_REVIEW_CODE
|
634
|
+
end
|
635
|
+
|
636
|
+
def authorization_from(response)
|
637
|
+
response[:transaction_id] || response[:authorization_id] || response[:refund_transaction_id] # middle one is from reauthorization
|
638
|
+
end
|
639
|
+
|
640
|
+
def successful?(response)
|
641
|
+
SUCCESS_CODES.include?(response[:ack])
|
642
|
+
end
|
643
|
+
|
644
|
+
def message_from(response)
|
645
|
+
response[:message] || response[:ack]
|
646
|
+
end
|
647
|
+
|
648
|
+
def date_to_iso(date)
|
649
|
+
(date.is_a?(Date) ? date.to_time : date).utc.iso8601
|
650
|
+
end
|
651
|
+
end
|
652
|
+
end
|
653
|
+
end
|