activemerchant 1.13.0 → 1.14.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.
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