jelaniharris-activemerchant 1.24.1
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +893 -0
- data/CONTRIBUTORS +307 -0
- data/MIT-LICENSE +20 -0
- data/README.md +196 -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 +57 -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 +170 -0
- data/lib/active_merchant/billing/gateways.rb +18 -0
- data/lib/active_merchant/billing/gateways/authorize_net.rb +694 -0
- data/lib/active_merchant/billing/gateways/authorize_net_cim.rb +946 -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 +388 -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 +17 -0
- data/lib/active_merchant/billing/gateways/braintree/braintree_common.rb +9 -0
- data/lib/active_merchant/billing/gateways/braintree_blue.rb +335 -0
- data/lib/active_merchant/billing/gateways/braintree_orange.rb +21 -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 +279 -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 +137 -0
- data/lib/active_merchant/billing/gateways/epay.rb +276 -0
- data/lib/active_merchant/billing/gateways/eway.rb +277 -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/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/itransact.rb +450 -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/litle.rb +275 -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/migs.rb +259 -0
- data/lib/active_merchant/billing/gateways/migs/migs_codes.rb +100 -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 +250 -0
- data/lib/active_merchant/billing/gateways/moneris_us.rb +211 -0
- data/lib/active_merchant/billing/gateways/nab_transact.rb +255 -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 +422 -0
- data/lib/active_merchant/billing/gateways/optimal_payment.rb +277 -0
- data/lib/active_merchant/billing/gateways/orbital.rb +353 -0
- data/lib/active_merchant/billing/gateways/orbital/orbital_soft_descriptors.rb +46 -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 +199 -0
- data/lib/active_merchant/billing/gateways/payflow.rb +266 -0
- data/lib/active_merchant/billing/gateways/payflow/payflow_common_api.rb +211 -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 +640 -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/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 +298 -0
- data/lib/active_merchant/billing/gateways/realex.rb +313 -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/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 +281 -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 +271 -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 +25 -0
- data/lib/active_merchant/billing/gateways/trust_commerce.rb +437 -0
- data/lib/active_merchant/billing/gateways/usa_epay.rb +23 -0
- data/lib/active_merchant/billing/gateways/usa_epay_advanced.rb +1496 -0
- data/lib/active_merchant/billing/gateways/usa_epay_transaction.rb +202 -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 +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 +72 -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/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/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 +113 -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 +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/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/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 +447 -0
@@ -0,0 +1,388 @@
|
|
1
|
+
module ActiveMerchant #:nodoc:
|
2
|
+
module Billing #:nodoc:
|
3
|
+
module BeanstreamCore
|
4
|
+
URL = 'https://www.beanstream.com/scripts/process_transaction.asp'
|
5
|
+
RECURRING_URL = 'https://www.beanstream.com/scripts/recurring_billing.asp'
|
6
|
+
SECURE_PROFILE_URL = 'https://www.beanstream.com/scripts/payment_profile.asp'
|
7
|
+
SP_SERVICE_VERSION = '1.1'
|
8
|
+
|
9
|
+
TRANSACTIONS = {
|
10
|
+
:authorization => 'PA',
|
11
|
+
:purchase => 'P',
|
12
|
+
:capture => 'PAC',
|
13
|
+
:refund => 'R',
|
14
|
+
:void => 'VP',
|
15
|
+
:check_purchase => 'D',
|
16
|
+
:check_refund => 'C',
|
17
|
+
:void_purchase => 'VP',
|
18
|
+
:void_refund => 'VR'
|
19
|
+
}
|
20
|
+
|
21
|
+
PROFILE_OPERATIONS = {
|
22
|
+
:new => 'N',
|
23
|
+
:modify => 'M'
|
24
|
+
}
|
25
|
+
|
26
|
+
CVD_CODES = {
|
27
|
+
'1' => 'M',
|
28
|
+
'2' => 'N',
|
29
|
+
'3' => 'I',
|
30
|
+
'4' => 'S',
|
31
|
+
'5' => 'U',
|
32
|
+
'6' => 'P'
|
33
|
+
}
|
34
|
+
|
35
|
+
AVS_CODES = {
|
36
|
+
'0' => 'R',
|
37
|
+
'5' => 'I',
|
38
|
+
'9' => 'I'
|
39
|
+
}
|
40
|
+
|
41
|
+
PERIODS = {
|
42
|
+
:days => 'D',
|
43
|
+
:weeks => 'W',
|
44
|
+
:months => 'M',
|
45
|
+
:years => 'Y'
|
46
|
+
}
|
47
|
+
|
48
|
+
PERIODICITIES = {
|
49
|
+
:daily => [:days, 1],
|
50
|
+
:weekly => [:weeks, 1],
|
51
|
+
:biweekly => [:weeks, 2],
|
52
|
+
:monthly => [:months, 1],
|
53
|
+
:bimonthly => [:months, 2],
|
54
|
+
:yearly => [:years, 1]
|
55
|
+
}
|
56
|
+
|
57
|
+
RECURRING_OPERATION = {
|
58
|
+
:update => 'M',
|
59
|
+
:cancel => 'C'
|
60
|
+
}
|
61
|
+
|
62
|
+
def self.included(base)
|
63
|
+
base.default_currency = 'CAD'
|
64
|
+
|
65
|
+
# The countries the gateway supports merchants from as 2 digit ISO country codes
|
66
|
+
base.supported_countries = ['CA']
|
67
|
+
|
68
|
+
# The card types supported by the payment gateway
|
69
|
+
base.supported_cardtypes = [:visa, :master, :american_express]
|
70
|
+
|
71
|
+
# The homepage URL of the gateway
|
72
|
+
base.homepage_url = 'http://www.beanstream.com/'
|
73
|
+
|
74
|
+
# The name of the gateway
|
75
|
+
base.display_name = 'Beanstream.com'
|
76
|
+
end
|
77
|
+
|
78
|
+
# Only <tt>:login</tt> is required by default,
|
79
|
+
# which is the merchant's merchant ID. If you'd like to perform void,
|
80
|
+
# capture or refund transactions then you'll also need to add a username
|
81
|
+
# and password to your account under administration -> account settings ->
|
82
|
+
# order settings -> Use username/password validation
|
83
|
+
def initialize(options = {})
|
84
|
+
requires!(options, :login)
|
85
|
+
@options = options
|
86
|
+
super
|
87
|
+
end
|
88
|
+
|
89
|
+
def capture(money, authorization, options = {})
|
90
|
+
reference, amount, type = split_auth(authorization)
|
91
|
+
|
92
|
+
post = {}
|
93
|
+
add_amount(post, money)
|
94
|
+
add_reference(post, reference)
|
95
|
+
add_transaction_type(post, :capture)
|
96
|
+
commit(post)
|
97
|
+
end
|
98
|
+
|
99
|
+
def refund(money, source, options = {})
|
100
|
+
post = {}
|
101
|
+
reference, amount, type = split_auth(source)
|
102
|
+
add_reference(post, reference)
|
103
|
+
add_transaction_type(post, refund_action(type))
|
104
|
+
add_amount(post, money)
|
105
|
+
commit(post)
|
106
|
+
end
|
107
|
+
|
108
|
+
def credit(money, source, options = {})
|
109
|
+
deprecated Gateway::CREDIT_DEPRECATION_MESSAGE
|
110
|
+
refund(money, source, options)
|
111
|
+
end
|
112
|
+
|
113
|
+
private
|
114
|
+
def purchase_action(source)
|
115
|
+
if source.is_a?(Check)
|
116
|
+
:check_purchase
|
117
|
+
else
|
118
|
+
:purchase
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def void_action(original_transaction_type)
|
123
|
+
(original_transaction_type == TRANSACTIONS[:refund]) ? :void_refund : :void_purchase
|
124
|
+
end
|
125
|
+
|
126
|
+
def refund_action(type)
|
127
|
+
(type == TRANSACTIONS[:check_purchase]) ? :check_refund : :refund
|
128
|
+
end
|
129
|
+
|
130
|
+
def secure_profile_action(type)
|
131
|
+
PROFILE_OPERATIONS[type] || PROFILE_OPERATIONS[:new]
|
132
|
+
end
|
133
|
+
|
134
|
+
def split_auth(string)
|
135
|
+
string.split(";")
|
136
|
+
end
|
137
|
+
|
138
|
+
def add_amount(post, money)
|
139
|
+
post[:trnAmount] = amount(money)
|
140
|
+
end
|
141
|
+
|
142
|
+
def add_original_amount(post, amount)
|
143
|
+
post[:trnAmount] = amount
|
144
|
+
end
|
145
|
+
|
146
|
+
def add_reference(post, reference)
|
147
|
+
post[:adjId] = reference
|
148
|
+
end
|
149
|
+
|
150
|
+
def add_address(post, options)
|
151
|
+
prepare_address_for_non_american_countries(options)
|
152
|
+
|
153
|
+
if billing_address = options[:billing_address] || options[:address]
|
154
|
+
post[:ordName] = billing_address[:name]
|
155
|
+
post[:ordEmailAddress] = options[:email]
|
156
|
+
post[:ordPhoneNumber] = billing_address[:phone]
|
157
|
+
post[:ordAddress1] = billing_address[:address1]
|
158
|
+
post[:ordAddress2] = billing_address[:address2]
|
159
|
+
post[:ordCity] = billing_address[:city]
|
160
|
+
post[:ordProvince] = billing_address[:state]
|
161
|
+
post[:ordPostalCode] = billing_address[:zip]
|
162
|
+
post[:ordCountry] = billing_address[:country]
|
163
|
+
end
|
164
|
+
if shipping_address = options[:shipping_address]
|
165
|
+
post[:shipName] = shipping_address[:name]
|
166
|
+
post[:shipEmailAddress] = options[:email]
|
167
|
+
post[:shipPhoneNumber] = shipping_address[:phone]
|
168
|
+
post[:shipAddress1] = shipping_address[:address1]
|
169
|
+
post[:shipAddress2] = shipping_address[:address2]
|
170
|
+
post[:shipCity] = shipping_address[:city]
|
171
|
+
post[:shipProvince] = shipping_address[:state]
|
172
|
+
post[:shipPostalCode] = shipping_address[:zip]
|
173
|
+
post[:shipCountry] = shipping_address[:country]
|
174
|
+
post[:shippingMethod] = shipping_address[:shipping_method]
|
175
|
+
post[:deliveryEstimate] = shipping_address[:delivery_estimate]
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
def prepare_address_for_non_american_countries(options)
|
180
|
+
[ options[:billing_address], options[:shipping_address] ].compact.each do |address|
|
181
|
+
unless ['US', 'CA'].include?(address[:country])
|
182
|
+
address[:state] = '--'
|
183
|
+
address[:zip] = '000000' unless address[:zip]
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
def add_invoice(post, options)
|
189
|
+
post[:trnOrderNumber] = options[:order_id]
|
190
|
+
post[:trnComments] = options[:description]
|
191
|
+
post[:ordItemPrice] = amount(options[:subtotal])
|
192
|
+
post[:ordShippingPrice] = amount(options[:shipping])
|
193
|
+
post[:ordTax1Price] = amount(options[:tax1] || options[:tax])
|
194
|
+
post[:ordTax2Price] = amount(options[:tax2])
|
195
|
+
post[:ref1] = options[:custom]
|
196
|
+
end
|
197
|
+
|
198
|
+
def add_credit_card(post, credit_card)
|
199
|
+
if credit_card
|
200
|
+
post[:trnCardOwner] = credit_card.name
|
201
|
+
post[:trnCardNumber] = credit_card.number
|
202
|
+
post[:trnExpMonth] = format(credit_card.month, :two_digits)
|
203
|
+
post[:trnExpYear] = format(credit_card.year, :two_digits)
|
204
|
+
post[:trnCardCvd] = credit_card.verification_value
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
def add_check(post, check)
|
209
|
+
# The institution number of the consumer’s financial institution. Required for Canadian dollar EFT transactions.
|
210
|
+
post[:institutionNumber] = check.institution_number
|
211
|
+
|
212
|
+
# The bank transit number of the consumer’s bank account. Required for Canadian dollar EFT transactions.
|
213
|
+
post[:transitNumber] = check.transit_number
|
214
|
+
|
215
|
+
# The routing number of the consumer’s bank account. Required for US dollar EFT transactions.
|
216
|
+
post[:routingNumber] = check.routing_number
|
217
|
+
|
218
|
+
# The account number of the consumer’s bank account. Required for both Canadian and US dollar EFT transactions.
|
219
|
+
post[:accountNumber] = check.account_number
|
220
|
+
end
|
221
|
+
|
222
|
+
def add_secure_profile_variables(post, options = {})
|
223
|
+
post[:serviceVersion] = SP_SERVICE_VERSION
|
224
|
+
post[:responseFormat] = 'QS'
|
225
|
+
post[:cardValidation] = (options[:cardValidation].to_i == 1) || '0'
|
226
|
+
|
227
|
+
post[:operationType] = options[:operationType] || options[:operation] || secure_profile_action(:new)
|
228
|
+
post[:customerCode] = options[:billing_id] || options[:vault_id] || false
|
229
|
+
post[:status] = options[:status]
|
230
|
+
end
|
231
|
+
|
232
|
+
def add_recurring_amount(post, money)
|
233
|
+
post[:amount] = amount(money)
|
234
|
+
end
|
235
|
+
|
236
|
+
def add_recurring_invoice(post, options)
|
237
|
+
post[:rbApplyTax1] = options[:apply_tax1]
|
238
|
+
end
|
239
|
+
|
240
|
+
def add_recurring_operation_type(post, operation)
|
241
|
+
post[:operationType] = RECURRING_OPERATION[operation]
|
242
|
+
end
|
243
|
+
|
244
|
+
def add_recurring_service(post, options)
|
245
|
+
post[:serviceVersion] = '1.0'
|
246
|
+
post[:merchantId] = @options[:login]
|
247
|
+
post[:passCode] = @options[:recurring_api_key]
|
248
|
+
post[:rbAccountId] = options[:account_id]
|
249
|
+
end
|
250
|
+
|
251
|
+
def add_recurring_type(post, options)
|
252
|
+
# XXX requires!
|
253
|
+
post[:trnRecurring] = 1
|
254
|
+
period, increment = interval(options)
|
255
|
+
post[:rbBillingPeriod] = PERIODS[period]
|
256
|
+
post[:rbBillingIncrement] = increment
|
257
|
+
|
258
|
+
if options.include? :start_date
|
259
|
+
post[:rbCharge] = 0
|
260
|
+
post[:rbFirstBilling] = options[:start_date].strftime('%m%d%Y')
|
261
|
+
end
|
262
|
+
|
263
|
+
if count = options[:occurrences] || options[:payments]
|
264
|
+
post[:rbExpiry] = (options[:start_date] || Date.current).advance(period => count).strftime('%m%d%Y')
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
def interval(options)
|
269
|
+
if options.include? :periodicity
|
270
|
+
requires!(options, [:periodicity, *PERIODICITIES.keys])
|
271
|
+
PERIODICITIES[options[:periodicity]]
|
272
|
+
elsif options.include? :interval
|
273
|
+
interval = options[:interval]
|
274
|
+
if interval.respond_to? :parts
|
275
|
+
parts = interval.parts
|
276
|
+
raise ArgumentError.new("Cannot recur with mixed interval (#{interval}). Use only one of: days, weeks, months or years") if parts.length > 1
|
277
|
+
parts.first
|
278
|
+
elsif interval.kind_of? Hash
|
279
|
+
requires!(interval, :unit)
|
280
|
+
unit, length = interval.values_at(:unit, :length)
|
281
|
+
length ||= 1
|
282
|
+
[unit, length]
|
283
|
+
end
|
284
|
+
end
|
285
|
+
end
|
286
|
+
|
287
|
+
def parse(body)
|
288
|
+
results = {}
|
289
|
+
if !body.nil?
|
290
|
+
body.split(/&/).each do |pair|
|
291
|
+
key, val = pair.split(/=/)
|
292
|
+
results[key.to_sym] = val.nil? ? nil : CGI.unescape(val)
|
293
|
+
end
|
294
|
+
end
|
295
|
+
|
296
|
+
# Clean up the message text if there is any
|
297
|
+
if results[:messageText]
|
298
|
+
results[:messageText].gsub!(/<LI>/, "")
|
299
|
+
results[:messageText].gsub!(/(\.)?<br>/, ". ")
|
300
|
+
results[:messageText].strip!
|
301
|
+
end
|
302
|
+
|
303
|
+
results
|
304
|
+
end
|
305
|
+
|
306
|
+
def recurring_parse(data)
|
307
|
+
REXML::Document.new(data).root.elements.to_a.inject({}) do |response, element|
|
308
|
+
response[element.name.to_sym] = element.text
|
309
|
+
response
|
310
|
+
end
|
311
|
+
end
|
312
|
+
|
313
|
+
def commit(params, use_profile_api = false)
|
314
|
+
post(post_data(params,use_profile_api),use_profile_api)
|
315
|
+
end
|
316
|
+
|
317
|
+
def recurring_commit(params)
|
318
|
+
recurring_post(post_data(params, false))
|
319
|
+
end
|
320
|
+
|
321
|
+
def post(data, use_profile_api=nil)
|
322
|
+
response = parse(ssl_post((use_profile_api ? SECURE_PROFILE_URL : URL), data))
|
323
|
+
response[:customer_vault_id] = response[:customerCode] if response[:customerCode]
|
324
|
+
build_response(success?(response), message_from(response), response,
|
325
|
+
:test => test? || response[:authCode] == "TEST",
|
326
|
+
:authorization => authorization_from(response),
|
327
|
+
:cvv_result => CVD_CODES[response[:cvdId]],
|
328
|
+
:avs_result => { :code => (AVS_CODES.include? response[:avsId]) ? AVS_CODES[response[:avsId]] : response[:avsId] }
|
329
|
+
)
|
330
|
+
end
|
331
|
+
|
332
|
+
def recurring_post(data)
|
333
|
+
response = recurring_parse(ssl_post(RECURRING_URL, data))
|
334
|
+
build_response(recurring_success?(response), recurring_message_from(response), response)
|
335
|
+
end
|
336
|
+
|
337
|
+
def authorization_from(response)
|
338
|
+
"#{response[:trnId]};#{response[:trnAmount]};#{response[:trnType]}"
|
339
|
+
end
|
340
|
+
|
341
|
+
def message_from(response)
|
342
|
+
response[:messageText] || response[:responseMessage]
|
343
|
+
end
|
344
|
+
|
345
|
+
def recurring_message_from(response)
|
346
|
+
response[:message]
|
347
|
+
end
|
348
|
+
|
349
|
+
def success?(response)
|
350
|
+
response[:responseType] == 'R' || response[:trnApproved] == '1' || response[:responseCode] == '1'
|
351
|
+
end
|
352
|
+
|
353
|
+
def recurring_success?(response)
|
354
|
+
response[:code] == '1'
|
355
|
+
end
|
356
|
+
|
357
|
+
def add_source(post, source)
|
358
|
+
if source.is_a?(String) or source.is_a?(Integer)
|
359
|
+
post[:customerCode] = source
|
360
|
+
else
|
361
|
+
card_brand(source) == "check" ? add_check(post, source) : add_credit_card(post, source)
|
362
|
+
end
|
363
|
+
end
|
364
|
+
|
365
|
+
def add_transaction_type(post, action)
|
366
|
+
post[:trnType] = TRANSACTIONS[action]
|
367
|
+
end
|
368
|
+
|
369
|
+
def post_data(params, use_profile_api)
|
370
|
+
params[:requestType] = 'BACKEND'
|
371
|
+
if use_profile_api
|
372
|
+
params[:merchantId] = @options[:login]
|
373
|
+
params[:passCode] = @options[:secure_profile_api_key]
|
374
|
+
else
|
375
|
+
params[:username] = @options[:user] if @options[:user]
|
376
|
+
params[:password] = @options[:password] if @options[:password]
|
377
|
+
params[:merchant_id] = @options[:login]
|
378
|
+
end
|
379
|
+
params[:vbvEnabled] = '0'
|
380
|
+
params[:scEnabled] = '0'
|
381
|
+
|
382
|
+
params.reject{|k, v| v.blank?}.collect { |key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join("&")
|
383
|
+
end
|
384
|
+
|
385
|
+
end
|
386
|
+
end
|
387
|
+
end
|
388
|
+
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/beanstream/beanstream_core'
|
2
|
+
|
3
|
+
module ActiveMerchant #:nodoc:
|
4
|
+
module Billing #:nodoc:
|
5
|
+
class BeanstreamInteracResponse < Response
|
6
|
+
def redirect
|
7
|
+
params['pageContents']
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class BeanstreamInteracGateway < Gateway
|
12
|
+
include BeanstreamCore
|
13
|
+
|
14
|
+
# Confirm a transaction posted back from the bank to Beanstream.
|
15
|
+
# Confirming a transaction does not require any credentials,
|
16
|
+
# and in an application with many merchants sharing a funded
|
17
|
+
# URL the application may not yet know which merchant the
|
18
|
+
# post back is for until the response of the confirmation is
|
19
|
+
# received, which contains the order number.
|
20
|
+
def self.confirm(transaction)
|
21
|
+
gateway = new(:login => '')
|
22
|
+
gateway.confirm(transaction)
|
23
|
+
end
|
24
|
+
|
25
|
+
def purchase(money, options = {})
|
26
|
+
post = {}
|
27
|
+
add_amount(post, money)
|
28
|
+
add_invoice(post, options)
|
29
|
+
add_address(post, options)
|
30
|
+
add_interac_details(post, options)
|
31
|
+
add_transaction_type(post, :purchase)
|
32
|
+
commit(post)
|
33
|
+
end
|
34
|
+
|
35
|
+
# Confirm a transaction posted back from the bank to Beanstream.
|
36
|
+
def confirm(transaction)
|
37
|
+
post(transaction)
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def add_interac_details(post, options)
|
43
|
+
address = options[:billing_address] || options[:address] || {}
|
44
|
+
post[:trnCardOwner] = address[:name]
|
45
|
+
post[:paymentMethod] = 'IO'
|
46
|
+
end
|
47
|
+
|
48
|
+
def build_response(*args)
|
49
|
+
BeanstreamInteracResponse.new(*args)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
@@ -0,0 +1,492 @@
|
|
1
|
+
require 'digest/md5'
|
2
|
+
|
3
|
+
module ActiveMerchant #:nodoc:
|
4
|
+
module Billing #:nodoc:
|
5
|
+
class BluePayGateway < Gateway
|
6
|
+
class_attribute :live_url, :rebilling_url, :ignore_http_status
|
7
|
+
|
8
|
+
self.live_url = 'https://secure.bluepay.com/interfaces/bp20post'
|
9
|
+
self.rebilling_url = 'https://secure.bluepay.com/interfaces/bp20rebadmin'
|
10
|
+
|
11
|
+
self.ignore_http_status = true
|
12
|
+
|
13
|
+
RESPONSE_CODE, RESPONSE_REASON_CODE, RESPONSE_REASON_TEXT = 0, 2, 3
|
14
|
+
AVS_RESULT_CODE, TRANSACTION_ID, CARD_CODE_RESPONSE_CODE = 5, 6, 38
|
15
|
+
|
16
|
+
CARD_CODE_ERRORS = %w( N S )
|
17
|
+
AVS_ERRORS = %w( A E N R W Z )
|
18
|
+
AVS_REASON_CODES = %w(27 45)
|
19
|
+
|
20
|
+
class_attribute :duplicate_window
|
21
|
+
|
22
|
+
self.supported_countries = ['US']
|
23
|
+
self.supported_cardtypes = [:visa, :master, :american_express, :discover, :diners_club, :jcb]
|
24
|
+
self.homepage_url = 'http://www.bluepay.com/'
|
25
|
+
self.display_name = 'BluePay'
|
26
|
+
self.money_format = :dollars
|
27
|
+
|
28
|
+
|
29
|
+
# Creates a new BluepayGateway
|
30
|
+
#
|
31
|
+
# The gateway requires that a valid Account ID and Secret Key be passed
|
32
|
+
# in the +options+ hash.
|
33
|
+
#
|
34
|
+
# ==== Options
|
35
|
+
#
|
36
|
+
# * <tt>:account_id</tt> -- The BluePay gateway Account ID (REQUIRED)
|
37
|
+
# * <tt>:secret_key</tt> -- The BluePay gateway Secret Key (REQUIRED)
|
38
|
+
# * <tt>:test</tt> -- set to true for TEST mode or false for LIVE mode
|
39
|
+
def initialize(options = {})
|
40
|
+
requires!(options, :login, :password)
|
41
|
+
@options = options
|
42
|
+
super
|
43
|
+
end
|
44
|
+
|
45
|
+
# Performs an authorization, which reserves the funds on the customer's credit card. This does not actually take funds from the customer
|
46
|
+
# This is referred to an AUTH transaction in BluePay
|
47
|
+
#
|
48
|
+
# ==== Parameters
|
49
|
+
#
|
50
|
+
# * <tt>money</tt> -- The amount to be authorized as an Integer value in cents.
|
51
|
+
# * <tt>payment_object</tt> -- This can either be one of three things:
|
52
|
+
# A CreditCard object,
|
53
|
+
# A Check object,
|
54
|
+
# or a token. The token is called the Master ID. This is a unique transaction ID returned from a previous transaction. This token associates all the stored information for a previous transaction.
|
55
|
+
# * <tt>options</tt> -- A hash of optional parameters.
|
56
|
+
def authorize(money, payment_object, options = {})
|
57
|
+
post = {}
|
58
|
+
post[:MASTER_ID] = ''
|
59
|
+
if payment_object != nil && payment_object.class() != String
|
60
|
+
payment_object.class() == ActiveMerchant::Billing::Check ?
|
61
|
+
add_check(post, payment_object) :
|
62
|
+
add_creditcard(post, payment_object)
|
63
|
+
else
|
64
|
+
post[:MASTER_ID] = payment_object
|
65
|
+
end
|
66
|
+
add_invoice(post, options)
|
67
|
+
add_address(post, options)
|
68
|
+
add_customer_data(post, options)
|
69
|
+
if options[:rebill] != nil
|
70
|
+
post[:DO_REBILL] = '1'
|
71
|
+
post[:REB_AMOUNT] = amount(options[:rebill_amount])
|
72
|
+
post[:REB_FIRST_DATE] = options[:rebill_start_date]
|
73
|
+
post[:REB_EXPR] = options[:rebill_expression]
|
74
|
+
post[:REB_CYCLES] = options[:rebill_cycles]
|
75
|
+
end
|
76
|
+
post[:TRANS_TYPE] = 'AUTH'
|
77
|
+
commit('AUTH_ONLY', money, post)
|
78
|
+
end
|
79
|
+
|
80
|
+
# Perform a purchase, which is essentially an authorization and capture in a single operation.
|
81
|
+
# This is referred to a SALE transaction in BluePay
|
82
|
+
#
|
83
|
+
# ==== Parameters
|
84
|
+
#
|
85
|
+
# * <tt>money</tt> -- The amount to be purchased as an Integer value in cents.
|
86
|
+
# * <tt>payment_object</tt> -- This can either be one of three things:
|
87
|
+
# A CreditCard object,
|
88
|
+
# A Check object,
|
89
|
+
# or a token. The token is called the Master ID. This is a unique transaction ID returned from a previous transaction. This token associates all the stored information for a previous transaction.
|
90
|
+
# * <tt>options</tt> -- A hash of optional parameters.,
|
91
|
+
def purchase(money, payment_object, options = {})
|
92
|
+
post = {}
|
93
|
+
post[:MASTER_ID] = ''
|
94
|
+
if payment_object != nil && payment_object.class() != String
|
95
|
+
payment_object.class() == ActiveMerchant::Billing::Check ?
|
96
|
+
add_check(post, payment_object) :
|
97
|
+
add_creditcard(post, payment_object)
|
98
|
+
else
|
99
|
+
post[:MASTER_ID] = payment_object
|
100
|
+
end
|
101
|
+
add_invoice(post, options)
|
102
|
+
add_address(post, options)
|
103
|
+
add_customer_data(post, options)
|
104
|
+
if options[:rebill] != nil
|
105
|
+
post[:DO_REBILL] = '1'
|
106
|
+
post[:REB_AMOUNT] = amount(options[:rebill_amount])
|
107
|
+
post[:REB_FIRST_DATE] = options[:rebill_start_date]
|
108
|
+
post[:REB_EXPR] = options[:rebill_expression]
|
109
|
+
post[:REB_CYCLES] = options[:rebill_cycles]
|
110
|
+
end
|
111
|
+
post[:TRANS_TYPE] = 'SALE'
|
112
|
+
commit('AUTH_CAPTURE', money, post)
|
113
|
+
end
|
114
|
+
|
115
|
+
# Captures the funds from an authorize transaction.
|
116
|
+
# This is referred to a CAPTURE transaction in BluePay
|
117
|
+
#
|
118
|
+
# ==== Parameters
|
119
|
+
#
|
120
|
+
# * <tt>money</tt> -- The amount to be captured as an Integer value in cents.
|
121
|
+
# * <tt>identification</tt> -- The Master ID, or token, returned from the previous authorize transaction.
|
122
|
+
def capture(money, identification, options = {})
|
123
|
+
post = {}
|
124
|
+
add_address(post, options)
|
125
|
+
add_customer_data(post, options)
|
126
|
+
post[:MASTER_ID] = identification
|
127
|
+
post[:TRANS_TYPE] = 'CAPTURE'
|
128
|
+
commit('PRIOR_AUTH_CAPTURE', money, post)
|
129
|
+
end
|
130
|
+
|
131
|
+
# Void a previous transaction
|
132
|
+
# This is referred to a VOID transaction in BluePay
|
133
|
+
#
|
134
|
+
# ==== Parameters
|
135
|
+
#
|
136
|
+
# * <tt>identification</tt> - The Master ID, or token, returned from a previous authorize transaction.
|
137
|
+
def void(identification, options = {})
|
138
|
+
post = {}
|
139
|
+
post[:MASTER_ID] = identification
|
140
|
+
post[:TRANS_TYPE] = 'VOID'
|
141
|
+
commit('VOID', nil, post)
|
142
|
+
end
|
143
|
+
|
144
|
+
# Performs a credit.
|
145
|
+
#
|
146
|
+
# This transaction indicates that money should flow from the merchant to the customer.
|
147
|
+
#
|
148
|
+
# ==== Parameters
|
149
|
+
#
|
150
|
+
# * <tt>money</tt> -- The amount to be credited to the customer as an Integer value in cents.
|
151
|
+
# * <tt>payment_object</tt> -- This can either be one of three things:
|
152
|
+
# A CreditCard object,
|
153
|
+
# A Check object,
|
154
|
+
# or a token. The token is called the Master ID. This is a unique transaction ID returned from a previous transaction. This token associates all the stored information for a previous transaction.
|
155
|
+
# If the payment_object is a token, then the transaction type will reverse a previous capture or purchase transaction, returning the funds to the customer. If the amount is nil, a full credit will be processed. This is referred to a REFUND transaction in BluePay.
|
156
|
+
# If the payment_object is either a CreditCard or Check object, then the transaction type will be an unmatched credit placing funds in the specified account. This is referred to a CREDIT transaction in BluePay.
|
157
|
+
# * <tt>options</tt> -- A hash of parameters.
|
158
|
+
def refund(money, payment_object, options = {})
|
159
|
+
post = {}
|
160
|
+
post[:PAYMENT_ACCOUNT] = ''
|
161
|
+
if payment_object != nil && payment_object.class() != String
|
162
|
+
payment_object.class() == ActiveMerchant::Billing::Check ?
|
163
|
+
add_check(post, payment_object) :
|
164
|
+
add_creditcard(post, payment_object)
|
165
|
+
post[:TRANS_TYPE] = 'CREDIT'
|
166
|
+
else
|
167
|
+
post[:MASTER_ID] = payment_object
|
168
|
+
post[:TRANS_TYPE] = 'REFUND'
|
169
|
+
end
|
170
|
+
|
171
|
+
options[:first_name] ? post[:NAME1] = options[:first_name] : post[:NAME1] = ''
|
172
|
+
post[:NAME2] = options[:last_name] if options[:last_name]
|
173
|
+
post[:ZIP] = options[:zip] if options[:zip]
|
174
|
+
add_invoice(post, options)
|
175
|
+
add_address(post, options)
|
176
|
+
add_customer_data(post, options)
|
177
|
+
commit('CREDIT', money, post)
|
178
|
+
end
|
179
|
+
|
180
|
+
def credit(money, identification, options = {})
|
181
|
+
deprecated CREDIT_DEPRECATION_MESSAGE
|
182
|
+
refund(money, identification, options)
|
183
|
+
end
|
184
|
+
|
185
|
+
# Create a new recurring payment.
|
186
|
+
#
|
187
|
+
# ==== Parameters
|
188
|
+
#
|
189
|
+
# * <tt>money</tt> -- The amount to charge the customer at the time of the recurring payment setup, in cents. Set to zero if you do not want the customer to be charged at this time.
|
190
|
+
# * <tt>payment_object</tt> -- This can either be one of three things:
|
191
|
+
# A CreditCard object,
|
192
|
+
# A Check object,
|
193
|
+
# or a token. The token is called the Master ID. This is a unique transaction ID returned from a previous transaction. This token associates all the stored information for a previous transaction.
|
194
|
+
# * <tt>options</tt> -- A hash of optional parameters.,
|
195
|
+
|
196
|
+
# ==== Options
|
197
|
+
#
|
198
|
+
# * <tt>:rebill_start_date</tt> is a string that tells the gateway when to start the rebill. (REQUIRED)
|
199
|
+
# Has two valid formats:
|
200
|
+
# "YYYY-MM-DD HH:MM:SS" Hours, minutes, and seconds are optional.
|
201
|
+
# "XX UNITS" Relative date as explained below. Marked from the time of the
|
202
|
+
# transaction (i.e.: 10 DAYS, 1 MONTH, 1 YEAR)
|
203
|
+
# * <tt>:rebill_expression</tt> is the period of time in-between rebillings. (REQUIRED)
|
204
|
+
# It uses the same "XX UNITS" format as rebill_start_date, explained above.
|
205
|
+
# Optional parameters include:
|
206
|
+
# * <tt>rebill_cycles</tt>: Number of times to rebill. Don't send or set to nil for infinite rebillings (or
|
207
|
+
# until canceled).
|
208
|
+
# * <tt>rebill_amount</tt>: Amount to rebill. Defaults to amount of transaction for rebillings.
|
209
|
+
#
|
210
|
+
# For example, to charge the customer $19.95 now and then charge $39.95 in 60 days every 3 months for 5 times, the options hash would be as follows:
|
211
|
+
# :rebill_start_date => '60 DAYS',
|
212
|
+
# :rebill_expression => '3 MONTHS',
|
213
|
+
# :rebill_cycles => '5',
|
214
|
+
# :rebill_amount => '39.95'
|
215
|
+
# A money object of 1995 cents would be passed into the 'money' parameter.
|
216
|
+
def recurring(money, payment_object, options = {})
|
217
|
+
requires!(options, :rebill_start_date, :rebill_expression)
|
218
|
+
options[:rebill] = '1'
|
219
|
+
money == nil ? authorize(money, payment_object, options) :
|
220
|
+
purchase(money, payment_object, options)
|
221
|
+
end
|
222
|
+
|
223
|
+
# View a recurring payment
|
224
|
+
#
|
225
|
+
# This will pull data associated with a current recurring billing
|
226
|
+
#
|
227
|
+
# ==== Parameters
|
228
|
+
#
|
229
|
+
# * <tt>rebill_id</tt> -- A string containing the rebill_id of the recurring billing that is already active (REQUIRED)
|
230
|
+
def status_recurring(rebill_id)
|
231
|
+
post = {}
|
232
|
+
requires!(rebill_id)
|
233
|
+
post[:REBILL_ID] = rebill_id
|
234
|
+
post[:TRANS_TYPE] = 'GET'
|
235
|
+
commit('rebill', 'nil', post)
|
236
|
+
end
|
237
|
+
|
238
|
+
# Update a recurring payment's details.
|
239
|
+
#
|
240
|
+
# This transaction updates an existing recurring billing
|
241
|
+
#
|
242
|
+
# ==== Options
|
243
|
+
#
|
244
|
+
# * <tt>:rebill_id</tt> -- The 12 digit rebill ID used to update a particular rebilling cycle. (REQUIRED)
|
245
|
+
# * <tt>:rebill_amount</tt> -- A string containing the new rebilling amount.
|
246
|
+
# * <tt>:rebill_next_date</tt> -- A string containing the new rebilling next date.
|
247
|
+
# * <tt>:rebill_expression</tt> -- A string containing the new rebilling expression.
|
248
|
+
# * <tt>:rebill_cycles</tt> -- A string containing the new rebilling cycles.
|
249
|
+
# * <tt>:rebill_next_amount</tt> -- A string containing the next rebilling amount to charge the customer. This ONLY affects the next scheduled charge; all other rebillings will continue at the regular (rebill_amount) amount.
|
250
|
+
# Take a look above at the recurring_payment method for similar examples on how to use.
|
251
|
+
def update_recurring(options = {})
|
252
|
+
post = {}
|
253
|
+
requires!(options, :rebill_id)
|
254
|
+
post[:REBILL_ID] = options[:rebill_id]
|
255
|
+
post[:TRANS_TYPE] = 'SET'
|
256
|
+
post[:REB_AMOUNT] = amount(options[:rebill_amount]) if !options[:rebill_amount].nil?
|
257
|
+
post[:NEXT_DATE] = options[:rebill_next_date] if !options[:rebill_next_date].nil?
|
258
|
+
post[:REB_EXPR] = options[:rebill_expression] if !options[:rebill_expression].nil?
|
259
|
+
post[:REB_CYCLES] = options[:rebill_cycles] if !options[:rebill_cycles].nil?
|
260
|
+
post[:NEXT_AMOUNT] = options[:rebill_next_amount] if !options[:rebill_next_amount].nil?
|
261
|
+
commit('rebill', 'nil', post)
|
262
|
+
end
|
263
|
+
|
264
|
+
# Cancel a recurring payment.
|
265
|
+
#
|
266
|
+
# This transaction cancels an existing recurring billing.
|
267
|
+
#
|
268
|
+
# ==== Parameters
|
269
|
+
#
|
270
|
+
# * <tt>rebill_id</tt> -- A string containing the rebill_id of the recurring billing that you wish to cancel/stop (REQUIRED)
|
271
|
+
def cancel_recurring(rebill_id)
|
272
|
+
post = {}
|
273
|
+
requires!(rebill_id)
|
274
|
+
post[:REBILL_ID] = rebill_id
|
275
|
+
post[:TRANS_TYPE] = 'SET'
|
276
|
+
post[:STATUS] = 'stopped'
|
277
|
+
commit('rebill', 'nil', post)
|
278
|
+
end
|
279
|
+
|
280
|
+
private
|
281
|
+
|
282
|
+
def commit(action, money, fields)
|
283
|
+
fields[:AMOUNT] = amount(money) unless (fields[:TRANS_TYPE] == 'VOID' or action == 'rebill')
|
284
|
+
test? == true || @options[:test] == true ? fields[:MODE] = 'TEST' : fields[:MODE] = 'LIVE'
|
285
|
+
action == 'rebill' ? begin url = rebilling_url; fields[:TAMPER_PROOF_SEAL] = calc_rebill_tps(fields) end : begin url = live_url; fields[:TAMPER_PROOF_SEAL] = calc_tps(amount(money), fields) end
|
286
|
+
fields[:ACCOUNT_ID] = @options[:login]
|
287
|
+
data = ssl_post url, post_data(action, fields)
|
288
|
+
response = parse(data)
|
289
|
+
message = message_from(response)
|
290
|
+
test_mode = test? || fields[:MODE] == 'TEST'
|
291
|
+
if (response.has_key?('TRANS_ID'))
|
292
|
+
response_id = response['TRANS_ID'].to_s()
|
293
|
+
elsif (response.has_key?('rebill_id'))
|
294
|
+
response_id = response['rebill_id'][0]
|
295
|
+
else
|
296
|
+
response_id = response[TRANSACTION_ID]
|
297
|
+
end
|
298
|
+
response.has_key?('AVS') ? avs = response['AVS'] : avs = ''
|
299
|
+
response[AVS_RESULT_CODE] != '' ? avs = response[AVS_RESULT_CODE] : avs = ''
|
300
|
+
response.has_key?('CVV2') ? cvv2 = response['CVV2'] : cvv2 = ''
|
301
|
+
response[CARD_CODE_RESPONSE_CODE] != '' ? cvv2 = response[CARD_CODE_RESPONSE_CODE] : cvv2 = ''
|
302
|
+
Response.new(success?(response), message, response,
|
303
|
+
:test => test_mode,
|
304
|
+
:authorization => response_id,
|
305
|
+
:fraud_review => fraud_review?(response),
|
306
|
+
:avs_result => { :code => avs },
|
307
|
+
:cvv_result => cvv2
|
308
|
+
)
|
309
|
+
end
|
310
|
+
|
311
|
+
def success?(response)
|
312
|
+
if (response['STATUS'] == '1' || message_from(response) =~ /approved/ || response.has_key?('rebill_id') || response[RESPONSE_REASON_TEXT] =~ /approved/)
|
313
|
+
return true
|
314
|
+
else
|
315
|
+
return false
|
316
|
+
end
|
317
|
+
end
|
318
|
+
|
319
|
+
def fraud_review?(response)
|
320
|
+
response['STATUS'] == 'E' || response['STATUS'] == '0' || response[RESPONSE_REASON_TEXT] =~ /being reviewed/
|
321
|
+
end
|
322
|
+
|
323
|
+
def get_rebill_id(response)
|
324
|
+
return response['REBID'] if response_has.key?('REBID')
|
325
|
+
end
|
326
|
+
|
327
|
+
def parse(body)
|
328
|
+
fields = CGI::parse(body)
|
329
|
+
if fields.has_key?('MESSAGE') or fields.has_key?('rebill_id')
|
330
|
+
if fields.has_key?('MESSAGE')
|
331
|
+
fields['MESSAGE'][0] == "Missing ACCOUNT_ID" ? message = "The merchant login ID or password is invalid" : message = fields['MESSAGE']
|
332
|
+
fields['MESSAGE'][0] =~ /Approved/ ? message = "This transaction has been approved" : message = fields['MESSAGE'] if message == fields['MESSAGE']
|
333
|
+
fields['MESSAGE'][0] =~ /Expired/ ? message = "The credit card has expired" : message = fields['MESSAGE'] if message == fields['MESSAGE']
|
334
|
+
fields.delete('MESSAGE')
|
335
|
+
end
|
336
|
+
fields.has_key?('STATUS') ? begin status = fields['STATUS']; fields.delete('STATUS') end : status = ''
|
337
|
+
fields.has_key?('AVS') ? begin avs = fields['AVS']; fields.delete('AVS') end : avs = ''
|
338
|
+
fields.has_key?('CVV2') ? begin cvv2 = fields['CVV2']; fields.delete('CVV2') end : cvv2 = ''
|
339
|
+
fields.has_key?('MASTER_ID') ? begin trans_id = fields['MASTER_ID']; fields.delete('MASTER_ID') end : trans_id = ''
|
340
|
+
fields[:avs_result_code] = avs
|
341
|
+
fields[:card_code] = cvv2
|
342
|
+
fields[:response_code] = status
|
343
|
+
fields[:response_reason_code] = ''
|
344
|
+
fields[:response_reason_text] = message
|
345
|
+
fields[:transaction_id] = trans_id
|
346
|
+
return fields
|
347
|
+
end
|
348
|
+
# parse response if using other old API
|
349
|
+
hash = Hash.new
|
350
|
+
fields = fields.first[0].split(",")
|
351
|
+
fields.each_index do |x|
|
352
|
+
hash[x] = fields[x].tr('$','')
|
353
|
+
end
|
354
|
+
hash
|
355
|
+
end
|
356
|
+
|
357
|
+
def add_invoice(post, options)
|
358
|
+
post[:ORDER_ID] = options[:order_id] if options.has_key? :order_id
|
359
|
+
post[:INVOICE_ID] = options[:invoice] if options.has_key? :invoice
|
360
|
+
post[:invoice_num] = options[:order_id] if options.has_key? :order_id
|
361
|
+
post[:MEMO] = options[:description] if options.has_key? :description
|
362
|
+
post[:description] = options[:description] if options.has_key? :description
|
363
|
+
end
|
364
|
+
|
365
|
+
def add_creditcard(post, creditcard)
|
366
|
+
post[:PAYMENT_TYPE] = 'CREDIT'
|
367
|
+
post[:PAYMENT_ACCOUNT] = creditcard.number
|
368
|
+
post[:CARD_CVV2] = creditcard.verification_value if
|
369
|
+
creditcard.verification_value?
|
370
|
+
post[:CARD_EXPIRE] = expdate(creditcard)
|
371
|
+
post[:NAME1] = creditcard.first_name
|
372
|
+
post[:NAME2] = creditcard.last_name
|
373
|
+
end
|
374
|
+
|
375
|
+
def add_check(post, check)
|
376
|
+
post[:PAYMENT_TYPE] = 'ACH'
|
377
|
+
post[:PAYMENT_ACCOUNT] = check.account_type + ":" + check.routing_number + ":" + check.account_number
|
378
|
+
post[:NAME1] = check.first_name
|
379
|
+
post[:NAME2] = check.last_name
|
380
|
+
end
|
381
|
+
|
382
|
+
def add_customer_data(post, options)
|
383
|
+
post[:EMAIL] = options[:email] if options.has_key? :email
|
384
|
+
post[:CUSTOM_ID] = options[:customer] if options.has_key? :customer
|
385
|
+
end
|
386
|
+
|
387
|
+
def add_duplicate_window(post)
|
388
|
+
unless duplicate_window.nil?
|
389
|
+
post[:duplicate_window] = duplicate_window
|
390
|
+
post[:DUPLICATE_OVERRIDE] = duplicate_window
|
391
|
+
end
|
392
|
+
end
|
393
|
+
|
394
|
+
def add_address(post, options)
|
395
|
+
if address = options[:billing_address] || options[:address]
|
396
|
+
post[:NAME1] = address[:first_name]
|
397
|
+
post[:NAME2] = address[:last_name]
|
398
|
+
post[:ADDR1] = address[:address1]
|
399
|
+
post[:ADDR2] = address[:address2]
|
400
|
+
post[:COMPANY_NAME] = address[:company]
|
401
|
+
post[:PHONE] = address[:phone]
|
402
|
+
post[:CITY] = address[:city]
|
403
|
+
post[:STATE] = address[:state].blank? ? 'n/a' : address[:state]
|
404
|
+
post[:ZIP] = address[:zip]
|
405
|
+
post[:COUNTRY] = address[:country]
|
406
|
+
end
|
407
|
+
if address = options[:shipping_address]
|
408
|
+
post[:NAME1] = address[:first_name]
|
409
|
+
post[:NAME2] = address[:last_name]
|
410
|
+
post[:ADDR1] = address[:address1]
|
411
|
+
post[:ADDR1] = address[:address1]
|
412
|
+
post[:COMPANY_NAME] = address[:company]
|
413
|
+
post[:PHONE] = address[:phone]
|
414
|
+
post[:ZIP] = address[:zip]
|
415
|
+
post[:CITY] = address[:city]
|
416
|
+
post[:COUNTRY] = address[:country]
|
417
|
+
post[:STATE] = address[:state].blank? ? 'n/a' : address[:state]
|
418
|
+
end
|
419
|
+
end
|
420
|
+
|
421
|
+
def post_data(action, parameters = {})
|
422
|
+
post = {}
|
423
|
+
post[:version] = '3.0'
|
424
|
+
post[:login] = ''
|
425
|
+
post[:tran_key] = ''
|
426
|
+
post[:relay_response] = "FALSE"
|
427
|
+
post[:type] = action
|
428
|
+
post[:delim_data] = "TRUE"
|
429
|
+
post[:delim_char] = ","
|
430
|
+
post[:encap_char] = "$"
|
431
|
+
post[:card_num] = '4111111111111111'
|
432
|
+
post[:exp_date] = '1212'
|
433
|
+
post[:solution_ID] = application_id if application_id.present? && application_id != "ActiveMerchant"
|
434
|
+
request = post.merge(parameters).collect { |key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join("&")
|
435
|
+
request
|
436
|
+
end
|
437
|
+
|
438
|
+
def message_from(results)
|
439
|
+
if results[:response_code] == 2
|
440
|
+
return CVVResult.messages[ results[:card_code] ] if CARD_CODE_ERRORS.include?(results[:card_code])
|
441
|
+
if AVS_REASON_CODES.include?(results[:response_reason_code]) && AVS_ERRORS.include?(results[:avs_result_code])
|
442
|
+
return AVSResult.messages[ results[:avs_result_code] ]
|
443
|
+
end
|
444
|
+
return (results[:response_reason_text] ? results[:response_reason_text].chomp('.') : '')
|
445
|
+
end
|
446
|
+
if results.has_key?(:response_reason_text)
|
447
|
+
return results[:response_reason_text].to_s()
|
448
|
+
end
|
449
|
+
if !results.has_key?('STATUS')
|
450
|
+
return results[RESPONSE_REASON_TEXT] ? results[RESPONSE_REASON_TEXT].chomp('.') : ''
|
451
|
+
end
|
452
|
+
end
|
453
|
+
|
454
|
+
def expdate(creditcard)
|
455
|
+
year = sprintf("%.4i", creditcard.year)
|
456
|
+
month = sprintf("%.2i", creditcard.month)
|
457
|
+
|
458
|
+
"#{month}#{year[-2..-1]}"
|
459
|
+
end
|
460
|
+
|
461
|
+
def calc_tps(amount, post)
|
462
|
+
post[:NAME1] = '' if post[:NAME1].nil?
|
463
|
+
digest = Digest::MD5.hexdigest(@options[:password] +
|
464
|
+
@options[:login] + post[:TRANS_TYPE] +
|
465
|
+
amount.to_s() + post[:MASTER_ID].to_s() +
|
466
|
+
post[:NAME1].to_s() + post[:PAYMENT_ACCOUNT].to_s())
|
467
|
+
return digest
|
468
|
+
end
|
469
|
+
|
470
|
+
|
471
|
+
def calc_rebill_tps(post)
|
472
|
+
digest = Digest::MD5.hexdigest(@options[:password] +
|
473
|
+
@options[:login] + post[:TRANS_TYPE] + post[:REBILL_ID][0].to_s())
|
474
|
+
return digest
|
475
|
+
end
|
476
|
+
|
477
|
+
def handle_response(response)
|
478
|
+
if ignore_http_status then
|
479
|
+
return response.body
|
480
|
+
else
|
481
|
+
case response.code.to_i
|
482
|
+
when 200...300
|
483
|
+
response.body
|
484
|
+
else
|
485
|
+
raise ResponseError.new(response)
|
486
|
+
end
|
487
|
+
end
|
488
|
+
end
|
489
|
+
|
490
|
+
end
|
491
|
+
end
|
492
|
+
end
|