activemerchant 1.20.4 → 1.21.0
Sign up to get free protection for your applications and to get access to all the features.
- data.tar.gz.sig +0 -0
- data/CHANGELOG +29 -0
- data/CONTRIBUTORS +13 -0
- data/lib/active_merchant/billing/credit_card_methods.rb +1 -1
- data/lib/active_merchant/billing/gateway.rb +1 -1
- data/lib/active_merchant/billing/gateways/authorize_net_cim.rb +104 -18
- data/lib/active_merchant/billing/gateways/beanstream.rb +29 -1
- data/lib/active_merchant/billing/gateways/beanstream/beanstream_core.rb +105 -3
- data/lib/active_merchant/billing/gateways/braintree_orange.rb +4 -0
- data/lib/active_merchant/billing/gateways/certo_direct.rb +279 -0
- data/lib/active_merchant/billing/gateways/epay.rb +2 -2
- data/lib/active_merchant/billing/gateways/eway_managed.rb +1 -0
- data/lib/active_merchant/billing/gateways/merchant_e_solutions.rb +1 -0
- data/lib/active_merchant/billing/gateways/nab_transact.rb +244 -0
- data/lib/active_merchant/billing/gateways/payflow.rb +10 -2
- data/lib/active_merchant/billing/gateways/payflow/payflow_common_api.rb +1 -0
- data/lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb +1 -1
- data/lib/active_merchant/billing/gateways/paypal_digital_goods.rb +43 -0
- data/lib/active_merchant/billing/gateways/paypal_express.rb +36 -1
- data/lib/active_merchant/billing/gateways/paypal_express_common.rb +8 -3
- data/lib/active_merchant/billing/gateways/quickpay.rb +1 -0
- data/lib/active_merchant/billing/gateways/samurai.rb +1 -0
- data/lib/active_merchant/billing/gateways/secure_pay_au.rb +136 -49
- data/lib/active_merchant/billing/gateways/secure_pay_tech.rb +1 -1
- data/lib/active_merchant/billing/gateways/stripe.rb +23 -11
- data/lib/active_merchant/billing/gateways/verifi.rb +2 -2
- data/lib/active_merchant/billing/gateways/viaklix.rb +1 -1
- data/lib/active_merchant/billing/integrations/action_view_helper.rb +5 -1
- 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/helper.rb +13 -1
- data/lib/active_merchant/billing/integrations/payflow_link/helper.rb +1 -1
- data/lib/active_merchant/version.rb +1 -1
- metadata +37 -31
- metadata.gz.sig +0 -0
data.tar.gz.sig
CHANGED
Binary file
|
data/CHANGELOG
CHANGED
@@ -1,5 +1,34 @@
|
|
1
1
|
= ActiveMerchant CHANGELOG
|
2
2
|
|
3
|
+
== Version 1.21.0 (March 7, 2012)
|
4
|
+
|
5
|
+
* Stripe: Add support for passing IP [collision]
|
6
|
+
* Merchant e-Solutions: pass expiration date when purchasing with a stored credit card [chrisyoung]
|
7
|
+
* Braintree: Fix passing custom processor ids to old accounts [maxsilver]
|
8
|
+
* Authorize.net CIM: Add validation mode option to create_customer_profile_request [jwood]
|
9
|
+
* eWay Managed: Include transaction number in response params [jamsi]
|
10
|
+
* Fix various hash ordering issues exposed by Ruby 1.8 [ntalbott]
|
11
|
+
* Authorize.Net CIM: Add WEB echeck type [deathbob]
|
12
|
+
* Move Braintree from the gemspec to the Gemfile [ntalbott]
|
13
|
+
* Add CertoDirect gateway [hron]
|
14
|
+
* Authorize.Net CIM: Add option for setting a custom delimiter [bmorton]
|
15
|
+
* Authorize.Net CIM: Add 3.1 response fields [bmorton]
|
16
|
+
* Authorize.Net CIM: Misc fixes and doc improvements [bmorton]
|
17
|
+
* Authorize.Net CIM: Fix error when order is blank [KeeperPat]
|
18
|
+
* Beanstream: Add recurring payments support [castiglione]
|
19
|
+
* Make ePay password optional [ePay]
|
20
|
+
* Quickpay: skip testmode if transaction provided [brentmc79]
|
21
|
+
* Payflow: add additional fields [thorstadt]
|
22
|
+
* Authorize.Net CIM: Add get_customer_profile_ids [howaboutwe]
|
23
|
+
* PayPal Express: Add support for BrandName and Custom fields [exviva]
|
24
|
+
* Payflow: Handle dates with leading zeros [jcoleman]
|
25
|
+
* Authorize.Net CIM: Add CCV code support & improve tests [tgarnett]
|
26
|
+
* Add Authorize.Net SIM integration [courtland & rdp]
|
27
|
+
* Secure Pay AU: Handle periodic payments [tommeier]
|
28
|
+
* Viaklix: Add discover as a supported card type [waelchatila]
|
29
|
+
* Improvements to testing infrastructure for integrations [jduff]
|
30
|
+
* Add NAB Transact (AU) Gateway [tommeier]
|
31
|
+
|
3
32
|
== Version 1.20.4 (February 22, 2012)
|
4
33
|
|
5
34
|
* Fix json dependency
|
data/CONTRIBUTORS
CHANGED
@@ -259,3 +259,16 @@ Dwolla (September, 2011)
|
|
259
259
|
Samurai (November, 2011)
|
260
260
|
|
261
261
|
* Joshua Krall (jkrall)
|
262
|
+
|
263
|
+
CertoDirect Gateway (February, 2012)
|
264
|
+
|
265
|
+
* Aleksei Gusev (hron)
|
266
|
+
|
267
|
+
Authorize.Net SIM Integration (February, 2012)
|
268
|
+
|
269
|
+
* Roger Pack (rdp)
|
270
|
+
* Nick Rogers (courtland)
|
271
|
+
|
272
|
+
NAB Transact (AU) Gateway (February, 2012)
|
273
|
+
|
274
|
+
* Tom Meier (tommeier)
|
@@ -14,7 +14,7 @@ module ActiveMerchant #:nodoc:
|
|
14
14
|
'dankort' => /^5019\d{12}$/,
|
15
15
|
'maestro' => /^(5[06-8]|6\d)\d{10,17}$/,
|
16
16
|
'forbrugsforeningen' => /^600722\d{10}$/,
|
17
|
-
'laser' => /^(6304|6706|6771
|
17
|
+
'laser' => /^(6304|6706|6709|6771(?!89))\d{8}(\d{4}|\d{6,7})?$/
|
18
18
|
}
|
19
19
|
|
20
20
|
def self.included(base)
|
@@ -53,7 +53,7 @@ module ActiveMerchant #:nodoc:
|
|
53
53
|
#
|
54
54
|
# == Implmenting new gateways
|
55
55
|
#
|
56
|
-
# See the {ActiveMerchant Guide to Contributing}[
|
56
|
+
# See the {ActiveMerchant Guide to Contributing}[https://github.com/Shopify/active_merchant/wiki/Contributing]
|
57
57
|
#
|
58
58
|
class Gateway
|
59
59
|
include PostsData
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
1
2
|
module ActiveMerchant #:nodoc:
|
2
3
|
module Billing #:nodoc:
|
3
4
|
# ==== Customer Information Manager (CIM)
|
@@ -39,6 +40,7 @@ module ActiveMerchant #:nodoc:
|
|
39
40
|
:create_customer_payment_profile => 'createCustomerPaymentProfile',
|
40
41
|
:create_customer_shipping_address => 'createCustomerShippingAddress',
|
41
42
|
:get_customer_profile => 'getCustomerProfile',
|
43
|
+
:get_customer_profile_ids => 'getCustomerProfileIds',
|
42
44
|
:get_customer_payment_profile => 'getCustomerPaymentProfile',
|
43
45
|
:get_customer_shipping_address => 'getCustomerShippingAddress',
|
44
46
|
:delete_customer_profile => 'deleteCustomerProfile',
|
@@ -75,7 +77,8 @@ module ActiveMerchant #:nodoc:
|
|
75
77
|
|
76
78
|
ECHECK_TYPES = {
|
77
79
|
:ccd => 'CCD',
|
78
|
-
:ppd => 'PPD'
|
80
|
+
:ppd => 'PPD',
|
81
|
+
:web => 'WEB'
|
79
82
|
}
|
80
83
|
|
81
84
|
self.homepage_url = 'http://www.authorize.net/'
|
@@ -93,6 +96,7 @@ module ActiveMerchant #:nodoc:
|
|
93
96
|
# * <tt>:login</tt> -- The Authorize.Net API Login ID (REQUIRED)
|
94
97
|
# * <tt>:password</tt> -- The Authorize.Net Transaction Key. (REQUIRED)
|
95
98
|
# * <tt>:test</tt> -- +true+ or +false+. If true, perform transactions against the test server.
|
99
|
+
# * <tt>:delimiter</tt> -- The delimiter used in the direct response. Default is ',' (comma).
|
96
100
|
# Otherwise, perform transactions against the production server.
|
97
101
|
def initialize(options = {})
|
98
102
|
requires!(options, :login, :password)
|
@@ -107,11 +111,28 @@ module ActiveMerchant #:nodoc:
|
|
107
111
|
# It is *CRITICAL* that you save this ID. There is no way to retrieve this through the API. You will not
|
108
112
|
# be able to create another Customer Profile with the same information.
|
109
113
|
#
|
114
|
+
#
|
115
|
+
#
|
110
116
|
# ==== Options
|
117
|
+
#
|
118
|
+
# * <tt>:profile</tt> -- A hash containing at least one of the CONDITIONAL profile options below (REQUIRED)
|
119
|
+
#
|
120
|
+
# ==== Profile
|
111
121
|
#
|
112
|
-
#
|
122
|
+
# * <tt>:email</tt> -- Email address associated with the customer profile (CONDITIONAL)
|
123
|
+
# * <tt>:description</tt> -- Description of the customer or customer profile (CONDITIONAL)
|
124
|
+
# * <tt>:merchant_customer_id</tt> -- Merchant assigned ID for the customer (CONDITIONAL)
|
125
|
+
# * <tt>:payment_profile</tt> -- A hash containing the elements of the new payment profile (optional)
|
126
|
+
#
|
127
|
+
# ==== Payment Profile
|
128
|
+
#
|
129
|
+
# * <tt>:payment</tt> -- A hash containing information on payment. Either :credit_card or :bank_account (optional)
|
113
130
|
def create_customer_profile(options)
|
114
|
-
|
131
|
+
requires!(options, :profile)
|
132
|
+
requires!(options[:profile], :email) unless options[:profile][:merchant_customer_id] || options[:profile][:description]
|
133
|
+
requires!(options[:profile], :description) unless options[:profile][:email] || options[:profile][:merchant_customer_id]
|
134
|
+
requires!(options[:profile], :merchant_customer_id) unless options[:profile][:description] || options[:profile][:email]
|
135
|
+
|
115
136
|
request = build_request(:create_customer_profile, options)
|
116
137
|
commit(:create_customer_profile, request)
|
117
138
|
end
|
@@ -203,6 +224,11 @@ module ActiveMerchant #:nodoc:
|
|
203
224
|
commit(:get_customer_profile, request)
|
204
225
|
end
|
205
226
|
|
227
|
+
def get_customer_profile_ids(options = {})
|
228
|
+
request = build_request(:get_customer_profile_ids, options)
|
229
|
+
commit(:get_customer_profile_ids, request)
|
230
|
+
end
|
231
|
+
|
206
232
|
# Retrieve a customer payment profile for an existing customer profile.
|
207
233
|
#
|
208
234
|
# Returns a Response whose params hash contains all the payment profile information. Sensitive information such as credit card
|
@@ -332,7 +358,11 @@ module ActiveMerchant #:nodoc:
|
|
332
358
|
# - :type = (:void, :refund, :prior_auth_capture) (REQUIRED)
|
333
359
|
# - :type = (:auth_only, :capture_only, :auth_capture) (NOT USED)
|
334
360
|
#
|
335
|
-
# * <tt
|
361
|
+
# * <tt>:card_code</tt> -- CVV/CCV code (OPTIONAL)
|
362
|
+
# - :type = (:void, :refund, :prior_auth_capture) (NOT USED)
|
363
|
+
# - :type = (:auth_only, :capture_only, :auth_capture) (OPTIONAL)
|
364
|
+
#
|
365
|
+
# * <tt>:customer_shipping_address_id</tt> -- Payment gateway assigned ID associated with the customer shipping address (CONDITIONAL)
|
336
366
|
# - :type = (:void, :refund) (OPTIONAL)
|
337
367
|
# - :type = (:auth_only, :capture_only, :auth_capture) (NOT USED)
|
338
368
|
# - :type = (:prior_auth_capture) (OPTIONAL)
|
@@ -383,6 +413,10 @@ module ActiveMerchant #:nodoc:
|
|
383
413
|
#
|
384
414
|
# * <tt>:bank_routing_number_masked</tt> -- The last four gidits of the routing number to be refunded (CONDITIONAL - must be used with :bank_account_number_masked)
|
385
415
|
# * <tt>:bank_account_number_masked</tt> -- The last four digis of the bank account number to be refunded, Ex. XXXX1234 (CONDITIONAL - must be used with :bank_routing_number_masked)
|
416
|
+
#
|
417
|
+
# * <tt>:tax</tt> - A hash containing tax information for the refund (OPTIONAL - <tt>:amount</tt>, <tt>:name</tt> (31 characters), <tt>:description</tt> (255 characters))
|
418
|
+
# * <tt>:duty</tt> - A hash containting duty information for the refund (OPTIONAL - <tt>:amount</tt>, <tt>:name</tt> (31 characters), <tt>:description</tt> (255 characters))
|
419
|
+
# * <tt>:shipping</tt> - A hash containing shipping information for the refund (OPTIONAL - <tt>:amount</tt>, <tt>:name</tt> (31 characters), <tt>:description</tt> (255 characters))
|
386
420
|
def create_customer_profile_transaction_for_refund(options)
|
387
421
|
requires!(options, :transaction)
|
388
422
|
options[:transaction][:type] = :refund
|
@@ -424,8 +458,9 @@ module ActiveMerchant #:nodoc:
|
|
424
458
|
#
|
425
459
|
# * <tt>:customer_profile_id</tt> -- The Customer Profile ID of the customer to use in this transaction. (REQUIRED)
|
426
460
|
# * <tt>:customer_payment_profile_id</tt> -- The Customer Payment Profile ID of the Customer Payment Profile to be verified. (REQUIRED)
|
427
|
-
# * <tt>:customer_address_id</tt> -- The Customer Address ID of the Customer Shipping Address to be verified.
|
428
|
-
# * <tt>:
|
461
|
+
# * <tt>:customer_address_id</tt> -- The Customer Address ID of the Customer Shipping Address to be verified. (OPTIONAL)
|
462
|
+
# * <tt>:card_code</tt> -- If the payment profile is a credit card, the CCV/CVV code to validate with (OPTIONAL)
|
463
|
+
# * <tt>:validation_mode</tt> -- <tt>:live</tt> or <tt>:test</tt> In Test Mode, only field validation is performed. (REQUIRED
|
429
464
|
# In Live Mode, a transaction is generated and submitted to the processor with the amount of $0.01. If successful, the transaction is immediately voided. (REQUIRED)
|
430
465
|
def validate_customer_payment_profile(options)
|
431
466
|
requires!(options, :customer_profile_id, :customer_payment_profile_id, :validation_mode)
|
@@ -466,6 +501,14 @@ module ActiveMerchant #:nodoc:
|
|
466
501
|
def build_create_customer_profile_request(xml, options)
|
467
502
|
add_profile(xml, options[:profile])
|
468
503
|
|
504
|
+
xml.tag!('validationMode', CIM_VALIDATION_MODES[options[:validation_mode]]) if options[:validation_mode]
|
505
|
+
|
506
|
+
if options.has_key?(:payment_profile)
|
507
|
+
xml.tag!('paymentProfile') do
|
508
|
+
add_payment_profile(xml, options[:payment_profile])
|
509
|
+
end
|
510
|
+
end
|
511
|
+
|
469
512
|
xml.target!
|
470
513
|
end
|
471
514
|
|
@@ -513,6 +556,10 @@ module ActiveMerchant #:nodoc:
|
|
513
556
|
xml.target!
|
514
557
|
end
|
515
558
|
|
559
|
+
def build_get_customer_profile_ids_request(xml, options)
|
560
|
+
xml.target!
|
561
|
+
end
|
562
|
+
|
516
563
|
def build_get_customer_payment_profile_request(xml, options)
|
517
564
|
xml.tag!('customerProfileId', options[:customer_profile_id])
|
518
565
|
xml.tag!('customerPaymentProfileId', options[:customer_payment_profile_id])
|
@@ -564,6 +611,7 @@ module ActiveMerchant #:nodoc:
|
|
564
611
|
xml.tag!('customerProfileId', options[:customer_profile_id])
|
565
612
|
xml.tag!('customerPaymentProfileId', options[:customer_payment_profile_id])
|
566
613
|
xml.tag!('customerShippingAddressId', options[:customer_address_id]) if options[:customer_address_id]
|
614
|
+
tag_unless_blank(xml, 'cardCode', options[:card_code])
|
567
615
|
xml.tag!('validationMode', CIM_VALIDATION_MODES[options[:validation_mode]]) if options[:validation_mode]
|
568
616
|
|
569
617
|
xml.target!
|
@@ -606,7 +654,7 @@ module ActiveMerchant #:nodoc:
|
|
606
654
|
tag_unless_blank(xml,'customerShippingAddressId', transaction[:customer_shipping_address_id])
|
607
655
|
xml.tag!('transId', transaction[:trans_id])
|
608
656
|
when :refund
|
609
|
-
#TODO - add
|
657
|
+
#TODO - add lineItems and extraOptions fields
|
610
658
|
xml.tag!('amount', transaction[:amount])
|
611
659
|
tag_unless_blank(xml, 'customerProfileId', transaction[:customer_profile_id])
|
612
660
|
tag_unless_blank(xml, 'customerPaymentProfileId', transaction[:customer_payment_profile_id])
|
@@ -615,6 +663,9 @@ module ActiveMerchant #:nodoc:
|
|
615
663
|
tag_unless_blank(xml, 'bankRoutingNumberMasked', transaction[:bank_routing_number_masked])
|
616
664
|
tag_unless_blank(xml, 'bankAccountNumberMasked', transaction[:bank_account_number_masked])
|
617
665
|
xml.tag!('transId', transaction[:trans_id])
|
666
|
+
add_tax(xml, transaction[:tax]) if transaction[:tax]
|
667
|
+
add_duty(xml, transaction[:duty]) if transaction[:duty]
|
668
|
+
add_shipping(xml, transaction[:shipping]) if transaction[:shipping]
|
618
669
|
when :prior_auth_capture
|
619
670
|
xml.tag!('amount', transaction[:amount])
|
620
671
|
xml.tag!('transId', transaction[:trans_id])
|
@@ -623,12 +674,37 @@ module ActiveMerchant #:nodoc:
|
|
623
674
|
xml.tag!('customerProfileId', transaction[:customer_profile_id])
|
624
675
|
xml.tag!('customerPaymentProfileId', transaction[:customer_payment_profile_id])
|
625
676
|
xml.tag!('approvalCode', transaction[:approval_code]) if transaction[:type] == :capture_only
|
677
|
+
tag_unless_blank(xml, 'cardCode', transaction[:card_code])
|
626
678
|
end
|
627
|
-
add_order(xml, transaction[:order]) if transaction[:order]
|
679
|
+
add_order(xml, transaction[:order]) if transaction[:order].present?
|
628
680
|
end
|
629
681
|
end
|
630
682
|
end
|
683
|
+
|
684
|
+
def add_tax(xml, tax)
|
685
|
+
xml.tag!('tax') do
|
686
|
+
xml.tag!('amount', tax[:amount]) if tax[:amount]
|
687
|
+
xml.tag!('name', tax[:name]) if tax[:name]
|
688
|
+
xml.tag!('description', tax[:description]) if tax[:description]
|
689
|
+
end
|
690
|
+
end
|
691
|
+
|
692
|
+
def add_duty(xml, duty)
|
693
|
+
xml.tag!('duty') do
|
694
|
+
xml.tag!('amount', duty[:amount]) if duty[:amount]
|
695
|
+
xml.tag!('name', duty[:name]) if duty[:name]
|
696
|
+
xml.tag!('description', duty[:description]) if duty[:description]
|
697
|
+
end
|
698
|
+
end
|
631
699
|
|
700
|
+
def add_shipping(xml, shipping)
|
701
|
+
xml.tag!('shipping') do
|
702
|
+
xml.tag!('amount', shipping[:amount]) if shipping[:amount]
|
703
|
+
xml.tag!('name', shipping[:name]) if shipping[:name]
|
704
|
+
xml.tag!('description', shipping[:description]) if shipping[:description]
|
705
|
+
end
|
706
|
+
end
|
707
|
+
|
632
708
|
def add_order(xml, order)
|
633
709
|
xml.tag!('order') do
|
634
710
|
xml.tag!('invoiceNumber', order[:invoice_number]) if order[:invoice_number]
|
@@ -702,6 +778,10 @@ module ActiveMerchant #:nodoc:
|
|
702
778
|
xml.tag!('cardNumber', credit_card.number)
|
703
779
|
# The expiration date of the credit card used for the subscription
|
704
780
|
xml.tag!('expirationDate', expdate(credit_card))
|
781
|
+
# Note that Authorize.net does not save CVV codes as part of the
|
782
|
+
# payment profile. Any transactions/validations after the payment
|
783
|
+
# profile is created that wish to use CVV verification must pass
|
784
|
+
# the CVV code to authorize.net again.
|
705
785
|
xml.tag!('cardCode', credit_card.verification_value) if credit_card.verification_value?
|
706
786
|
end
|
707
787
|
end
|
@@ -756,24 +836,23 @@ module ActiveMerchant #:nodoc:
|
|
756
836
|
message = response_params['messages']['message']['text']
|
757
837
|
test_mode = test? || message =~ /Test Mode/
|
758
838
|
success = response_params['messages']['result_code'] == 'Ok'
|
839
|
+
response_params['direct_response'] = parse_direct_response(response_params['direct_response']) if response_params['direct_response']
|
840
|
+
transaction_id = response_params['direct_response']['transaction_id'] if response_params['direct_response']
|
759
841
|
|
760
|
-
|
842
|
+
Response.new(success, message, response_params,
|
761
843
|
:test => test_mode,
|
762
|
-
:authorization => response_params['customer_profile_id'] || (response_params['profile'] ? response_params['profile']['customer_profile_id'] : nil)
|
844
|
+
:authorization => transaction_id || response_params['customer_profile_id'] || (response_params['profile'] ? response_params['profile']['customer_profile_id'] : nil)
|
763
845
|
)
|
764
|
-
|
765
|
-
response.params['direct_response'] = parse_direct_response(response) if response.params['direct_response']
|
766
|
-
response
|
767
846
|
end
|
768
847
|
|
769
848
|
def tag_unless_blank(xml, tag_name, data)
|
770
849
|
xml.tag!(tag_name, data) unless data.blank? || data.nil?
|
771
850
|
end
|
772
851
|
|
773
|
-
def parse_direct_response(
|
774
|
-
|
775
|
-
|
776
|
-
|
852
|
+
def parse_direct_response(params)
|
853
|
+
delimiter = @options[:delimiter] || ','
|
854
|
+
direct_response = {'raw' => params}
|
855
|
+
direct_response_fields = params.split(delimiter)
|
777
856
|
direct_response.merge(
|
778
857
|
{
|
779
858
|
'response_code' => direct_response_fields[0],
|
@@ -815,7 +894,14 @@ module ActiveMerchant #:nodoc:
|
|
815
894
|
'purchase_order_number' => direct_response_fields[36],
|
816
895
|
'md5_hash' => direct_response_fields[37],
|
817
896
|
'card_code' => direct_response_fields[38],
|
818
|
-
'cardholder_authentication_verification_response' => direct_response_fields[39]
|
897
|
+
'cardholder_authentication_verification_response' => direct_response_fields[39],
|
898
|
+
# The following direct response fields are only available in version 3.1 of the
|
899
|
+
# transaction response. Check your merchant account settings for details.
|
900
|
+
'account_number' => direct_response_fields[50] || '',
|
901
|
+
'card_type' => direct_response_fields[51] || '',
|
902
|
+
'split_tender_id' => direct_response_fields[52] || '',
|
903
|
+
'requested_amount' => direct_response_fields[53] || '',
|
904
|
+
'balance_on_card' => direct_response_fields[54] || '',
|
819
905
|
}
|
820
906
|
)
|
821
907
|
end
|
@@ -19,7 +19,6 @@ module ActiveMerchant #:nodoc:
|
|
19
19
|
# To learn more about storing credit cards with the Beanstream gateway, please read the BEAN_Payment_Profiles.pdf (I had to phone BeanStream to request it.)
|
20
20
|
#
|
21
21
|
# == Notes
|
22
|
-
# * Recurring billing is not yet implemented.
|
23
22
|
# * Adding of order products information is not implemented.
|
24
23
|
# * Ensure that country and province data is provided as a code such as "CA", "US", "QC".
|
25
24
|
# * login is the Beanstream merchant ID, username and password should be enabled in your Beanstream account and passed in using the <tt>:user</tt> and <tt>:password</tt> options.
|
@@ -95,6 +94,35 @@ module ActiveMerchant #:nodoc:
|
|
95
94
|
commit(post)
|
96
95
|
end
|
97
96
|
|
97
|
+
def recurring(money, source, options = {})
|
98
|
+
post = {}
|
99
|
+
add_amount(post, money)
|
100
|
+
add_invoice(post, options)
|
101
|
+
add_credit_card(post, source)
|
102
|
+
add_address(post, options)
|
103
|
+
add_transaction_type(post, purchase_action(source))
|
104
|
+
add_recurring_type(post, options)
|
105
|
+
commit(post)
|
106
|
+
end
|
107
|
+
|
108
|
+
def update_recurring(amount, source, options = {})
|
109
|
+
post = {}
|
110
|
+
add_recurring_amount(post, amount)
|
111
|
+
add_recurring_invoice(post, options)
|
112
|
+
add_credit_card(post, source)
|
113
|
+
add_address(post, options)
|
114
|
+
add_recurring_operation_type(post, :update)
|
115
|
+
add_recurring_service(post, options)
|
116
|
+
recurring_commit(post)
|
117
|
+
end
|
118
|
+
|
119
|
+
def cancel_recurring(options = {})
|
120
|
+
post = {}
|
121
|
+
add_recurring_operation_type(post, :cancel)
|
122
|
+
add_recurring_service(post, options)
|
123
|
+
recurring_commit(post)
|
124
|
+
end
|
125
|
+
|
98
126
|
def interac
|
99
127
|
@interac ||= BeanstreamInteracGateway.new(@options)
|
100
128
|
end
|
@@ -2,6 +2,7 @@ module ActiveMerchant #:nodoc:
|
|
2
2
|
module Billing #:nodoc:
|
3
3
|
module BeanstreamCore
|
4
4
|
URL = 'https://www.beanstream.com/scripts/process_transaction.asp'
|
5
|
+
RECURRING_URL = 'https://www.beanstream.com/scripts/recurring_billing.asp'
|
5
6
|
SECURE_PROFILE_URL = 'https://www.beanstream.com/scripts/payment_profile.asp'
|
6
7
|
SP_SERVICE_VERSION = '1.1'
|
7
8
|
|
@@ -37,6 +38,27 @@ module ActiveMerchant #:nodoc:
|
|
37
38
|
'9' => 'I'
|
38
39
|
}
|
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
|
+
|
40
62
|
def self.included(base)
|
41
63
|
base.default_currency = 'CAD'
|
42
64
|
|
@@ -207,11 +229,66 @@ module ActiveMerchant #:nodoc:
|
|
207
229
|
post[:status] = options[:status]
|
208
230
|
end
|
209
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
|
+
|
210
287
|
def parse(body)
|
211
288
|
results = {}
|
212
289
|
if !body.nil?
|
213
290
|
body.split(/&/).each do |pair|
|
214
|
-
key,val = pair.split(/=/)
|
291
|
+
key, val = pair.split(/=/)
|
215
292
|
results[key.to_sym] = val.nil? ? nil : CGI.unescape(val)
|
216
293
|
end
|
217
294
|
end
|
@@ -225,11 +302,22 @@ module ActiveMerchant #:nodoc:
|
|
225
302
|
|
226
303
|
results
|
227
304
|
end
|
228
|
-
|
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
|
+
|
229
313
|
def commit(params, use_profile_api = false)
|
230
314
|
post(post_data(params,use_profile_api),use_profile_api)
|
231
315
|
end
|
232
316
|
|
317
|
+
def recurring_commit(params)
|
318
|
+
recurring_post(post_data(params, false))
|
319
|
+
end
|
320
|
+
|
233
321
|
def post(data, use_profile_api=nil)
|
234
322
|
response = parse(ssl_post((use_profile_api ? SECURE_PROFILE_URL : URL), data))
|
235
323
|
response[:customer_vault_id] = response[:customerCode] if response[:customerCode]
|
@@ -240,7 +328,12 @@ module ActiveMerchant #:nodoc:
|
|
240
328
|
:avs_result => { :code => (AVS_CODES.include? response[:avsId]) ? AVS_CODES[response[:avsId]] : response[:avsId] }
|
241
329
|
)
|
242
330
|
end
|
243
|
-
|
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
|
+
|
244
337
|
def authorization_from(response)
|
245
338
|
"#{response[:trnId]};#{response[:trnAmount]};#{response[:trnType]}"
|
246
339
|
end
|
@@ -249,10 +342,18 @@ module ActiveMerchant #:nodoc:
|
|
249
342
|
response[:messageText] || response[:responseMessage]
|
250
343
|
end
|
251
344
|
|
345
|
+
def recurring_message_from(response)
|
346
|
+
response[:message]
|
347
|
+
end
|
348
|
+
|
252
349
|
def success?(response)
|
253
350
|
response[:responseType] == 'R' || response[:trnApproved] == '1' || response[:responseCode] == '1'
|
254
351
|
end
|
255
352
|
|
353
|
+
def recurring_success?(response)
|
354
|
+
response[:code] == '1'
|
355
|
+
end
|
356
|
+
|
256
357
|
def add_source(post, source)
|
257
358
|
if source.is_a?(String) or source.is_a?(Integer)
|
258
359
|
post[:customerCode] = source
|
@@ -280,6 +381,7 @@ module ActiveMerchant #:nodoc:
|
|
280
381
|
|
281
382
|
params.reject{|k, v| v.blank?}.collect { |key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join("&")
|
282
383
|
end
|
384
|
+
|
283
385
|
end
|
284
386
|
end
|
285
387
|
end
|