activemerchant 1.52.0 → 1.53.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +56 -0
- data/README.md +1 -1
- data/lib/active_merchant/billing/gateways/authorize_net.rb +4 -1
- data/lib/active_merchant/billing/gateways/banwire.rb +11 -0
- data/lib/active_merchant/billing/gateways/beanstream.rb +12 -1
- data/lib/active_merchant/billing/gateways/blue_pay.rb +519 -506
- data/lib/active_merchant/billing/gateways/borgun.rb +10 -0
- data/lib/active_merchant/billing/gateways/braintree/braintree_common.rb +13 -1
- data/lib/active_merchant/billing/gateways/braintree_blue.rb +2 -2
- data/lib/active_merchant/billing/gateways/braintree_orange.rb +0 -1
- data/lib/active_merchant/billing/gateways/card_stream.rb +14 -19
- data/lib/active_merchant/billing/gateways/cecabank.rb +11 -1
- data/lib/active_merchant/billing/gateways/cenpos.rb +62 -2
- data/lib/active_merchant/billing/gateways/checkout.rb +1 -1
- data/lib/active_merchant/billing/gateways/checkout_v2.rb +3 -3
- data/lib/active_merchant/billing/gateways/conekta.rb +11 -1
- data/lib/active_merchant/billing/gateways/creditcall.rb +208 -0
- data/lib/active_merchant/billing/gateways/epay.rb +12 -0
- data/lib/active_merchant/billing/gateways/eway.rb +11 -0
- data/lib/active_merchant/billing/gateways/eway_rapid.rb +11 -0
- data/lib/active_merchant/billing/gateways/forte.rb +238 -0
- data/lib/active_merchant/billing/gateways/iridium.rb +11 -0
- data/lib/active_merchant/billing/gateways/jetpay.rb +10 -1
- data/lib/active_merchant/billing/gateways/linkpoint.rb +11 -0
- data/lib/active_merchant/billing/gateways/litle.rb +8 -1
- data/lib/active_merchant/billing/gateways/merchant_ware_version_four.rb +1 -1
- data/lib/active_merchant/billing/gateways/micropayment.rb +167 -0
- data/lib/active_merchant/billing/gateways/migs.rb +13 -4
- data/lib/active_merchant/billing/gateways/monei.rb +1 -1
- data/lib/active_merchant/billing/gateways/netbilling.rb +11 -1
- data/lib/active_merchant/billing/gateways/nmi.rb +164 -178
- data/lib/active_merchant/billing/gateways/ogone.rb +50 -15
- data/lib/active_merchant/billing/gateways/openpay.rb +10 -1
- data/lib/active_merchant/billing/gateways/pac_net_raven.rb +5 -5
- data/lib/active_merchant/billing/gateways/payment_express.rb +11 -0
- data/lib/active_merchant/billing/gateways/paymill.rb +11 -0
- data/lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb +1 -1
- data/lib/active_merchant/billing/gateways/paystation.rb +3 -4
- data/lib/active_merchant/billing/gateways/pin.rb +10 -0
- data/lib/active_merchant/billing/gateways/quickpay/quickpay_v10.rb +106 -57
- data/lib/active_merchant/billing/gateways/realex.rb +10 -0
- data/lib/active_merchant/billing/gateways/redsys.rb +20 -0
- data/lib/active_merchant/billing/gateways/s5.rb +1 -0
- data/lib/active_merchant/billing/gateways/sage_pay.rb +11 -0
- data/lib/active_merchant/billing/gateways/secure_net.rb +1 -0
- data/lib/active_merchant/billing/gateways/stripe.rb +10 -4
- data/lib/active_merchant/billing/gateways/tns.rb +15 -4
- data/lib/active_merchant/billing/gateways/trust_commerce.rb +11 -0
- data/lib/active_merchant/billing/gateways/usa_epay_transaction.rb +12 -2
- data/lib/active_merchant/billing/gateways/wirecard.rb +11 -1
- data/lib/active_merchant/billing/gateways/worldpay.rb +11 -0
- data/lib/active_merchant/billing/gateways/worldpay_online_payments.rb +1 -1
- data/lib/active_merchant/version.rb +1 -1
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a66a1463e2d11b64b17b7690b2fe48e97279a6b6
|
4
|
+
data.tar.gz: 99be80349b8f54a9a07761c8b4b983c9353bf955
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ca1cae5f0c4cb904135e2464e36419f95383222408a45bd8e1fb02f91354701191a5c9ae34c95169e809effe08f093583c48b62477065d89860951e7921883f9
|
7
|
+
data.tar.gz: 1b159f4b9bd19e5b80c20c7db233bbe10a54b92811e02c9f6cb4ea885e983b8fbb800c288bf919a20df3793a2e285b892483838ecc190be3214e336dc4d80bfd
|
data/CHANGELOG
CHANGED
@@ -1,5 +1,60 @@
|
|
1
1
|
= ActiveMerchant CHANGELOG
|
2
2
|
|
3
|
+
|
4
|
+
== Version 1.53.0 (September 1, 2015)
|
5
|
+
|
6
|
+
* Redsys: Add a number of currencies [agseco]
|
7
|
+
* Raven: update description, test url, and routing; fix tests [bslobodin]
|
8
|
+
* Raven: do not pass default (incorrect) PaymentType to #void [bslobodin]
|
9
|
+
* Add scrubbing to a number of gateways [anellis]
|
10
|
+
* BluePay: Add scrubbing [anellis]
|
11
|
+
* BraintreeBlue: Allow custom logger [duff]
|
12
|
+
* MerchantWareFour: Truncate invoiceNumber [duff]
|
13
|
+
* S5: Pass recurrence_mode in store [duff]
|
14
|
+
* QuickPay: Support 2-letter country codes in V10 API [girasquid]
|
15
|
+
* Stripe: Support validate:false field on store [anellis]
|
16
|
+
* CheckoutV2: Use correct live_url [duff]
|
17
|
+
* QuickPay: strip # from Order IDs before submission [girasquid]
|
18
|
+
* Litle: Use schema version 9.4 rather than 8.18 [anellis]
|
19
|
+
* Litle: Add decrypted apple_pay [anellis]
|
20
|
+
* QuickPay: fix method signature on #void [girasquid]
|
21
|
+
* Forte: Add gateway [davidsantoso]
|
22
|
+
* Stripe: return refund id for refund authorization [anellis]
|
23
|
+
* Paypal: Update api version [anellis]
|
24
|
+
* TNS: Translate countries to alpha3 codes [anellis]
|
25
|
+
* TNS: Handle non existent country [duff]
|
26
|
+
* TNS: Rescue Errors [anellis]
|
27
|
+
* CenPOS: Support avs_result and cvv_result [tjstankus]
|
28
|
+
* Stripe: Add application fee only on non-EMV transactions [bizla]
|
29
|
+
* Stripe: don't send blank, non-nil values [girasquid]
|
30
|
+
* Ogone: Send different auth type for mastercard [anellis]
|
31
|
+
* Cardstream: Add "type" field support [rwdaigle]
|
32
|
+
* Cardstream: 3dsecure transaction option [rwdaigle]
|
33
|
+
* Paystation: Map order_id to non-unique merchant reference field [anellis]
|
34
|
+
* Cardstream: Check for nil street address [anellis]
|
35
|
+
* Checkout.com and CheckoutV2.com: Update country list [duff]
|
36
|
+
* Cardstream: Handle nil addresses [rwdaigle]
|
37
|
+
* MiGS: Allow passing in currency [alovak]
|
38
|
+
* [POSSIBLE BREAKAGE] NMI: No longer use auth.net emulator [rwdaigle]
|
39
|
+
* SecureNet: Add DEVELOPERID if supplied [wedy]
|
40
|
+
* Braintree: Update country list [duff]
|
41
|
+
* NMI: Don't include dup_seconds if nil [rwdaigle]
|
42
|
+
* QuickPay: Make all operations to v10 platform synchronous [ta]
|
43
|
+
* QuickPay: Handle issue where no operations exists on payment [ta]
|
44
|
+
* NMI: Support merchant_defined_fields [duff]
|
45
|
+
* QuickpayV10: Add verify [anellis]
|
46
|
+
* BraintreeBlue: Use wiredump_device for logging only if present [braintreeps]
|
47
|
+
* QuickpayV10: Add scrubbing [anellis]
|
48
|
+
* QuickPayV10: Change tests to point to proper gateway [anellis]
|
49
|
+
* Monei: Add default options argument [davidgf]
|
50
|
+
* Ogone: Add additional 3d-secure parameters [ntalbott]
|
51
|
+
* Ogone: Refactor signature calculation [ntalbott]
|
52
|
+
* Add Creditcall gateway [davidsantoso]
|
53
|
+
* Redsys: Fix scrubbing for failed transactions [davidsantoso]
|
54
|
+
* Micropayment: Support Micropayment gateway [rwdaigle]
|
55
|
+
* USAePay: Use names from the given billing and shipping address [marquisong]
|
56
|
+
* Stripe: Add application fee on EMV authorize calls [bizla]
|
57
|
+
|
3
58
|
== Version 1.52.0 (July 20, 2015)
|
4
59
|
|
5
60
|
* Authorize.Net: Add device type to authorize.net retail requests [abecevello]
|
@@ -57,6 +112,7 @@
|
|
57
112
|
* Checkout: Support descriptor_name and descriptor_city [duff]
|
58
113
|
* Add supports_network_tokenization? to gateways [jnormore]
|
59
114
|
|
115
|
+
|
60
116
|
== Version 1.50.0 (June 1, 2015)
|
61
117
|
|
62
118
|
* Vanco: Add gateway [duff]
|
data/README.md
CHANGED
@@ -191,7 +191,7 @@ The [ActiveMerchant Wiki](http://github.com/activemerchant/active_merchant/wikis
|
|
191
191
|
* [Quantum Gateway](http://www.quantumgateway.com) - US
|
192
192
|
* [QuickPay](http://quickpay.net/) - DE, DK, ES, FI, FR, FO, GB, IS, NO, SE
|
193
193
|
* [Qvalent](https://www.qvalent.com/) - AU
|
194
|
-
* [Raven
|
194
|
+
* [Raven](http://www.deepcovelabs.com/raven) - AI, AN, AT, AU, BE, BG, BS, BZ, CA, CH, CR, CY, CZ, DE, DK, DM, DO, EE, EL, ES, FI, FR, GB, GG, GI, HK, HR, HU, IE, IL, IM, IN, IT, JE, KN, LI, LT, LU, LV, MH, MT, MY, NL, NO, NZ, PA, PE, PH, PL, PT, RO, RS, SC, SE, SG, SI, SK, UK, US, VG, ZA
|
195
195
|
* [Realex](http://www.realexpayments.com/) - IE, GB, FR, BE, NL, LU, IT
|
196
196
|
* [Redsys](http://www.redsys.es/) - ES
|
197
197
|
* [S5](http://www.s5.dk/) - DK
|
@@ -6,7 +6,7 @@ module ActiveMerchant #:nodoc:
|
|
6
6
|
include Empty
|
7
7
|
|
8
8
|
self.test_url = 'https://apitest.authorize.net/xml/v1/request.api'
|
9
|
-
self.live_url = 'https://
|
9
|
+
self.live_url = 'https://api2.authorize.net/xml/v1/request.api'
|
10
10
|
|
11
11
|
self.supported_countries = %w(AD AT AU BE BG CA CH CY CZ DE DK ES FI FR GB GB GI GR HU IE IT LI LU MC MT NL NO PL PT RO SE SI SK SM TR US VA)
|
12
12
|
self.default_currency = 'USD'
|
@@ -180,11 +180,14 @@ module ActiveMerchant #:nodoc:
|
|
180
180
|
|
181
181
|
def scrub(transcript)
|
182
182
|
transcript.
|
183
|
+
gsub(%r((Authorization: Basic )\w+), '\1[FILTERED]').
|
183
184
|
gsub(%r((<transactionKey>).+(</transactionKey>)), '\1[FILTERED]\2').
|
184
185
|
gsub(%r((<cardNumber>).+(</cardNumber>)), '\1[FILTERED]\2').
|
185
186
|
gsub(%r((<cardCode>).+(</cardCode>)), '\1[FILTERED]\2').
|
186
187
|
gsub(%r((<track1>).+(</track1>)), '\1[FILTERED]\2').
|
187
188
|
gsub(%r((<track2>).+(</track2>)), '\1[FILTERED]\2').
|
189
|
+
gsub(/(<routingNumber>).+(<\/routingNumber>)/, '\1[FILTERED]\2').
|
190
|
+
gsub(/(<accountNumber>).+(<\/accountNumber>)/, '\1[FILTERED]\2').
|
188
191
|
gsub(%r((<cryptogram>).+(</cryptogram>)), '\1[FILTERED]\2')
|
189
192
|
end
|
190
193
|
|
@@ -26,6 +26,17 @@ module ActiveMerchant #:nodoc:
|
|
26
26
|
commit(money, post)
|
27
27
|
end
|
28
28
|
|
29
|
+
def supports_scrubbing?
|
30
|
+
true
|
31
|
+
end
|
32
|
+
|
33
|
+
def scrub(transcript)
|
34
|
+
transcript.
|
35
|
+
gsub(%r((Authorization: Basic )\w+), '\1[FILTERED]').
|
36
|
+
gsub(%r((&?card_num=)[^&]*)i, '\1[FILTERED]').
|
37
|
+
gsub(%r((&?card_ccv2=)[^&]*)i, '\1[FILTERED]')
|
38
|
+
end
|
39
|
+
|
29
40
|
private
|
30
41
|
|
31
42
|
def add_response_type(post)
|
@@ -182,6 +182,18 @@ module ActiveMerchant #:nodoc:
|
|
182
182
|
commit(post, true)
|
183
183
|
end
|
184
184
|
|
185
|
+
def supports_scrubbing?
|
186
|
+
true
|
187
|
+
end
|
188
|
+
|
189
|
+
def scrub(transcript)
|
190
|
+
transcript.
|
191
|
+
gsub(%r((Authorization: Basic )\w+), '\1[FILTERED]').
|
192
|
+
gsub(/(&?password=)[^&\s]*(&?)/, '\1[FILTERED]\2').
|
193
|
+
gsub(/(&?trnCardCvd=)\d*(&?)/, '\1[FILTERED]\2').
|
194
|
+
gsub(/(&?trnCardNumber=)\d*(&?)/, '\1[FILTERED]\2')
|
195
|
+
end
|
196
|
+
|
185
197
|
private
|
186
198
|
def build_response(*args)
|
187
199
|
Response.new(*args)
|
@@ -189,4 +201,3 @@ module ActiveMerchant #:nodoc:
|
|
189
201
|
end
|
190
202
|
end
|
191
203
|
end
|
192
|
-
|
@@ -1,506 +1,519 @@
|
|
1
|
-
require 'digest/md5'
|
2
|
-
|
3
|
-
module ActiveMerchant #:nodoc:
|
4
|
-
module Billing #:nodoc:
|
5
|
-
class BluePayGateway < Gateway
|
6
|
-
class_attribute :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
|
-
CARD_CODE_ERRORS = %w( N S )
|
14
|
-
AVS_ERRORS = %w( A E N R W Z )
|
15
|
-
AVS_REASON_CODES = %w(27 45)
|
16
|
-
|
17
|
-
FIELD_MAP = {
|
18
|
-
'TRANS_ID' => :transaction_id,
|
19
|
-
'STATUS' => :response_code,
|
20
|
-
'AVS' => :avs_result_code,
|
21
|
-
'CVV2'=> :card_code,
|
22
|
-
'AUTH_CODE' => :authorization,
|
23
|
-
'MESSAGE' => :message,
|
24
|
-
'REBID' => :rebid,
|
25
|
-
'TRANS_TYPE' => :trans_type,
|
26
|
-
'PAYMENT_ACCOUNT_MASK' => :acct_mask,
|
27
|
-
'CARD_TYPE' => :card_type,
|
28
|
-
}
|
29
|
-
|
30
|
-
REBILL_FIELD_MAP = {
|
31
|
-
'REBILL_ID' => :rebill_id,
|
32
|
-
'ACCOUNT_ID'=> :account_id,
|
33
|
-
'USER_ID' => :user_id,
|
34
|
-
'TEMPLATE_ID' => :template_id,
|
35
|
-
'STATUS' => :status,
|
36
|
-
'CREATION_DATE' => :creation_date,
|
37
|
-
'NEXT_DATE' => :next_date,
|
38
|
-
'LAST_DATE' => :last_date,
|
39
|
-
'SCHED_EXPR' => :schedule,
|
40
|
-
'CYCLES_REMAIN' => :cycles_remain,
|
41
|
-
'REB_AMOUNT' => :rebill_amount,
|
42
|
-
'NEXT_AMOUNT' => :next_amount,
|
43
|
-
'USUAL_DATE' => :undoc_usual_date, # Not found in the bp20rebadmin API doc.
|
44
|
-
}
|
45
|
-
|
46
|
-
self.supported_countries = ['US']
|
47
|
-
self.supported_cardtypes = [:visa, :master, :american_express, :discover, :diners_club, :jcb]
|
48
|
-
self.homepage_url = 'http://www.bluepay.com/'
|
49
|
-
self.display_name = 'BluePay'
|
50
|
-
self.money_format = :dollars
|
51
|
-
|
52
|
-
# Creates a new BluepayGateway
|
53
|
-
#
|
54
|
-
# The gateway requires that a valid Account ID and Secret Key be passed
|
55
|
-
# in the +options+ hash.
|
56
|
-
#
|
57
|
-
# ==== Options
|
58
|
-
#
|
59
|
-
# * <tt>:account_id</tt> -- The BluePay gateway Account ID (REQUIRED)
|
60
|
-
# * <tt>:secret_key</tt> -- The BluePay gateway Secret Key (REQUIRED)
|
61
|
-
# * <tt>:test</tt> -- set to true for TEST mode or false for LIVE mode
|
62
|
-
def initialize(options = {})
|
63
|
-
requires!(options, :login, :password)
|
64
|
-
super
|
65
|
-
end
|
66
|
-
|
67
|
-
# Performs an authorization, which reserves the funds on the customer's credit card. This does not actually take funds from the customer
|
68
|
-
# This is referred to an AUTH transaction in BluePay
|
69
|
-
#
|
70
|
-
# ==== Parameters
|
71
|
-
#
|
72
|
-
# * <tt>money</tt> -- The amount to be authorized as an Integer value in cents.
|
73
|
-
# * <tt>payment_object</tt> -- This can either be one of three things:
|
74
|
-
# A CreditCard object,
|
75
|
-
# A Check object,
|
76
|
-
# 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.
|
77
|
-
# * <tt>options</tt> -- A hash of optional parameters.
|
78
|
-
def authorize(money, payment_object, options = {})
|
79
|
-
post = {}
|
80
|
-
add_payment_method(post, payment_object)
|
81
|
-
add_invoice(post, options)
|
82
|
-
add_address(post, options)
|
83
|
-
add_customer_data(post, options)
|
84
|
-
add_rebill(post, options) if options[:rebill]
|
85
|
-
add_duplicate_override(post, options)
|
86
|
-
post[:TRANS_TYPE] = 'AUTH'
|
87
|
-
commit('AUTH_ONLY', money, post)
|
88
|
-
end
|
89
|
-
|
90
|
-
# Perform a purchase, which is essentially an authorization and capture in a single operation.
|
91
|
-
# This is referred to a SALE transaction in BluePay
|
92
|
-
#
|
93
|
-
# ==== Parameters
|
94
|
-
#
|
95
|
-
# * <tt>money</tt> -- The amount to be purchased as an Integer value in cents.
|
96
|
-
# * <tt>payment_object</tt> -- This can either be one of three things:
|
97
|
-
# A CreditCard object,
|
98
|
-
# A Check object,
|
99
|
-
# 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.
|
100
|
-
# * <tt>options</tt> -- A hash of optional parameters.,
|
101
|
-
def purchase(money, payment_object, options = {})
|
102
|
-
post = {}
|
103
|
-
add_payment_method(post, payment_object)
|
104
|
-
add_invoice(post, options)
|
105
|
-
add_address(post, options)
|
106
|
-
add_customer_data(post, options)
|
107
|
-
add_rebill(post, options) if options[:rebill]
|
108
|
-
add_duplicate_override(post, options)
|
109
|
-
post[:TRANS_TYPE] = 'SALE'
|
110
|
-
commit('AUTH_CAPTURE', money, post)
|
111
|
-
end
|
112
|
-
|
113
|
-
# Captures the funds from an authorize transaction.
|
114
|
-
# This is referred to a CAPTURE transaction in BluePay
|
115
|
-
#
|
116
|
-
# ==== Parameters
|
117
|
-
#
|
118
|
-
# * <tt>money</tt> -- The amount to be captured as an Integer value in cents.
|
119
|
-
# * <tt>identification</tt> -- The Master ID, or token, returned from the previous authorize transaction.
|
120
|
-
def capture(money, identification, options = {})
|
121
|
-
post = {}
|
122
|
-
add_address(post, options)
|
123
|
-
add_customer_data(post, options)
|
124
|
-
post[:MASTER_ID] = identification
|
125
|
-
post[:TRANS_TYPE] = 'CAPTURE'
|
126
|
-
commit('PRIOR_AUTH_CAPTURE', money, post)
|
127
|
-
end
|
128
|
-
|
129
|
-
# Void a previous transaction
|
130
|
-
# This is referred to a VOID transaction in BluePay
|
131
|
-
#
|
132
|
-
# ==== Parameters
|
133
|
-
#
|
134
|
-
# * <tt>identification</tt> - The Master ID, or token, returned from a previous authorize transaction.
|
135
|
-
def void(identification, options = {})
|
136
|
-
post = {}
|
137
|
-
post[:MASTER_ID] = identification
|
138
|
-
post[:TRANS_TYPE] = 'VOID'
|
139
|
-
commit('VOID', nil, post)
|
140
|
-
end
|
141
|
-
|
142
|
-
# Performs a credit.
|
143
|
-
#
|
144
|
-
# This transaction indicates that money should flow from the merchant to the customer.
|
145
|
-
#
|
146
|
-
# ==== Parameters
|
147
|
-
#
|
148
|
-
# * <tt>money</tt> -- The amount to be credited to the customer as an Integer value in cents.
|
149
|
-
# * <tt>payment_object</tt> -- This can either be one of three things:
|
150
|
-
# A CreditCard object,
|
151
|
-
# A Check object,
|
152
|
-
# 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.
|
153
|
-
# 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.
|
154
|
-
# 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.
|
155
|
-
# * <tt>options</tt> -- A hash of parameters.
|
156
|
-
def refund(money, identification, options = {})
|
157
|
-
if(identification && !identification.kind_of?(String))
|
158
|
-
ActiveMerchant.deprecated "refund should only be used to refund a referenced transaction"
|
159
|
-
return credit(money, identification, options)
|
160
|
-
end
|
161
|
-
|
162
|
-
post = {}
|
163
|
-
post[:PAYMENT_ACCOUNT] = ''
|
164
|
-
post[:MASTER_ID] = identification
|
165
|
-
post[:TRANS_TYPE] = 'REFUND'
|
166
|
-
post[:NAME1] = (options[:first_name] ? options[:first_name] : "")
|
167
|
-
post[:NAME2] = options[:last_name] if options[:last_name]
|
168
|
-
post[:ZIP] = options[:zip] if options[:zip]
|
169
|
-
add_invoice(post, options)
|
170
|
-
add_address(post, options)
|
171
|
-
add_customer_data(post, options)
|
172
|
-
commit('CREDIT', money, post)
|
173
|
-
end
|
174
|
-
|
175
|
-
def credit(money, payment_object, options = {})
|
176
|
-
if(payment_object && payment_object.kind_of?(String))
|
177
|
-
ActiveMerchant.deprecated "credit should only be used to credit a payment method"
|
178
|
-
return refund(money, payment_object, options)
|
179
|
-
end
|
180
|
-
|
181
|
-
post = {}
|
182
|
-
post[:PAYMENT_ACCOUNT] = ''
|
183
|
-
add_payment_method(post, payment_object)
|
184
|
-
post[:TRANS_TYPE] = 'CREDIT'
|
185
|
-
|
186
|
-
post[:NAME1] = (options[:first_name] ? options[:first_name] : "")
|
187
|
-
post[:NAME2] = options[:last_name] if options[:last_name]
|
188
|
-
post[:ZIP] = options[:zip] if options[:zip]
|
189
|
-
add_invoice(post, options)
|
190
|
-
add_address(post, options)
|
191
|
-
add_customer_data(post, options)
|
192
|
-
commit('CREDIT', money, post)
|
193
|
-
end
|
194
|
-
|
195
|
-
# Create a new recurring payment.
|
196
|
-
#
|
197
|
-
# ==== Parameters
|
198
|
-
#
|
199
|
-
# * <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.
|
200
|
-
# * <tt>payment_object</tt> -- This can either be one of three things:
|
201
|
-
# A CreditCard object,
|
202
|
-
# A Check object,
|
203
|
-
# 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.
|
204
|
-
# * <tt>options</tt> -- A hash of optional parameters.,
|
205
|
-
|
206
|
-
# ==== Options
|
207
|
-
#
|
208
|
-
# * <tt>:rebill_start_date</tt> is a string that tells the gateway when to start the rebill. (REQUIRED)
|
209
|
-
# Has two valid formats:
|
210
|
-
# "YYYY-MM-DD HH:MM:SS" Hours, minutes, and seconds are optional.
|
211
|
-
# "XX UNITS" Relative date as explained below. Marked from the time of the
|
212
|
-
# transaction (i.e.: 10 DAYS, 1 MONTH, 1 YEAR)
|
213
|
-
# * <tt>:rebill_expression</tt> is the period of time in-between rebillings. (REQUIRED)
|
214
|
-
# It uses the same "XX UNITS" format as rebill_start_date, explained above.
|
215
|
-
# Optional parameters include:
|
216
|
-
# * <tt>rebill_cycles</tt>: Number of times to rebill. Don't send or set to nil for infinite rebillings (or
|
217
|
-
# until canceled).
|
218
|
-
# * <tt>rebill_amount</tt>: Amount to rebill. Defaults to amount of transaction for rebillings.
|
219
|
-
#
|
220
|
-
# 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:
|
221
|
-
# :rebill_start_date => '60 DAYS',
|
222
|
-
# :rebill_expression => '3 MONTHS',
|
223
|
-
# :rebill_cycles => '5',
|
224
|
-
# :rebill_amount => '39.95'
|
225
|
-
# A money object of 1995 cents would be passed into the 'money' parameter.
|
226
|
-
def recurring(money, payment_object, options = {})
|
227
|
-
ActiveMerchant.deprecated RECURRING_DEPRECATION_MESSAGE
|
228
|
-
|
229
|
-
requires!(options, :rebill_start_date, :rebill_expression)
|
230
|
-
options[:rebill] = true
|
231
|
-
if money
|
232
|
-
purchase(money, payment_object, options)
|
233
|
-
else
|
234
|
-
authorize(money, payment_object, options)
|
235
|
-
end
|
236
|
-
end
|
237
|
-
|
238
|
-
# View a recurring payment
|
239
|
-
#
|
240
|
-
# This will pull data associated with a current recurring billing
|
241
|
-
#
|
242
|
-
# ==== Parameters
|
243
|
-
#
|
244
|
-
# * <tt>rebill_id</tt> -- A string containing the rebill_id of the recurring billing that is already active (REQUIRED)
|
245
|
-
def status_recurring(rebill_id)
|
246
|
-
ActiveMerchant.deprecated RECURRING_DEPRECATION_MESSAGE
|
247
|
-
|
248
|
-
post = {}
|
249
|
-
requires!(rebill_id)
|
250
|
-
post[:REBILL_ID] = rebill_id
|
251
|
-
post[:TRANS_TYPE] = 'GET'
|
252
|
-
commit('rebill', 'nil', post)
|
253
|
-
end
|
254
|
-
|
255
|
-
# Update a recurring payment's details.
|
256
|
-
#
|
257
|
-
# This transaction updates an existing recurring billing
|
258
|
-
#
|
259
|
-
# ==== Options
|
260
|
-
#
|
261
|
-
# * <tt>:rebill_id</tt> -- The 12 digit rebill ID used to update a particular rebilling cycle. (REQUIRED)
|
262
|
-
# * <tt>:rebill_amount</tt> -- A string containing the new rebilling amount.
|
263
|
-
# * <tt>:rebill_next_date</tt> -- A string containing the new rebilling next date.
|
264
|
-
# * <tt>:rebill_expression</tt> -- A string containing the new rebilling expression.
|
265
|
-
# * <tt>:rebill_cycles</tt> -- A string containing the new rebilling cycles.
|
266
|
-
# * <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.
|
267
|
-
# Take a look above at the recurring_payment method for similar examples on how to use.
|
268
|
-
def update_recurring(options = {})
|
269
|
-
ActiveMerchant.deprecated RECURRING_DEPRECATION_MESSAGE
|
270
|
-
|
271
|
-
post = {}
|
272
|
-
requires!(options, :rebill_id)
|
273
|
-
post[:REBILL_ID] = options[:rebill_id]
|
274
|
-
post[:TRANS_TYPE] = 'SET'
|
275
|
-
post[:REB_AMOUNT] = amount(options[:rebill_amount]) if options[:rebill_amount]
|
276
|
-
post[:NEXT_DATE] = options[:rebill_next_date]
|
277
|
-
post[:REB_EXPR] = options[:rebill_expression]
|
278
|
-
post[:REB_CYCLES] = options[:rebill_cycles]
|
279
|
-
post[:NEXT_AMOUNT] = options[:rebill_next_amount]
|
280
|
-
commit('rebill', 'nil', post)
|
281
|
-
end
|
282
|
-
|
283
|
-
# Cancel a recurring payment.
|
284
|
-
#
|
285
|
-
# This transaction cancels an existing recurring billing.
|
286
|
-
#
|
287
|
-
# ==== Parameters
|
288
|
-
#
|
289
|
-
# * <tt>rebill_id</tt> -- A string containing the rebill_id of the recurring billing that you wish to cancel/stop (REQUIRED)
|
290
|
-
def cancel_recurring(rebill_id)
|
291
|
-
ActiveMerchant.deprecated RECURRING_DEPRECATION_MESSAGE
|
292
|
-
|
293
|
-
post = {}
|
294
|
-
requires!(rebill_id)
|
295
|
-
post[:REBILL_ID] = rebill_id
|
296
|
-
post[:TRANS_TYPE] = 'SET'
|
297
|
-
post[:STATUS] = 'stopped'
|
298
|
-
commit('rebill', 'nil', post)
|
299
|
-
end
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
#
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
post[:
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
post[:
|
414
|
-
post[:
|
415
|
-
post[:
|
416
|
-
post[:
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
post[:
|
434
|
-
post[:
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
end
|
440
|
-
|
441
|
-
def
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
post[:
|
456
|
-
post[:
|
457
|
-
post[:
|
458
|
-
post[:
|
459
|
-
post[:
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
"
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
post[:
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
@options[:
|
491
|
-
|
492
|
-
|
493
|
-
post[:
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
1
|
+
require 'digest/md5'
|
2
|
+
|
3
|
+
module ActiveMerchant #:nodoc:
|
4
|
+
module Billing #:nodoc:
|
5
|
+
class BluePayGateway < Gateway
|
6
|
+
class_attribute :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
|
+
CARD_CODE_ERRORS = %w( N S )
|
14
|
+
AVS_ERRORS = %w( A E N R W Z )
|
15
|
+
AVS_REASON_CODES = %w(27 45)
|
16
|
+
|
17
|
+
FIELD_MAP = {
|
18
|
+
'TRANS_ID' => :transaction_id,
|
19
|
+
'STATUS' => :response_code,
|
20
|
+
'AVS' => :avs_result_code,
|
21
|
+
'CVV2'=> :card_code,
|
22
|
+
'AUTH_CODE' => :authorization,
|
23
|
+
'MESSAGE' => :message,
|
24
|
+
'REBID' => :rebid,
|
25
|
+
'TRANS_TYPE' => :trans_type,
|
26
|
+
'PAYMENT_ACCOUNT_MASK' => :acct_mask,
|
27
|
+
'CARD_TYPE' => :card_type,
|
28
|
+
}
|
29
|
+
|
30
|
+
REBILL_FIELD_MAP = {
|
31
|
+
'REBILL_ID' => :rebill_id,
|
32
|
+
'ACCOUNT_ID'=> :account_id,
|
33
|
+
'USER_ID' => :user_id,
|
34
|
+
'TEMPLATE_ID' => :template_id,
|
35
|
+
'STATUS' => :status,
|
36
|
+
'CREATION_DATE' => :creation_date,
|
37
|
+
'NEXT_DATE' => :next_date,
|
38
|
+
'LAST_DATE' => :last_date,
|
39
|
+
'SCHED_EXPR' => :schedule,
|
40
|
+
'CYCLES_REMAIN' => :cycles_remain,
|
41
|
+
'REB_AMOUNT' => :rebill_amount,
|
42
|
+
'NEXT_AMOUNT' => :next_amount,
|
43
|
+
'USUAL_DATE' => :undoc_usual_date, # Not found in the bp20rebadmin API doc.
|
44
|
+
}
|
45
|
+
|
46
|
+
self.supported_countries = ['US']
|
47
|
+
self.supported_cardtypes = [:visa, :master, :american_express, :discover, :diners_club, :jcb]
|
48
|
+
self.homepage_url = 'http://www.bluepay.com/'
|
49
|
+
self.display_name = 'BluePay'
|
50
|
+
self.money_format = :dollars
|
51
|
+
|
52
|
+
# Creates a new BluepayGateway
|
53
|
+
#
|
54
|
+
# The gateway requires that a valid Account ID and Secret Key be passed
|
55
|
+
# in the +options+ hash.
|
56
|
+
#
|
57
|
+
# ==== Options
|
58
|
+
#
|
59
|
+
# * <tt>:account_id</tt> -- The BluePay gateway Account ID (REQUIRED)
|
60
|
+
# * <tt>:secret_key</tt> -- The BluePay gateway Secret Key (REQUIRED)
|
61
|
+
# * <tt>:test</tt> -- set to true for TEST mode or false for LIVE mode
|
62
|
+
def initialize(options = {})
|
63
|
+
requires!(options, :login, :password)
|
64
|
+
super
|
65
|
+
end
|
66
|
+
|
67
|
+
# Performs an authorization, which reserves the funds on the customer's credit card. This does not actually take funds from the customer
|
68
|
+
# This is referred to an AUTH transaction in BluePay
|
69
|
+
#
|
70
|
+
# ==== Parameters
|
71
|
+
#
|
72
|
+
# * <tt>money</tt> -- The amount to be authorized as an Integer value in cents.
|
73
|
+
# * <tt>payment_object</tt> -- This can either be one of three things:
|
74
|
+
# A CreditCard object,
|
75
|
+
# A Check object,
|
76
|
+
# 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.
|
77
|
+
# * <tt>options</tt> -- A hash of optional parameters.
|
78
|
+
def authorize(money, payment_object, options = {})
|
79
|
+
post = {}
|
80
|
+
add_payment_method(post, payment_object)
|
81
|
+
add_invoice(post, options)
|
82
|
+
add_address(post, options)
|
83
|
+
add_customer_data(post, options)
|
84
|
+
add_rebill(post, options) if options[:rebill]
|
85
|
+
add_duplicate_override(post, options)
|
86
|
+
post[:TRANS_TYPE] = 'AUTH'
|
87
|
+
commit('AUTH_ONLY', money, post)
|
88
|
+
end
|
89
|
+
|
90
|
+
# Perform a purchase, which is essentially an authorization and capture in a single operation.
|
91
|
+
# This is referred to a SALE transaction in BluePay
|
92
|
+
#
|
93
|
+
# ==== Parameters
|
94
|
+
#
|
95
|
+
# * <tt>money</tt> -- The amount to be purchased as an Integer value in cents.
|
96
|
+
# * <tt>payment_object</tt> -- This can either be one of three things:
|
97
|
+
# A CreditCard object,
|
98
|
+
# A Check object,
|
99
|
+
# 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.
|
100
|
+
# * <tt>options</tt> -- A hash of optional parameters.,
|
101
|
+
def purchase(money, payment_object, options = {})
|
102
|
+
post = {}
|
103
|
+
add_payment_method(post, payment_object)
|
104
|
+
add_invoice(post, options)
|
105
|
+
add_address(post, options)
|
106
|
+
add_customer_data(post, options)
|
107
|
+
add_rebill(post, options) if options[:rebill]
|
108
|
+
add_duplicate_override(post, options)
|
109
|
+
post[:TRANS_TYPE] = 'SALE'
|
110
|
+
commit('AUTH_CAPTURE', money, post)
|
111
|
+
end
|
112
|
+
|
113
|
+
# Captures the funds from an authorize transaction.
|
114
|
+
# This is referred to a CAPTURE transaction in BluePay
|
115
|
+
#
|
116
|
+
# ==== Parameters
|
117
|
+
#
|
118
|
+
# * <tt>money</tt> -- The amount to be captured as an Integer value in cents.
|
119
|
+
# * <tt>identification</tt> -- The Master ID, or token, returned from the previous authorize transaction.
|
120
|
+
def capture(money, identification, options = {})
|
121
|
+
post = {}
|
122
|
+
add_address(post, options)
|
123
|
+
add_customer_data(post, options)
|
124
|
+
post[:MASTER_ID] = identification
|
125
|
+
post[:TRANS_TYPE] = 'CAPTURE'
|
126
|
+
commit('PRIOR_AUTH_CAPTURE', money, post)
|
127
|
+
end
|
128
|
+
|
129
|
+
# Void a previous transaction
|
130
|
+
# This is referred to a VOID transaction in BluePay
|
131
|
+
#
|
132
|
+
# ==== Parameters
|
133
|
+
#
|
134
|
+
# * <tt>identification</tt> - The Master ID, or token, returned from a previous authorize transaction.
|
135
|
+
def void(identification, options = {})
|
136
|
+
post = {}
|
137
|
+
post[:MASTER_ID] = identification
|
138
|
+
post[:TRANS_TYPE] = 'VOID'
|
139
|
+
commit('VOID', nil, post)
|
140
|
+
end
|
141
|
+
|
142
|
+
# Performs a credit.
|
143
|
+
#
|
144
|
+
# This transaction indicates that money should flow from the merchant to the customer.
|
145
|
+
#
|
146
|
+
# ==== Parameters
|
147
|
+
#
|
148
|
+
# * <tt>money</tt> -- The amount to be credited to the customer as an Integer value in cents.
|
149
|
+
# * <tt>payment_object</tt> -- This can either be one of three things:
|
150
|
+
# A CreditCard object,
|
151
|
+
# A Check object,
|
152
|
+
# 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.
|
153
|
+
# 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.
|
154
|
+
# 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.
|
155
|
+
# * <tt>options</tt> -- A hash of parameters.
|
156
|
+
def refund(money, identification, options = {})
|
157
|
+
if(identification && !identification.kind_of?(String))
|
158
|
+
ActiveMerchant.deprecated "refund should only be used to refund a referenced transaction"
|
159
|
+
return credit(money, identification, options)
|
160
|
+
end
|
161
|
+
|
162
|
+
post = {}
|
163
|
+
post[:PAYMENT_ACCOUNT] = ''
|
164
|
+
post[:MASTER_ID] = identification
|
165
|
+
post[:TRANS_TYPE] = 'REFUND'
|
166
|
+
post[:NAME1] = (options[:first_name] ? options[:first_name] : "")
|
167
|
+
post[:NAME2] = options[:last_name] if options[:last_name]
|
168
|
+
post[:ZIP] = options[:zip] if options[:zip]
|
169
|
+
add_invoice(post, options)
|
170
|
+
add_address(post, options)
|
171
|
+
add_customer_data(post, options)
|
172
|
+
commit('CREDIT', money, post)
|
173
|
+
end
|
174
|
+
|
175
|
+
def credit(money, payment_object, options = {})
|
176
|
+
if(payment_object && payment_object.kind_of?(String))
|
177
|
+
ActiveMerchant.deprecated "credit should only be used to credit a payment method"
|
178
|
+
return refund(money, payment_object, options)
|
179
|
+
end
|
180
|
+
|
181
|
+
post = {}
|
182
|
+
post[:PAYMENT_ACCOUNT] = ''
|
183
|
+
add_payment_method(post, payment_object)
|
184
|
+
post[:TRANS_TYPE] = 'CREDIT'
|
185
|
+
|
186
|
+
post[:NAME1] = (options[:first_name] ? options[:first_name] : "")
|
187
|
+
post[:NAME2] = options[:last_name] if options[:last_name]
|
188
|
+
post[:ZIP] = options[:zip] if options[:zip]
|
189
|
+
add_invoice(post, options)
|
190
|
+
add_address(post, options)
|
191
|
+
add_customer_data(post, options)
|
192
|
+
commit('CREDIT', money, post)
|
193
|
+
end
|
194
|
+
|
195
|
+
# Create a new recurring payment.
|
196
|
+
#
|
197
|
+
# ==== Parameters
|
198
|
+
#
|
199
|
+
# * <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.
|
200
|
+
# * <tt>payment_object</tt> -- This can either be one of three things:
|
201
|
+
# A CreditCard object,
|
202
|
+
# A Check object,
|
203
|
+
# 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.
|
204
|
+
# * <tt>options</tt> -- A hash of optional parameters.,
|
205
|
+
|
206
|
+
# ==== Options
|
207
|
+
#
|
208
|
+
# * <tt>:rebill_start_date</tt> is a string that tells the gateway when to start the rebill. (REQUIRED)
|
209
|
+
# Has two valid formats:
|
210
|
+
# "YYYY-MM-DD HH:MM:SS" Hours, minutes, and seconds are optional.
|
211
|
+
# "XX UNITS" Relative date as explained below. Marked from the time of the
|
212
|
+
# transaction (i.e.: 10 DAYS, 1 MONTH, 1 YEAR)
|
213
|
+
# * <tt>:rebill_expression</tt> is the period of time in-between rebillings. (REQUIRED)
|
214
|
+
# It uses the same "XX UNITS" format as rebill_start_date, explained above.
|
215
|
+
# Optional parameters include:
|
216
|
+
# * <tt>rebill_cycles</tt>: Number of times to rebill. Don't send or set to nil for infinite rebillings (or
|
217
|
+
# until canceled).
|
218
|
+
# * <tt>rebill_amount</tt>: Amount to rebill. Defaults to amount of transaction for rebillings.
|
219
|
+
#
|
220
|
+
# 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:
|
221
|
+
# :rebill_start_date => '60 DAYS',
|
222
|
+
# :rebill_expression => '3 MONTHS',
|
223
|
+
# :rebill_cycles => '5',
|
224
|
+
# :rebill_amount => '39.95'
|
225
|
+
# A money object of 1995 cents would be passed into the 'money' parameter.
|
226
|
+
def recurring(money, payment_object, options = {})
|
227
|
+
ActiveMerchant.deprecated RECURRING_DEPRECATION_MESSAGE
|
228
|
+
|
229
|
+
requires!(options, :rebill_start_date, :rebill_expression)
|
230
|
+
options[:rebill] = true
|
231
|
+
if money
|
232
|
+
purchase(money, payment_object, options)
|
233
|
+
else
|
234
|
+
authorize(money, payment_object, options)
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
# View a recurring payment
|
239
|
+
#
|
240
|
+
# This will pull data associated with a current recurring billing
|
241
|
+
#
|
242
|
+
# ==== Parameters
|
243
|
+
#
|
244
|
+
# * <tt>rebill_id</tt> -- A string containing the rebill_id of the recurring billing that is already active (REQUIRED)
|
245
|
+
def status_recurring(rebill_id)
|
246
|
+
ActiveMerchant.deprecated RECURRING_DEPRECATION_MESSAGE
|
247
|
+
|
248
|
+
post = {}
|
249
|
+
requires!(rebill_id)
|
250
|
+
post[:REBILL_ID] = rebill_id
|
251
|
+
post[:TRANS_TYPE] = 'GET'
|
252
|
+
commit('rebill', 'nil', post)
|
253
|
+
end
|
254
|
+
|
255
|
+
# Update a recurring payment's details.
|
256
|
+
#
|
257
|
+
# This transaction updates an existing recurring billing
|
258
|
+
#
|
259
|
+
# ==== Options
|
260
|
+
#
|
261
|
+
# * <tt>:rebill_id</tt> -- The 12 digit rebill ID used to update a particular rebilling cycle. (REQUIRED)
|
262
|
+
# * <tt>:rebill_amount</tt> -- A string containing the new rebilling amount.
|
263
|
+
# * <tt>:rebill_next_date</tt> -- A string containing the new rebilling next date.
|
264
|
+
# * <tt>:rebill_expression</tt> -- A string containing the new rebilling expression.
|
265
|
+
# * <tt>:rebill_cycles</tt> -- A string containing the new rebilling cycles.
|
266
|
+
# * <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.
|
267
|
+
# Take a look above at the recurring_payment method for similar examples on how to use.
|
268
|
+
def update_recurring(options = {})
|
269
|
+
ActiveMerchant.deprecated RECURRING_DEPRECATION_MESSAGE
|
270
|
+
|
271
|
+
post = {}
|
272
|
+
requires!(options, :rebill_id)
|
273
|
+
post[:REBILL_ID] = options[:rebill_id]
|
274
|
+
post[:TRANS_TYPE] = 'SET'
|
275
|
+
post[:REB_AMOUNT] = amount(options[:rebill_amount]) if options[:rebill_amount]
|
276
|
+
post[:NEXT_DATE] = options[:rebill_next_date]
|
277
|
+
post[:REB_EXPR] = options[:rebill_expression]
|
278
|
+
post[:REB_CYCLES] = options[:rebill_cycles]
|
279
|
+
post[:NEXT_AMOUNT] = options[:rebill_next_amount]
|
280
|
+
commit('rebill', 'nil', post)
|
281
|
+
end
|
282
|
+
|
283
|
+
# Cancel a recurring payment.
|
284
|
+
#
|
285
|
+
# This transaction cancels an existing recurring billing.
|
286
|
+
#
|
287
|
+
# ==== Parameters
|
288
|
+
#
|
289
|
+
# * <tt>rebill_id</tt> -- A string containing the rebill_id of the recurring billing that you wish to cancel/stop (REQUIRED)
|
290
|
+
def cancel_recurring(rebill_id)
|
291
|
+
ActiveMerchant.deprecated RECURRING_DEPRECATION_MESSAGE
|
292
|
+
|
293
|
+
post = {}
|
294
|
+
requires!(rebill_id)
|
295
|
+
post[:REBILL_ID] = rebill_id
|
296
|
+
post[:TRANS_TYPE] = 'SET'
|
297
|
+
post[:STATUS] = 'stopped'
|
298
|
+
commit('rebill', 'nil', post)
|
299
|
+
end
|
300
|
+
|
301
|
+
def supports_scrubbing
|
302
|
+
true
|
303
|
+
end
|
304
|
+
|
305
|
+
def scrub(transcript)
|
306
|
+
transcript.
|
307
|
+
gsub(%r((Authorization: Basic )\w+), '\1[FILTERED]').
|
308
|
+
gsub(%r((&?card_num=)[^&]*)i, '\1[FILTERED]').
|
309
|
+
gsub(%r((&?CARD_CVV2=)[^&]*)i, '\1[FILTERED]').
|
310
|
+
gsub(%r((&?PAYMENT_ACCOUNT=)[^&]*)i, '\1[FILTERED]').
|
311
|
+
gsub(%r((&?TAMPER_PROOF_SEAL=)[^&"]*)i, '\1[FILTERED]')
|
312
|
+
end
|
313
|
+
|
314
|
+
private
|
315
|
+
|
316
|
+
def commit(action, money, fields)
|
317
|
+
fields[:AMOUNT] = amount(money) unless(fields[:TRANS_TYPE] == 'VOID' || action == 'rebill')
|
318
|
+
fields[:MODE] = (test? ? 'TEST' : 'LIVE')
|
319
|
+
fields[:ACCOUNT_ID] = @options[:login]
|
320
|
+
|
321
|
+
if action == 'rebill'
|
322
|
+
url = rebilling_url
|
323
|
+
fields[:TAMPER_PROOF_SEAL] = calc_rebill_tps(fields)
|
324
|
+
else
|
325
|
+
url = live_url
|
326
|
+
fields[:TAMPER_PROOF_SEAL] = calc_tps(amount(money), fields)
|
327
|
+
end
|
328
|
+
parse(ssl_post(url, post_data(action, fields)))
|
329
|
+
end
|
330
|
+
|
331
|
+
def parse_recurring(response_fields, opts={}) # expected status?
|
332
|
+
parsed = {}
|
333
|
+
response_fields.each do |k,v|
|
334
|
+
mapped_key = REBILL_FIELD_MAP.include?(k) ? REBILL_FIELD_MAP[k] : k
|
335
|
+
parsed[mapped_key] = v
|
336
|
+
end
|
337
|
+
|
338
|
+
success = parsed[:status] != 'error'
|
339
|
+
message = parsed[:status]
|
340
|
+
|
341
|
+
Response.new(success, message, parsed,
|
342
|
+
:test => test?,
|
343
|
+
:authorization => parsed[:rebill_id])
|
344
|
+
end
|
345
|
+
|
346
|
+
def parse(body)
|
347
|
+
# The bp20api has max one value per form field.
|
348
|
+
response_fields = Hash[CGI::parse(body).map{|k,v| [k.upcase,v.first]}]
|
349
|
+
|
350
|
+
if response_fields.include? "REBILL_ID"
|
351
|
+
return parse_recurring(response_fields)
|
352
|
+
end
|
353
|
+
|
354
|
+
parsed = {}
|
355
|
+
response_fields.each do |k,v|
|
356
|
+
mapped_key = FIELD_MAP.include?(k) ? FIELD_MAP[k] : k
|
357
|
+
parsed[mapped_key] = v
|
358
|
+
end
|
359
|
+
|
360
|
+
# normalize message
|
361
|
+
message = message_from(parsed)
|
362
|
+
success = parsed[:response_code] == '1'
|
363
|
+
Response.new(success, message, parsed,
|
364
|
+
:test => test?,
|
365
|
+
:authorization => (parsed[:rebid] && parsed[:rebid] != '' ? parsed[:rebid] : parsed[:transaction_id]),
|
366
|
+
:avs_result => { :code => parsed[:avs_result_code] },
|
367
|
+
:cvv_result => parsed[:card_code]
|
368
|
+
)
|
369
|
+
end
|
370
|
+
|
371
|
+
def message_from(parsed)
|
372
|
+
message = parsed[:message]
|
373
|
+
if(parsed[:response_code].to_i == 2)
|
374
|
+
if CARD_CODE_ERRORS.include?(parsed[:card_code])
|
375
|
+
message = CVVResult.messages[parsed[:card_code]]
|
376
|
+
elsif AVS_ERRORS.include?(parsed[:avs_result_code])
|
377
|
+
message = AVSResult.messages[ parsed[:avs_result_code] ]
|
378
|
+
else
|
379
|
+
message = message.chomp('.')
|
380
|
+
end
|
381
|
+
elsif message == "Missing ACCOUNT_ID"
|
382
|
+
message = "The merchant login ID or password is invalid"
|
383
|
+
elsif message =~ /Approved/
|
384
|
+
message = "This transaction has been approved"
|
385
|
+
elsif message =~ /Expired/
|
386
|
+
message = "The credit card has expired"
|
387
|
+
end
|
388
|
+
message
|
389
|
+
end
|
390
|
+
|
391
|
+
def add_invoice(post, options)
|
392
|
+
post[:ORDER_ID] = options[:order_id]
|
393
|
+
post[:INVOICE_ID] = options[:invoice]
|
394
|
+
post[:invoice_num] = options[:order_id]
|
395
|
+
post[:MEMO] = options[:description]
|
396
|
+
post[:description] = options[:description]
|
397
|
+
end
|
398
|
+
|
399
|
+
def add_payment_method(post, payment_object)
|
400
|
+
post[:MASTER_ID] = ''
|
401
|
+
case payment_object
|
402
|
+
when String
|
403
|
+
post[:MASTER_ID] = payment_object
|
404
|
+
when Check
|
405
|
+
add_check(post, payment_object)
|
406
|
+
else
|
407
|
+
add_creditcard(post, payment_object)
|
408
|
+
end
|
409
|
+
end
|
410
|
+
|
411
|
+
def add_creditcard(post, creditcard)
|
412
|
+
post[:PAYMENT_TYPE] = 'CREDIT'
|
413
|
+
post[:PAYMENT_ACCOUNT] = creditcard.number
|
414
|
+
post[:CARD_CVV2] = creditcard.verification_value
|
415
|
+
post[:CARD_EXPIRE] = expdate(creditcard)
|
416
|
+
post[:NAME1] = creditcard.first_name
|
417
|
+
post[:NAME2] = creditcard.last_name
|
418
|
+
end
|
419
|
+
|
420
|
+
CHECK_ACCOUNT_TYPES = {
|
421
|
+
"checking" => "C",
|
422
|
+
"savings" => "S"
|
423
|
+
}
|
424
|
+
|
425
|
+
def add_check(post, check)
|
426
|
+
post[:PAYMENT_TYPE] = 'ACH'
|
427
|
+
post[:PAYMENT_ACCOUNT] = [CHECK_ACCOUNT_TYPES[check.account_type], check.routing_number, check.account_number].join(":")
|
428
|
+
post[:NAME1] = check.first_name
|
429
|
+
post[:NAME2] = check.last_name
|
430
|
+
end
|
431
|
+
|
432
|
+
def add_customer_data(post, options)
|
433
|
+
post[:EMAIL] = options[:email]
|
434
|
+
post[:CUSTOM_ID] = options[:customer]
|
435
|
+
end
|
436
|
+
|
437
|
+
def add_duplicate_override(post, options)
|
438
|
+
post[:DUPLICATE_OVERRIDE] = options[:duplicate_override]
|
439
|
+
end
|
440
|
+
|
441
|
+
def add_address(post, options)
|
442
|
+
if address = (options[:shipping_address] || options[:billing_address] || options[:address])
|
443
|
+
post[:ADDR1] = address[:address1]
|
444
|
+
post[:ADDR2] = address[:address2]
|
445
|
+
post[:COMPANY_NAME] = address[:company]
|
446
|
+
post[:PHONE] = address[:phone]
|
447
|
+
post[:CITY] = address[:city]
|
448
|
+
post[:STATE] = (address[:state].blank? ? 'n/a' : address[:state])
|
449
|
+
post[:ZIP] = address[:zip]
|
450
|
+
post[:COUNTRY] = address[:country]
|
451
|
+
end
|
452
|
+
end
|
453
|
+
|
454
|
+
def add_rebill(post, options)
|
455
|
+
post[:DO_REBILL] = '1'
|
456
|
+
post[:REB_AMOUNT] = amount(options[:rebill_amount])
|
457
|
+
post[:REB_FIRST_DATE] = options[:rebill_start_date]
|
458
|
+
post[:REB_EXPR] = options[:rebill_expression]
|
459
|
+
post[:REB_CYCLES] = options[:rebill_cycles]
|
460
|
+
end
|
461
|
+
|
462
|
+
def post_data(action, parameters = {})
|
463
|
+
post = {}
|
464
|
+
post[:version] = '1'
|
465
|
+
post[:login] = ''
|
466
|
+
post[:tran_key] = ''
|
467
|
+
post[:relay_response] = "FALSE"
|
468
|
+
post[:type] = action
|
469
|
+
post[:delim_data] = "TRUE"
|
470
|
+
post[:delim_char] = ","
|
471
|
+
post[:encap_char] = "$"
|
472
|
+
post[:card_num] = '4111111111111111'
|
473
|
+
post[:exp_date] = '1212'
|
474
|
+
post[:solution_ID] = application_id if(application_id && application_id != "ActiveMerchant")
|
475
|
+
post.merge(parameters).collect { |key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join("&")
|
476
|
+
end
|
477
|
+
|
478
|
+
def expdate(creditcard)
|
479
|
+
year = format(creditcard.year, :two_digits)
|
480
|
+
month = format(creditcard.month, :two_digits)
|
481
|
+
|
482
|
+
"#{month}#{year}"
|
483
|
+
end
|
484
|
+
|
485
|
+
def calc_tps(amount, post)
|
486
|
+
post[:NAME1] ||= ''
|
487
|
+
Digest::MD5.hexdigest(
|
488
|
+
[
|
489
|
+
@options[:password],
|
490
|
+
@options[:login],
|
491
|
+
post[:TRANS_TYPE],
|
492
|
+
amount,
|
493
|
+
post[:MASTER_ID],
|
494
|
+
post[:NAME1],
|
495
|
+
post[:PAYMENT_ACCOUNT]
|
496
|
+
].join("")
|
497
|
+
)
|
498
|
+
end
|
499
|
+
|
500
|
+
def calc_rebill_tps(post)
|
501
|
+
Digest::MD5.hexdigest(
|
502
|
+
[
|
503
|
+
@options[:password],
|
504
|
+
@options[:login],
|
505
|
+
post[:TRANS_TYPE],
|
506
|
+
post[:REBILL_ID]
|
507
|
+
].join("")
|
508
|
+
)
|
509
|
+
end
|
510
|
+
|
511
|
+
def handle_response(response)
|
512
|
+
if ignore_http_status || (200...300).include?(response.code.to_i)
|
513
|
+
return response.body
|
514
|
+
end
|
515
|
+
raise ResponseError.new(response)
|
516
|
+
end
|
517
|
+
end
|
518
|
+
end
|
519
|
+
end
|