activemerchant 1.13.0 → 1.14.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. data.tar.gz.sig +0 -0
  2. data/CHANGELOG +19 -0
  3. data/CONTRIBUTORS +14 -2
  4. data/README.rdoc +2 -0
  5. data/lib/active_merchant/billing/credit_card.rb +4 -4
  6. data/lib/active_merchant/billing/gateway.rb +1 -1
  7. data/lib/active_merchant/billing/gateways/authorize_net.rb +10 -5
  8. data/lib/active_merchant/billing/gateways/authorize_net_cim.rb +133 -11
  9. data/lib/active_merchant/billing/gateways/barclays_epdq.rb +1 -1
  10. data/lib/active_merchant/billing/gateways/beanstream.rb +39 -2
  11. data/lib/active_merchant/billing/gateways/beanstream/beanstream_core.rb +64 -26
  12. data/lib/active_merchant/billing/gateways/bogus.rb +21 -3
  13. data/lib/active_merchant/billing/gateways/cyber_source.rb +5 -1
  14. data/lib/active_merchant/billing/gateways/data_cash.rb +1 -1
  15. data/lib/active_merchant/billing/gateways/efsnet.rb +1 -1
  16. data/lib/active_merchant/billing/gateways/epay.rb +5 -1
  17. data/lib/active_merchant/billing/gateways/eway.rb +4 -0
  18. data/lib/active_merchant/billing/gateways/eway_managed.rb +231 -0
  19. data/lib/active_merchant/billing/gateways/federated_canada.rb +6 -7
  20. data/lib/active_merchant/billing/gateways/first_pay.rb +7 -2
  21. data/lib/active_merchant/billing/gateways/iridium.rb +1 -1
  22. data/lib/active_merchant/billing/gateways/jetpay.rb +5 -2
  23. data/lib/active_merchant/billing/gateways/linkpoint.rb +6 -1
  24. data/lib/active_merchant/billing/gateways/merchant_e_solutions.rb +6 -4
  25. data/lib/active_merchant/billing/gateways/merchant_ware.rb +1 -1
  26. data/lib/active_merchant/billing/gateways/moneris.rb +1 -1
  27. data/lib/active_merchant/billing/gateways/netaxept.rb +6 -1
  28. data/lib/active_merchant/billing/gateways/ogone.rb +1 -1
  29. data/lib/active_merchant/billing/gateways/orbital.rb +317 -0
  30. data/lib/active_merchant/billing/gateways/orbital/orbital_soft_descriptors.rb +46 -0
  31. data/lib/active_merchant/billing/gateways/paybox_direct.rb +1 -1
  32. data/lib/active_merchant/billing/gateways/payflow.rb +1 -1
  33. data/lib/active_merchant/billing/gateways/payflow_express.rb +6 -1
  34. data/lib/active_merchant/billing/gateways/payment_express.rb +6 -1
  35. data/lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb +7 -2
  36. data/lib/active_merchant/billing/gateways/paypal/paypal_express_response.rb +11 -7
  37. data/lib/active_merchant/billing/gateways/plugnpay.rb +1 -1
  38. data/lib/active_merchant/billing/gateways/psigate.rb +1 -1
  39. data/lib/active_merchant/billing/gateways/qbms.rb +1 -1
  40. data/lib/active_merchant/billing/gateways/quantum.rb +6 -1
  41. data/lib/active_merchant/billing/gateways/quickpay.rb +6 -1
  42. data/lib/active_merchant/billing/gateways/realex.rb +196 -72
  43. data/lib/active_merchant/billing/gateways/sage_pay.rb +7 -2
  44. data/lib/active_merchant/billing/gateways/secure_pay_au.rb +38 -2
  45. data/lib/active_merchant/billing/gateways/smart_ps.rb +2 -2
  46. data/lib/active_merchant/billing/gateways/trust_commerce.rb +7 -2
  47. data/lib/active_merchant/billing/gateways/verifi.rb +1 -1
  48. data/lib/active_merchant/billing/gateways/worldpay.rb +280 -0
  49. data/lib/active_merchant/billing/integrations/moneybookers/helper.rb +0 -1
  50. data/lib/active_merchant/billing/integrations/return.rb +6 -1
  51. data/lib/active_merchant/billing/integrations/sage_pay_form/notification.rb +6 -0
  52. data/lib/active_merchant/billing/integrations/sage_pay_form/return.rb +5 -1
  53. data/lib/active_merchant/common/connection.rb +15 -0
  54. data/lib/active_merchant/common/posts_data.rb +2 -0
  55. data/lib/active_merchant/common/utils.rb +4 -0
  56. data/lib/active_merchant/version.rb +1 -1
  57. metadata +8 -4
  58. metadata.gz.sig +0 -0
data.tar.gz.sig CHANGED
Binary file
data/CHANGELOG CHANGED
@@ -1,5 +1,24 @@
1
1
  = ActiveMerchant CHANGELOG
2
2
 
3
+ == Version 1.14.0 (Apr 29, 2011)
4
+
5
+ * SagePayForm: Implement #cancelled? for Return. [wisq]
6
+ * Add #cancelled? to Integrations::Return [wisq]
7
+ * Bogus gateway: Add refund support and better tests [wisq]
8
+ * Beanstream: Add support for storing cards [duffomelia]
9
+ * eWay: Add support for storing cards [duffomelia]
10
+ * Add validation mode to update profile request [Ken Miller]
11
+ * Authorize.net CIM: Add oldLiveMode [ntalbott]
12
+ * Authorize.net CIM: Add extra transaction types [Ken Miller]
13
+ * JetPay: gateway tweaks [ntalbott]
14
+ * Deprecate a bunch more #credit methods [ntalbott]
15
+ * RealEx: Add authorize/capture/credit/void [ntalbott]
16
+ * SecurePay AU: Add authorize/capture/credit/void [ntalbott]
17
+ * PayPal Express: Make response parsing more robust [ntalbott]
18
+ * Test deprecation warnings; add deprecation line numbers [ntabott]
19
+ * Add Orbital direct gateway [ntalbott]
20
+ * Add WorldPay direct gateway [ntalbott]
21
+
3
22
  == Version 1.13.0 (Apr 19, 2011)
4
23
 
5
24
  * Add a Gemfile for optional bundler support [ssoroka]
@@ -26,6 +26,7 @@ Linkpoint Gateway
26
26
  eWay Gateway
27
27
 
28
28
  * Originally contributed by Lucas Carlson (mailto:lucas@rufy.com)
29
+ * Managed Payments support by Jason Stirk with improvements by Keith Pitt
29
30
 
30
31
  CardStream Gateway
31
32
 
@@ -83,6 +84,7 @@ PaypalNVGateway (Apr 12, 2008)
83
84
  Beanstream (May 13, 2008)
84
85
 
85
86
  * Created by xiaobozz ( xiaobozzz at gmail dot com )
87
+ * Secure Profiles support by Forrest Zeisler (http://github.com/forrest)
86
88
 
87
89
  Sage (June, 2008)
88
90
 
@@ -211,7 +213,17 @@ NMI
211
213
  QBMS
212
214
 
213
215
  * Will Glozer (wg)
214
- WorldPay (Feb 17, 2011)
216
+
217
+ WorldPay Integration (Feb 17, 2011)
215
218
 
216
219
  * Original code by Unknown from this patch: https://jadedpixel.lighthouseapp.com/projects/11599/tickets/3-patch-integration-support-for-worldpay-uk
217
- * Refactored by Soleone
220
+ * Refactored by Soleone
221
+
222
+ WorldPay Gateway
223
+
224
+ * Original code by Amit kumar (ask4amit@gmail.com)
225
+ * Refactored by Nathaniel Talbott (ntalbott)
226
+
227
+ Orbital Paymentech Gateway (July, 2009)
228
+
229
+ * Sam Vincent - http://ecommerce.versapay.com
@@ -43,6 +43,7 @@ The {ActiveMerchant Wiki}[http://github.com/Shopify/active_merchant/wikis] conta
43
43
  * {NETbilling}[http://www.netbilling.com] - US
44
44
  * {NMI}[http://nmi.com/] - US
45
45
  * {Ogone DirectLink}[http://www.ogone.com] - BE, DE, FR, NL, AT, CH
46
+ * {Orbital Paymentech}[http://chasepaymentech.com/] - CA, US
46
47
  * {PayBox Direct}[http://www.paybox.com] - FR
47
48
  * {PayJunction}[http://www.payjunction.com/] - US
48
49
  * {PaySecure}[http://www.commsecure.com.au/paysecure.shtml] - AU
@@ -75,6 +76,7 @@ The {ActiveMerchant Wiki}[http://github.com/Shopify/active_merchant/wikis] conta
75
76
  * {Verifi}[http://www.verifi.com/] - US
76
77
  * {ViaKLIX}[http://viaklix.com] - US
77
78
  * {Wirecard}[http://www.wirecard.com] - DE
79
+ * {WorldPay}[http://www.worldpay.com] - AU, HK, GB, US
78
80
 
79
81
  == Supported Offsite Payment Gateways
80
82
 
@@ -65,19 +65,19 @@ module ActiveMerchant #:nodoc:
65
65
  end
66
66
 
67
67
  def name?
68
- first_name? && last_name?
68
+ first_name? || last_name?
69
69
  end
70
70
 
71
71
  def first_name?
72
- !@first_name.blank?
72
+ @first_name.present?
73
73
  end
74
74
 
75
75
  def last_name?
76
- !@last_name.blank?
76
+ @last_name.present?
77
77
  end
78
78
 
79
79
  def name
80
- "#{@first_name} #{@last_name}"
80
+ [@first_name, @last_name].compact.join(' ')
81
81
  end
82
82
 
83
83
  def verification_value?
@@ -135,7 +135,7 @@ module ActiveMerchant #:nodoc:
135
135
  def amount(money)
136
136
  return nil if money.nil?
137
137
  cents = if money.respond_to?(:cents)
138
- warn "Support for Money objects is deprecated and will be removed from a future release of ActiveMerchant. Please use an Integer value in cents"
138
+ deprecated "Support for Money objects is deprecated and will be removed from a future release of ActiveMerchant. Please use an Integer value in cents"
139
139
  money.cents
140
140
  else
141
141
  money
@@ -134,21 +134,21 @@ module ActiveMerchant #:nodoc:
134
134
  commit('VOID', nil, post)
135
135
  end
136
136
 
137
- # Credit an account.
137
+ # Refund a transaction.
138
138
  #
139
- # This transaction is also referred to as a Refund and indicates to the gateway that
139
+ # This transaction indicates to the gateway that
140
140
  # money should flow from the merchant to the customer.
141
141
  #
142
142
  # ==== Parameters
143
143
  #
144
144
  # * <tt>money</tt> -- The amount to be credited to the customer as an Integer value in cents.
145
- # * <tt>identification</tt> -- The ID of the original transaction against which the credit is being issued.
145
+ # * <tt>identification</tt> -- The ID of the original transaction against which the refund is being issued.
146
146
  # * <tt>options</tt> -- A hash of parameters.
147
147
  #
148
148
  # ==== Options
149
149
  #
150
- # * <tt>:card_number</tt> -- The credit card number the credit is being issued to. (REQUIRED)
151
- def credit(money, identification, options = {})
150
+ # * <tt>:card_number</tt> -- The credit card number the refund is being issued to. (REQUIRED)
151
+ def refund(money, identification, options = {})
152
152
  requires!(options, :card_number)
153
153
 
154
154
  post = { :trans_id => identification,
@@ -159,6 +159,11 @@ module ActiveMerchant #:nodoc:
159
159
  commit('CREDIT', money, post)
160
160
  end
161
161
 
162
+ def credit(money, identification, options = {})
163
+ deprecated CREDIT_DEPRECATION_MESSAGE
164
+ refund(money, identification, options)
165
+ end
166
+
162
167
  # Create a recurring payment.
163
168
  #
164
169
  # This transaction creates a new Automated Recurring Billing (ARB) subscription. Your account must have ARB enabled.
@@ -54,13 +54,17 @@ module ActiveMerchant #:nodoc:
54
54
  CIM_TRANSACTION_TYPES = {
55
55
  :auth_capture => 'profileTransAuthCapture',
56
56
  :auth_only => 'profileTransAuthOnly',
57
- :capture_only => 'profileTransCaptureOnly'
57
+ :capture_only => 'profileTransCaptureOnly',
58
+ :prior_auth_capture => 'profileTransPriorAuthCapture',
59
+ :refund => 'profileTransRefund',
60
+ :void => 'profileTransVoid'
58
61
  }
59
62
 
60
63
  CIM_VALIDATION_MODES = {
61
64
  :none => 'none',
62
65
  :test => 'testMode',
63
- :live => 'liveMode'
66
+ :live => 'liveMode',
67
+ :old => 'oldLiveMode'
64
68
  }
65
69
 
66
70
  BANK_ACCOUNT_TYPES = {
@@ -309,14 +313,105 @@ module ActiveMerchant #:nodoc:
309
313
  #
310
314
  # ==== Transaction
311
315
  #
312
- # * <tt>:type</tt> -- The type of transaction. Can be either <tt>:auth_only</tt>, <tt>:capture_only</tt>, or <tt>:auth_capture</tt>. (REQUIRED)
313
- # * <tt>:amount</tt> -- The amount for the tranaction. Formatted with a decimal. For example "4.95" (REQUIRED)
314
- # * <tt>:customer_profile_id</tt> -- The Customer Profile ID of the customer to use in this transaction. (REQUIRED)
315
- # * <tt>:customer_payment_profile_id</tt> -- The Customer Payment Profile ID of the Customer Payment Profile to use in this transaction. (REQUIRED)
316
+ # * <tt>:type</tt> -- The type of transaction. Can be either <tt>:auth_only</tt>, <tt>:capture_only</tt>, <tt>:auth_capture</tt>, <tt>:prior_auth_capture</tt>, <tt>:refund</tt> or <tt>:void</tt>. (REQUIRED)
317
+ # * <tt>:amount</tt> -- The amount for the tranaction. Formatted with a decimal. For example "4.95" (CONDITIONAL)
318
+ # - :type == :void (NOT USED)
319
+ # - :type == (:refund, :auth_only, :capture_only, :auth_capture, :prior_auth_capture) (REQUIRED)
320
+ #
321
+ # * <tt>:customer_profile_id</tt> -- The Customer Profile ID of the customer to use in this transaction. (CONDITIONAL)
322
+ # - :type == (:void, :prior_auth_capture) (OPTIONAL)
323
+ # - :type == :refund (CONDITIONAL - required if masked information is not being submitted [see below])
324
+ # - :type == (:auth_only, :capture_only, :auth_capture) (REQUIRED)
325
+ #
326
+ # * <tt>:customer_payment_profile_id</tt> -- The Customer Payment Profile ID of the Customer Payment Profile to use in this transaction. (CONDITIONAL)
327
+ # - :type == (:void, :prior_auth_capture) (OPTIONAL)
328
+ # - :type == :refund (CONDITIONAL - required if masked information is not being submitted [see below])
329
+ # - :type == (:auth_only, :capture_only, :auth_capture) (REQUIRED)
330
+ #
331
+ # * <tt>:trans_id</tt> -- The payment gateway assigned transaction ID of the original transaction (CONDITIONAL):
332
+ # - :type = (:void, :refund, :prior_auth_capture) (REQUIRED)
333
+ # - :type = (:auth_only, :capture_only, :auth_capture) (NOT USED)
334
+ #
335
+ # * <tt>customer_shipping_address_id</tt> -- Payment gateway assigned ID associated with the customer shipping address (CONDITIONAL)
336
+ # - :type = (:void, :refund) (OPTIONAL)
337
+ # - :type = (:auth_only, :capture_only, :auth_capture) (NOT USED)
338
+ # - :type = (:prior_auth_capture) (OPTIONAL)
339
+ #
340
+ # ==== For :type == :refund only
341
+ # * <tt>:credit_card_number_masked</tt> -- (CONDITIONAL - requied for credit card refunds is :customer_profile_id AND :customer_payment_profile_id are missing)
342
+ # * <tt>:bank_routing_number_masked && :bank_account_number_masked</tt> -- (CONDITIONAL - requied for electronic check refunds is :customer_profile_id AND :customer_payment_profile_id are missing) (NOT ABLE TO TEST - I keep getting "ACH transactions are not accepted by this merchant." when trying to make a payment and, until that's possible I can't refund (wiseleyb@gmail.com))
316
343
  def create_customer_profile_transaction(options)
317
344
  requires!(options, :transaction)
318
- requires!(options[:transaction], :type, :amount, :customer_profile_id, :customer_payment_profile_id)
345
+ requires!(options[:transaction], :type)
346
+ case options[:transaction][:type]
347
+ when :void
348
+ requires!(options[:transaction], :trans_id)
349
+ when :refund
350
+ requires!(options[:transaction], :trans_id) &&
351
+ (
352
+ (options[:transaction][:customer_profile_id] && options[:transaction][:customer_payment_profile_id]) ||
353
+ options[:transaction][:credit_card_number_masked] ||
354
+ (options[:transaction][:bank_routing_number_masked] && options[:transaction][:bank_account_number_masked])
355
+ )
356
+ when :prior_auth_capture
357
+ requires!(options[:transaction], :amount, :trans_id)
358
+ else
359
+ requires!(options[:transaction], :amount, :customer_profile_id, :customer_payment_profile_id)
360
+ end
361
+ request = build_request(:create_customer_profile_transaction, options)
362
+ commit(:create_customer_profile_transaction, request)
363
+ end
319
364
 
365
+ # Creates a new payment transaction for refund from an existing customer profile
366
+ #
367
+ # This is what is used to refund a transaction you have stored in a Customer Profile.
368
+ #
369
+ # Returns a Response object that contains the result of the transaction in <tt>params['direct_response']</tt>
370
+ #
371
+ # ==== Options
372
+ #
373
+ # * <tt>:transaction</tt> -- A hash containing information on the transaction that is being requested. (REQUIRED)
374
+ #
375
+ # ==== Transaction
376
+ #
377
+ # * <tt>:amount</tt> -- The total amount to be refunded (REQUIRED)
378
+ #
379
+ # * <tt>:customer_profile_id</tt> -- The Customer Profile ID of the customer to use in this transaction. (CONDITIONAL :customer_payment_profile_id must be included if used)
380
+ # * <tt>:customer_payment_profile_id</tt> -- The Customer Payment Profile ID of the Customer Payment Profile to use in this transaction. (CONDITIONAL :customer_profile_id must be included if used)
381
+ #
382
+ # * <tt>:credit_card_number_masked</tt> -- Four Xs follwed by the last four digits of the credit card (CONDITIONAL - used if customer_profile_id and customer_payment_profile_id aren't given)
383
+ #
384
+ # * <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
+ # * <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)
386
+ def create_customer_profile_transaction_for_refund(options)
387
+ requires!(options, :transaction)
388
+ options[:transaction][:type] = :refund
389
+ requires!(options[:transaction], :trans_id)
390
+ requires!(options[:transaction], :amount)
391
+ request = build_request(:create_customer_profile_transaction, options)
392
+ commit(:create_customer_profile_transaction, request)
393
+ end
394
+
395
+ # Creates a new payment transaction for void from an existing customer profile
396
+ #
397
+ # This is what is used to void a transaction you have stored in a Customer Profile.
398
+ #
399
+ # Returns a Response object that contains the result of the transaction in <tt>params['direct_response']</tt>
400
+ #
401
+ # ==== Options
402
+ #
403
+ # * <tt>:transaction</tt> -- A hash containing information on the transaction that is being requested. (REQUIRED)
404
+ #
405
+ # ==== Transaction
406
+ #
407
+ # * <tt>:trans_id</tt> -- The payment gateway assigned transaction id of the original transaction. (REQUIRED)
408
+ # * <tt>:customer_profile_id</tt> -- The Customer Profile ID of the customer to use in this transaction.
409
+ # * <tt>:customer_payment_profile_id</tt> -- The Customer Payment Profile ID of the Customer Payment Profile to use in this transaction.
410
+ # * <tt>:customer_shipping_address_id</tt> -- Payment gateway assigned ID associated with the customer shipping address.
411
+ def create_customer_profile_transaction_for_void(options)
412
+ requires!(options, :transaction)
413
+ options[:transaction][:type] = :void
414
+ requires!(options[:transaction], :trans_id)
320
415
  request = build_request(:create_customer_profile_transaction, options)
321
416
  commit(:create_customer_profile_transaction, request)
322
417
  end
@@ -443,6 +538,8 @@ module ActiveMerchant #:nodoc:
443
538
  add_payment_profile(xml, options[:payment_profile])
444
539
  end
445
540
 
541
+ xml.tag!('validationMode', CIM_VALIDATION_MODES[options[:validation_mode]]) if options[:validation_mode]
542
+
446
543
  xml.target!
447
544
  end
448
545
 
@@ -502,10 +599,31 @@ module ActiveMerchant #:nodoc:
502
599
  xml.tag!('transaction') do
503
600
  xml.tag!(CIM_TRANSACTION_TYPES[transaction[:type]]) do
504
601
  # The amount to be billed to the customer
505
- xml.tag!('amount', transaction[:amount])
506
- xml.tag!('customerProfileId', transaction[:customer_profile_id])
507
- xml.tag!('customerPaymentProfileId', transaction[:customer_payment_profile_id])
508
- xml.tag!('approvalCode', transaction[:approval_code]) if transaction[:type] == :capture_only
602
+ case transaction[:type]
603
+ when :void
604
+ tag_unless_blank(xml,'customerProfileId', transaction[:customer_profile_id])
605
+ tag_unless_blank(xml,'customerPaymentProfileId', transaction[:customer_payment_profile_id])
606
+ tag_unless_blank(xml,'customerShippingAddressId', transaction[:customer_shipping_address_id])
607
+ xml.tag!('transId', transaction[:trans_id])
608
+ when :refund
609
+ #TODO - add support for all the other options fields
610
+ xml.tag!('amount', transaction[:amount])
611
+ tag_unless_blank(xml, 'customerProfileId', transaction[:customer_profile_id])
612
+ tag_unless_blank(xml, 'customerPaymentProfileId', transaction[:customer_payment_profile_id])
613
+ tag_unless_blank(xml, 'customerShippingAddressId', transaction[:customer_shipping_address_id])
614
+ tag_unless_blank(xml, 'creditCardNumberMasked', transaction[:credit_card_number_masked])
615
+ tag_unless_blank(xml, 'bankRoutingNumberMasked', transaction[:bank_routing_number_masked])
616
+ tag_unless_blank(xml, 'bankAccountNumberMasked', transaction[:bank_account_number_masked])
617
+ xml.tag!('transId', transaction[:trans_id])
618
+ when :prior_auth_capture
619
+ xml.tag!('amount', transaction[:amount])
620
+ xml.tag!('transId', transaction[:trans_id])
621
+ else
622
+ xml.tag!('amount', transaction[:amount])
623
+ xml.tag!('customerProfileId', transaction[:customer_profile_id])
624
+ xml.tag!('customerPaymentProfileId', transaction[:customer_payment_profile_id])
625
+ xml.tag!('approvalCode', transaction[:approval_code]) if transaction[:type] == :capture_only
626
+ end
509
627
  add_order(xml, transaction[:order]) if transaction[:order]
510
628
  end
511
629
  end
@@ -648,6 +766,10 @@ module ActiveMerchant #:nodoc:
648
766
  response
649
767
  end
650
768
 
769
+ def tag_unless_blank(xml, tag_name, data)
770
+ xml.tag!(tag_name, data) unless data.blank? || data.nil?
771
+ end
772
+
651
773
  def parse_direct_response(response)
652
774
  direct_response = {'raw' => response.params['direct_response']}
653
775
  direct_response_fields = response.params['direct_response'].split(',')
@@ -64,7 +64,7 @@ module ActiveMerchant #:nodoc:
64
64
  # code returned by ePDQ
65
65
  def credit(money, creditcard_or_authorization, options = {})
66
66
  if creditcard_or_authorization.is_a?(String)
67
- warn CREDIT_DEPRECATION_MESSAGE
67
+ deprecated CREDIT_DEPRECATION_MESSAGE
68
68
  refund(money, creditcard_or_authorization, options)
69
69
  else
70
70
  credit_new_order(money, creditcard_or_authorization, options)
@@ -12,12 +12,19 @@ module ActiveMerchant #:nodoc:
12
12
  # * +PA+ - Pre Authorization
13
13
  # * +PAC+ - Pre Authorization Completion
14
14
  #
15
+ # == Secure Payment Profiles:
16
+ # BeanStream supports payment profiles (vaults). This allows you to store cc information with BeanStream and process subsequent transactions with a customer id.
17
+ # Secure Payment Profiles must be enabled on your account (must be done over the phone).
18
+ # Your API Access Passcode must be set in Administration => account settings => order settings.
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
+ #
15
21
  # == Notes
16
22
  # * Recurring billing is not yet implemented.
17
23
  # * Adding of order products information is not implemented.
18
24
  # * Ensure that country and province data is provided as a code such as "CA", "US", "QC".
19
25
  # * 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.
20
26
  # * Test your app with your true merchant id and test credit card information provided in the api pdf document.
27
+ # * Beanstream does not allow Payment Profiles to be deleted with their API. The accounts are 'closed', but have to be deleted manually.
21
28
  #
22
29
  # Example authorization (Beanstream PA transaction type):
23
30
  #
@@ -58,11 +65,11 @@ module ActiveMerchant #:nodoc:
58
65
  class BeanstreamGateway < Gateway
59
66
  include BeanstreamCore
60
67
 
61
- def authorize(money, credit_card, options = {})
68
+ def authorize(money, source, options = {})
62
69
  post = {}
63
70
  add_amount(post, money)
64
71
  add_invoice(post, options)
65
- add_credit_card(post, credit_card)
72
+ add_source(post, source)
66
73
  add_address(post, options)
67
74
  add_transaction_type(post, :authorization)
68
75
  commit(post)
@@ -91,6 +98,36 @@ module ActiveMerchant #:nodoc:
91
98
  def interac
92
99
  @interac ||= BeanstreamInteracGateway.new(@options)
93
100
  end
101
+
102
+ # To match the other stored-value gateways, like TrustCommerce,
103
+ # store and unstore need to be defined
104
+ def store(credit_card, options = {})
105
+ post = {}
106
+ add_address(post, options)
107
+ add_credit_card(post, credit_card)
108
+ add_secure_profile_variables(post,options)
109
+ commit(post, true)
110
+ end
111
+
112
+ #can't actually delete a secure profile with the supplicaed API. This function sets the status of the profile to closed (C).
113
+ #Closed profiles will have to removed manually.
114
+ def delete(vault_id)
115
+ update(vault_id, false, {:status => "C"})
116
+ end
117
+
118
+ alias_method :unstore, :delete
119
+
120
+ # Update the values (such as CC expiration) stored at
121
+ # the gateway. The CC number must be supplied in the
122
+ # CreditCard object.
123
+ def update(vault_id, credit_card, options = {})
124
+ post = {}
125
+ add_address(post, options)
126
+ add_credit_card(post, credit_card)
127
+ options.merge!({:vault_id => vault_id, :operation => secure_profile_action(:modify)})
128
+ add_secure_profile_variables(post,options)
129
+ commit(post, true)
130
+ end
94
131
 
95
132
  private
96
133
  def build_response(*args)
@@ -2,17 +2,24 @@ module ActiveMerchant #:nodoc:
2
2
  module Billing #:nodoc:
3
3
  module BeanstreamCore
4
4
  URL = 'https://www.beanstream.com/scripts/process_transaction.asp'
5
+ SECURE_PROFILE_URL = 'https://www.beanstream.com/scripts/payment_profile.asp'
6
+ SP_SERVICE_VERSION = '1.1'
5
7
 
6
8
  TRANSACTIONS = {
7
9
  :authorization => 'PA',
8
10
  :purchase => 'P',
9
11
  :capture => 'PAC',
10
- :credit => 'R',
12
+ :refund => 'R',
11
13
  :void => 'VP',
12
14
  :check_purchase => 'D',
13
- :check_credit => 'C',
15
+ :check_refund => 'C',
14
16
  :void_purchase => 'VP',
15
- :void_credit => 'VR'
17
+ :void_refund => 'VR'
18
+ }
19
+
20
+ PROFILE_OPERATIONS = {
21
+ :new => 'N',
22
+ :modify => 'M'
16
23
  }
17
24
 
18
25
  CVD_CODES = {
@@ -48,7 +55,7 @@ module ActiveMerchant #:nodoc:
48
55
 
49
56
  # Only <tt>:login</tt> is required by default,
50
57
  # which is the merchant's merchant ID. If you'd like to perform void,
51
- # capture or credit transactions then you'll also need to add a username
58
+ # capture or refund transactions then you'll also need to add a username
52
59
  # and password to your account under administration -> account settings ->
53
60
  # order settings -> Use username/password validation
54
61
  def initialize(options = {})
@@ -67,26 +74,35 @@ module ActiveMerchant #:nodoc:
67
74
  commit(post)
68
75
  end
69
76
 
70
- def credit(money, source, options = {})
77
+ def refund(money, source, options = {})
71
78
  post = {}
72
79
  reference, amount, type = split_auth(source)
73
80
  add_reference(post, reference)
74
- add_transaction_type(post, credit_action(type))
81
+ add_transaction_type(post, refund_action(type))
75
82
  add_amount(post, money)
76
83
  commit(post)
77
84
  end
85
+
86
+ def credit(money, source, options = {})
87
+ deprecated CREDIT_DEPRECATION_MESSAGE
88
+ refund(money, source, options)
89
+ end
78
90
 
79
91
  private
80
92
  def purchase_action(source)
81
- card_brand(source) == "check" ? :check_purchase : :purchase
93
+ (card_brand(source) == "check") ? :check_purchase : :purchase
82
94
  end
83
95
 
84
96
  def void_action(original_transaction_type)
85
- original_transaction_type == TRANSACTIONS[:credit] ? :void_credit : :void_purchase
97
+ (original_transaction_type == TRANSACTIONS[:refund]) ? :void_refund : :void_purchase
98
+ end
99
+
100
+ def refund_action(type)
101
+ (type == TRANSACTIONS[:check_purchase]) ? :check_refund : :refund
86
102
  end
87
103
 
88
- def credit_action(type)
89
- type == TRANSACTIONS[:check_purchase] ? :check_credit : :credit
104
+ def secure_profile_action(type)
105
+ PROFILE_OPERATIONS[type] || PROFILE_OPERATIONS[:new]
90
106
  end
91
107
 
92
108
  def split_auth(string)
@@ -154,11 +170,13 @@ module ActiveMerchant #:nodoc:
154
170
  end
155
171
 
156
172
  def add_credit_card(post, credit_card)
157
- post[:trnCardOwner] = credit_card.name
158
- post[:trnCardNumber] = credit_card.number
159
- post[:trnExpMonth] = format(credit_card.month, :two_digits)
160
- post[:trnExpYear] = format(credit_card.year, :two_digits)
161
- post[:trnCardCvd] = credit_card.verification_value
173
+ if credit_card
174
+ post[:trnCardOwner] = credit_card.name
175
+ post[:trnCardNumber] = credit_card.number
176
+ post[:trnExpMonth] = format(credit_card.month, :two_digits)
177
+ post[:trnExpYear] = format(credit_card.year, :two_digits)
178
+ post[:trnCardCvd] = credit_card.verification_value
179
+ end
162
180
  end
163
181
 
164
182
  def add_check(post, check)
@@ -175,6 +193,16 @@ module ActiveMerchant #:nodoc:
175
193
  post[:accountNumber] = check.account_number
176
194
  end
177
195
 
196
+ def add_secure_profile_variables(post, options = {})
197
+ post[:serviceVersion] = SP_SERVICE_VERSION
198
+ post[:responseFormat] = 'QS'
199
+ post[:cardValidation] = (options[:cardValidation].to_i == 1) || '0'
200
+
201
+ post[:operationType] = options[:operationType] || options[:operation] || secure_profile_action(:new)
202
+ post[:customerCode] = options[:billing_id] || options[:vault_id] || false
203
+ post[:status] = options[:status]
204
+ end
205
+
178
206
  def parse(body)
179
207
  results = {}
180
208
  if !body.nil?
@@ -194,12 +222,13 @@ module ActiveMerchant #:nodoc:
194
222
  results
195
223
  end
196
224
 
197
- def commit(params)
198
- post(post_data(params))
225
+ def commit(params, use_profile_api = false)
226
+ post(post_data(params,use_profile_api),use_profile_api)
199
227
  end
200
228
 
201
- def post(data)
202
- response = parse(ssl_post(URL, data))
229
+ def post(data, use_profile_api=nil)
230
+ response = parse(ssl_post((use_profile_api ? SECURE_PROFILE_URL : URL), data))
231
+ response[:customer_vault_id] = response[:customerCode] if response[:customerCode]
203
232
  build_response(success?(response), message_from(response), response,
204
233
  :test => test? || response[:authCode] == "TEST",
205
234
  :authorization => authorization_from(response),
@@ -213,26 +242,35 @@ module ActiveMerchant #:nodoc:
213
242
  end
214
243
 
215
244
  def message_from(response)
216
- response[:messageText]
245
+ response[:messageText] || response[:responseMessage]
217
246
  end
218
247
 
219
248
  def success?(response)
220
- response[:responseType] == 'R' || response[:trnApproved] == '1'
249
+ response[:responseType] == 'R' || response[:trnApproved] == '1' || response[:responseCode] == '1'
221
250
  end
222
251
 
223
252
  def add_source(post, source)
224
- card_brand(source) == "check" ? add_check(post, source) : add_credit_card(post, source)
253
+ if source.is_a?(String) or source.is_a?(Integer)
254
+ post[:customerCode] = source
255
+ else
256
+ card_brand(source) == "check" ? add_check(post, source) : add_credit_card(post, source)
257
+ end
225
258
  end
226
259
 
227
260
  def add_transaction_type(post, action)
228
261
  post[:trnType] = TRANSACTIONS[action]
229
262
  end
230
263
 
231
- def post_data(params)
264
+ def post_data(params, use_profile_api)
232
265
  params[:requestType] = 'BACKEND'
233
- params[:merchant_id] = @options[:login]
234
- params[:username] = @options[:user] if @options[:user]
235
- params[:password] = @options[:password] if @options[:password]
266
+ if use_profile_api
267
+ params[:merchantId] = @options[:login]
268
+ params[:passCode] = @options[:secure_profile_api_key]
269
+ else
270
+ params[:username] = @options[:user] if @options[:user]
271
+ params[:password] = @options[:password] if @options[:password]
272
+ params[:merchant_id] = @options[:login]
273
+ end
236
274
  params[:vbvEnabled] = '0'
237
275
  params[:scEnabled] = '0'
238
276