activemerchant 1.20.4 → 1.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data.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
|