activemerchant 1.1.0 → 1.2.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 (178) hide show
  1. data.tar.gz.sig +0 -0
  2. data/CHANGELOG +226 -0
  3. data/CONTRIBUTERS +52 -0
  4. data/README +34 -24
  5. data/Rakefile +152 -0
  6. data/gem-public_cert.pem +20 -0
  7. data/init.rb +3 -0
  8. data/lib/active_merchant.rb +3 -1
  9. data/lib/active_merchant/billing/credit_card.rb +21 -17
  10. data/lib/active_merchant/billing/credit_card_methods.rb +17 -19
  11. data/lib/active_merchant/billing/gateway.rb +160 -44
  12. data/lib/active_merchant/billing/gateways.rb +2 -15
  13. data/lib/active_merchant/billing/gateways/authorize_net.rb +21 -21
  14. data/lib/active_merchant/billing/gateways/bogus.rb +6 -6
  15. data/lib/active_merchant/billing/gateways/brain_tree.rb +191 -0
  16. data/lib/active_merchant/billing/gateways/card_stream.rb +207 -0
  17. data/lib/active_merchant/billing/gateways/cyber_source.rb +402 -0
  18. data/lib/active_merchant/billing/gateways/data_cash.rb +41 -97
  19. data/lib/active_merchant/billing/gateways/efsnet.rb +256 -0
  20. data/lib/active_merchant/billing/gateways/eway.rb +77 -29
  21. data/lib/active_merchant/billing/gateways/exact.rb +230 -0
  22. data/lib/active_merchant/billing/gateways/linkpoint.rb +6 -33
  23. data/lib/active_merchant/billing/gateways/moneris.rb +155 -125
  24. data/lib/active_merchant/billing/gateways/net_registry.rb +257 -0
  25. data/lib/active_merchant/billing/gateways/pay_junction.rb +407 -0
  26. data/lib/active_merchant/billing/gateways/payflow.rb +163 -25
  27. data/lib/active_merchant/billing/gateways/payflow/payflow_common_api.rb +56 -38
  28. data/lib/active_merchant/billing/gateways/payflow/payflow_express_response.rb +10 -1
  29. data/lib/active_merchant/billing/gateways/payflow/payflow_response.rb +9 -0
  30. data/lib/active_merchant/billing/gateways/payflow_express.rb +36 -11
  31. data/lib/active_merchant/billing/gateways/payflow_express_uk.rb +6 -0
  32. data/lib/active_merchant/billing/gateways/payflow_uk.rb +7 -3
  33. data/lib/active_merchant/billing/gateways/payment_express.rb +261 -0
  34. data/lib/active_merchant/billing/gateways/paypal.rb +18 -4
  35. data/lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb +31 -15
  36. data/lib/active_merchant/billing/gateways/paypal/paypal_express_response.rb +8 -0
  37. data/lib/active_merchant/billing/gateways/paypal_express.rb +33 -8
  38. data/lib/active_merchant/billing/gateways/plugnpay.rb +300 -0
  39. data/lib/active_merchant/billing/gateways/protx.rb +285 -0
  40. data/lib/active_merchant/billing/gateways/psigate.rb +13 -12
  41. data/lib/active_merchant/billing/gateways/psl_card.rb +297 -0
  42. data/lib/active_merchant/billing/gateways/quickpay.rb +197 -0
  43. data/lib/active_merchant/billing/gateways/realex.rb +212 -0
  44. data/lib/active_merchant/billing/gateways/secure_pay.rb +31 -0
  45. data/lib/active_merchant/billing/gateways/trans_first.rb +136 -0
  46. data/lib/active_merchant/billing/gateways/trust_commerce.rb +43 -20
  47. data/lib/active_merchant/billing/gateways/usa_epay.rb +6 -5
  48. data/lib/active_merchant/billing/gateways/verifi.rb +235 -0
  49. data/lib/active_merchant/billing/gateways/viaklix.rb +171 -0
  50. data/lib/active_merchant/billing/integrations/gestpay/helper.rb +0 -2
  51. data/lib/active_merchant/billing/integrations/helper.rb +8 -1
  52. data/lib/active_merchant/billing/integrations/nochex.rb +62 -1
  53. data/lib/active_merchant/billing/integrations/nochex/notification.rb +9 -16
  54. data/lib/active_merchant/billing/integrations/notification.rb +1 -1
  55. data/lib/active_merchant/billing/integrations/paypal/helper.rb +59 -46
  56. data/lib/active_merchant/billing/integrations/paypal/notification.rb +14 -47
  57. data/lib/active_merchant/lib/error.rb +4 -0
  58. data/lib/active_merchant/lib/post_data.rb +22 -0
  59. data/lib/active_merchant/lib/posts_data.rb +23 -5
  60. data/lib/active_merchant/lib/requires_parameters.rb +2 -2
  61. data/lib/active_merchant/lib/validateable.rb +1 -1
  62. data/lib/support/gateway_support.rb +45 -0
  63. data/lib/tasks/cia.rb +1 -1
  64. data/script/generate +14 -0
  65. data/script/generator/base.rb +45 -0
  66. data/script/generator/generator.rb +24 -0
  67. data/script/generator/generators/gateway/gateway_generator.rb +14 -0
  68. data/script/generator/generators/gateway/templates/gateway.rb +73 -0
  69. data/script/generator/generators/gateway/templates/gateway_test.rb +41 -0
  70. data/script/generator/generators/gateway/templates/remote_gateway_test.rb +56 -0
  71. data/script/generator/generators/integration/integration_generator.rb +25 -0
  72. data/script/generator/generators/integration/templates/helper.rb +34 -0
  73. data/script/generator/generators/integration/templates/helper_test.rb +54 -0
  74. data/script/generator/generators/integration/templates/integration.rb +18 -0
  75. data/script/generator/generators/integration/templates/module_test.rb +9 -0
  76. data/script/generator/generators/integration/templates/notification.rb +100 -0
  77. data/script/generator/generators/integration/templates/notification_test.rb +41 -0
  78. data/script/generator/manifest.rb +20 -0
  79. data/test/extra/binding_of_caller.rb +80 -0
  80. data/test/extra/breakpoint.rb +547 -0
  81. data/test/fixtures.yml +251 -0
  82. data/test/remote_tests/remote_authorize_net_test.rb +113 -0
  83. data/test/remote_tests/remote_brain_tree_test.rb +78 -0
  84. data/test/remote_tests/remote_card_stream_test.rb +160 -0
  85. data/test/remote_tests/remote_cyber_source_test.rb +130 -0
  86. data/test/remote_tests/remote_data_cash_test.rb +155 -0
  87. data/test/remote_tests/remote_efsnet_test.rb +93 -0
  88. data/test/remote_tests/remote_eway_test.rb +71 -0
  89. data/test/remote_tests/remote_exact_test.rb +59 -0
  90. data/test/remote_tests/remote_gestpay_integration_test.rb +37 -0
  91. data/test/remote_tests/remote_linkpoint_test.rb +144 -0
  92. data/test/remote_tests/remote_moneris_test.rb +110 -0
  93. data/test/remote_tests/remote_net_registry_test.rb +120 -0
  94. data/test/remote_tests/remote_pay_junction_test.rb +162 -0
  95. data/test/remote_tests/remote_payflow_express_test.rb +50 -0
  96. data/test/remote_tests/remote_payflow_test.rb +241 -0
  97. data/test/remote_tests/remote_payflow_uk_test.rb +172 -0
  98. data/test/remote_tests/remote_payment_express_test.rb +136 -0
  99. data/test/remote_tests/remote_paypal_express_test.rb +49 -0
  100. data/test/remote_tests/remote_paypal_integration_test.rb +14 -0
  101. data/test/remote_tests/remote_paypal_test.rb +163 -0
  102. data/test/remote_tests/remote_plugnpay_test.rb +70 -0
  103. data/test/remote_tests/remote_protx_test.rb +184 -0
  104. data/test/remote_tests/remote_psigate_test.rb +87 -0
  105. data/test/remote_tests/remote_psl_card_test.rb +105 -0
  106. data/test/remote_tests/remote_quickpay_test.rb +182 -0
  107. data/test/remote_tests/remote_realex_test.rb +227 -0
  108. data/test/remote_tests/remote_secure_pay_test.rb +36 -0
  109. data/test/remote_tests/remote_trans_first_test.rb +37 -0
  110. data/test/remote_tests/remote_trust_commerce_test.rb +136 -0
  111. data/test/remote_tests/remote_usa_epay_test.rb +57 -0
  112. data/test/remote_tests/remote_verifi_test.rb +107 -0
  113. data/test/remote_tests/remote_viaklix_test.rb +53 -0
  114. data/test/test_helper.rb +132 -0
  115. data/test/unit/base_test.rb +61 -0
  116. data/test/unit/country_code_test.rb +33 -0
  117. data/test/unit/country_test.rb +64 -0
  118. data/test/unit/credit_card_formatting_test.rb +24 -0
  119. data/test/unit/credit_card_methods_test.rb +37 -0
  120. data/test/unit/credit_card_test.rb +365 -0
  121. data/test/unit/gateways/authorize_net_test.rb +140 -0
  122. data/test/unit/gateways/bogus_test.rb +43 -0
  123. data/test/unit/gateways/brain_tree_test.rb +77 -0
  124. data/test/unit/gateways/card_stream_test.rb +37 -0
  125. data/test/unit/gateways/cyber_source_test.rb +151 -0
  126. data/test/unit/gateways/data_cash_test.rb +23 -0
  127. data/test/unit/gateways/efsnet_test.rb +70 -0
  128. data/test/unit/gateways/eway_test.rb +105 -0
  129. data/test/unit/gateways/exact_test.rb +118 -0
  130. data/test/unit/gateways/gateway_test.rb +24 -0
  131. data/test/unit/gateways/linkpoint_test.rb +165 -0
  132. data/test/unit/gateways/moneris_test.rb +167 -0
  133. data/test/unit/gateways/net_registry_test.rb +478 -0
  134. data/test/unit/gateways/pay_junction_test.rb +61 -0
  135. data/test/unit/gateways/payflow_express_test.rb +165 -0
  136. data/test/unit/gateways/payflow_express_uk_test.rb +14 -0
  137. data/test/unit/gateways/payflow_test.rb +230 -0
  138. data/test/unit/gateways/payflow_uk_test.rb +68 -0
  139. data/test/unit/gateways/payment_express_test.rb +215 -0
  140. data/test/unit/gateways/paypal_express_test.rb +222 -0
  141. data/test/unit/gateways/paypal_test.rb +241 -0
  142. data/test/unit/gateways/plugnpay_test.rb +79 -0
  143. data/test/unit/gateways/protx_test.rb +110 -0
  144. data/test/unit/gateways/psigate_test.rb +110 -0
  145. data/test/unit/gateways/psl_card_test.rb +51 -0
  146. data/test/unit/gateways/quickpay_test.rb +125 -0
  147. data/test/unit/gateways/realex_test.rb +150 -0
  148. data/test/unit/gateways/secure_pay_test.rb +78 -0
  149. data/test/unit/gateways/trans_first_test.rb +125 -0
  150. data/test/unit/gateways/trust_commerce_test.rb +57 -0
  151. data/test/unit/gateways/usa_epay_test.rb +117 -0
  152. data/test/unit/gateways/verifi_test.rb +91 -0
  153. data/test/unit/gateways/viaklix_test.rb +72 -0
  154. data/test/unit/integrations/action_view_helper_test.rb +54 -0
  155. data/test/unit/integrations/bogus_module_test.rb +16 -0
  156. data/test/unit/integrations/chronopay_module_test.rb +9 -0
  157. data/test/unit/integrations/gestpay_module_test.rb +10 -0
  158. data/test/unit/integrations/helpers/bogus_helper_test.rb +28 -0
  159. data/test/unit/integrations/helpers/chronopay_helper_test.rb +67 -0
  160. data/test/unit/integrations/helpers/gestpay_helper_test.rb +100 -0
  161. data/test/unit/integrations/helpers/nochex_helper_test.rb +53 -0
  162. data/test/unit/integrations/helpers/paypal_helper_test.rb +162 -0
  163. data/test/unit/integrations/helpers/two_checkout_helper_test.rb +92 -0
  164. data/test/unit/integrations/nochex_module_test.rb +9 -0
  165. data/test/unit/integrations/notifications/chronopay_notification_test.rb +66 -0
  166. data/test/unit/integrations/notifications/gestpay_notification_test.rb +60 -0
  167. data/test/unit/integrations/notifications/nochex_notification_test.rb +51 -0
  168. data/test/unit/integrations/notifications/notification_test.rb +41 -0
  169. data/test/unit/integrations/notifications/paypal_notification_test.rb +85 -0
  170. data/test/unit/integrations/notifications/two_checkout_notification_test.rb +55 -0
  171. data/test/unit/integrations/paypal_module_test.rb +24 -0
  172. data/test/unit/integrations/two_checkout_module_test.rb +9 -0
  173. data/test/unit/post_data_test.rb +55 -0
  174. data/test/unit/response_test.rb +14 -0
  175. data/test/unit/validateable_test.rb +56 -0
  176. metadata +160 -7
  177. metadata.gz.sig +0 -0
  178. data/lib/active_merchant/billing/gateways/payflow/f73e89fd.0 +0 -17
@@ -2,13 +2,20 @@
2
2
 
3
3
  module ActiveMerchant
4
4
  module Billing
5
- # ActiveMerchant Datacash Gateway
6
- #
7
- # Datacash allows a policy for CV2 checks. There is currently no way
8
- # to modify this programatically. The policy may be changed in the
9
- # add_credit_card method.
10
- #
11
5
  class DataCashGateway < Gateway
6
+ self.default_currency = 'GBP'
7
+ self.supported_countries = ['GB']
8
+
9
+ # From the DataCash docs; Page 13, the following cards are
10
+ # usable:
11
+ # American Express, ATM, Carte Blanche, Diners Club, Discover,
12
+ # EnRoute, GE Capital, JCB, Laser, Maestro, Mastercard, Solo,
13
+ # Switch, Visa, Visa Delta, VISA Electron, Visa Purchasing
14
+ self.supported_cardtypes = [ :visa, :master, :american_express, :discover, :diners_club, :jcb,
15
+ :maestro, :switch, :solo, :laser ]
16
+
17
+ self.homepage_url = 'http://www.datacash.com/'
18
+ self.display_name = 'DataCash'
12
19
 
13
20
  # Datacash server URLs
14
21
  TEST_URL = 'https://testserver.datacash.com/Transaction'
@@ -25,7 +32,7 @@ module ActiveMerchant
25
32
  POLICY_ACCEPT = 'accept'
26
33
  POLICY_REJECT = 'reject'
27
34
 
28
- #Datacash success code
35
+ # Datacash success code
29
36
  DATACASH_SUCCESS = '1'
30
37
 
31
38
  # Class attributes
@@ -33,16 +40,16 @@ module ActiveMerchant
33
40
  attr_reader :response
34
41
  attr_reader :options
35
42
 
36
- # Create a new DataCashGateway
43
+ # Creates a new DataCashGateway
37
44
  #
38
- # The gateway requires that a valid :login and :password be passed
39
- # in the options hash
45
+ # The gateway requires that a valid login and password be passed
46
+ # in the +options+ hash.
40
47
  #
41
- # Parameters:
42
- # -options:
43
- # :login - the Datacash account login
44
- # :password - the Datacash account password
45
- # :test - boolean, use the test or live Datacash url
48
+ # ==== Options
49
+ #
50
+ # * <tt>:login</tt> -- The Datacash account login.
51
+ # * <tt>:password</tt> -- The Datacash account password.
52
+ # * <tt>:test => +true+ or +false+</tt> -- Use the test or live Datacash url.
46
53
  #
47
54
  def initialize(options = {})
48
55
  requires!(options, :login, :password)
@@ -50,16 +57,13 @@ module ActiveMerchant
50
57
  super
51
58
  end
52
59
 
53
- # Purchase the item straight away
60
+ # Perform a purchase, which is essentially an authorization and capture in a single operation.
54
61
  #
55
- # Parameters:
56
- # -money: Money object for the total to be charged
57
- # -credit_card: ActiveMerchant::Billing::CreditCard details for the transaction
58
- # -options:
62
+ # ==== Parameters
59
63
  #
60
- # Returns:
61
- # -ActiveRecord::Billing::Response object
62
- #
64
+ # * <tt>money</tt> -- The amount to be purchased. Either an Integer value in cents or a Money object.
65
+ # * <tt>credit_card</tt> -- The CreditCard details for the transaction.
66
+ # * <tt>options</tt> -- A hash of optional parameters.
63
67
  def purchase(money, credit_card, options = {})
64
68
  if result = test_result_from_cc_number(credit_card.number)
65
69
  return result
@@ -70,19 +74,14 @@ module ActiveMerchant
70
74
  commit(request)
71
75
  end
72
76
 
73
- # Authorize the transaction
74
- #
75
- # Reserves the funds on the customer's credit card, but does not
77
+ # Performs an authorization, which reserves the funds on the customer's credit card, but does not
76
78
  # charge the card.
77
79
  #
78
- # Parameters:
79
- # -money: Money object for the total to be charged
80
- # -credit_card: ActiveMerchant::Billing::CreditCard details for the transaction
81
- # -options:
80
+ # ==== Parameters
82
81
  #
83
- # Returns:
84
- # -ActiveRecord::Billing::Response object
85
- #
82
+ # * <tt>money</tt> -- The amount to be authorized. Either an Integer value in cents or a Money object.
83
+ # * <tt>credit_card</tt> -- The CreditCard details for the transaction.
84
+ # * <tt>options</tt> -- A hash of optional parameters.
86
85
  def authorize(money, credit_card, options = {})
87
86
  if result = test_result_from_cc_number(credit_card.number)
88
87
  return result
@@ -93,24 +92,12 @@ module ActiveMerchant
93
92
  commit(request)
94
93
  end
95
94
 
96
- # Datacash requires both the reference and the authcode of the original
97
- # authorization. To maintain the same interface as the other
98
- # gateways the two numbers are concatenated together with an ; separator as
99
- # the authorization number returned by authorization
100
-
101
- # Captures the funds from an authorized transaction.
102
- # authorization must be a valid Datacash reference and :authcode must be
103
- # a valid Datacash authcode from a prior authorized transaction.
95
+ # Captures the funds from an authorized transaction.
104
96
  #
105
- # This needs to create a 'historic txn' to fulfill
106
- #
107
- # Parameters:
108
- # -money: Money object for the total to be charged
109
- # -authorization: the Datacash reference and authcode from the previous authorization
97
+ # ==== Parameters
110
98
  #
111
- # Returns:
112
- # -ActiveRecord::Billing::Response object
113
- #
99
+ # * <tt>money</tt> -- The amount to be captured. Either an Integer value in cents or a Money object.
100
+ # * <tt>authorization</tt> -- The authorization returned from the previous authorize request.
114
101
  def capture(money, authorization, options = {})
115
102
  request = build_void_or_capture_request(FULFILL_TYPE, money, authorization, options)
116
103
 
@@ -119,46 +106,16 @@ module ActiveMerchant
119
106
 
120
107
  # Void a previous transaction
121
108
  #
122
- # This needs to create a 'historic txn' to fulfil
123
- #
124
- # Parameters:
125
- # -authorization: the Datacash reference from the previous authorization
109
+ # ==== Parameters
126
110
  #
127
- # Returns:
128
- # -ActiveRecord::Billing::Response object
129
- #
111
+ # * <tt>authorization</tt> - The authorization returned from the previous authorize request.
130
112
  def void(authorization, options = {})
131
113
  request = build_void_or_capture_request(CANCEL_TYPE, nil, authorization, options)
132
114
 
133
115
  commit(request)
134
116
  end
135
117
 
136
- # From the DataCash docs; Page 13, the following cards are
137
- # usable
138
- #
139
- # American Express, ATM, Carte Blanche, Diners Club, Discover,
140
- # EnRoute, GE Capital, JCB, Laser, Maestro, Mastercard, Solo,
141
- # Switch, Unknown, Visa, Visa Delta, VISA Electron, Visa Purchasing
142
- #
143
- # Parameters:
144
- # -none
145
- #
146
- # Returns:
147
- # -the list of all supported cards
148
- #
149
- def self.supported_cardtypes
150
- [ :visa, :master, :american_express, :discover, :diners_club, :jcb,
151
- :switch, :solo ]
152
- end
153
-
154
- # Return whether or not the gateway is in test mode
155
- #
156
- # Parameters:
157
- # -none
158
- #
159
- # Returns:
160
- # -boolean
161
- #
118
+ # Is the gateway running in test mode?
162
119
  def test?
163
120
  @options[:test] || Base.gateway_mode == :test
164
121
  end
@@ -213,7 +170,7 @@ module ActiveMerchant
213
170
  if money
214
171
  xml.tag! :TxnDetails do
215
172
  xml.tag! :merchantreference, format_reference_number(options[:order_id])
216
- xml.tag! :amount, amount(money), :currency => currency(money)
173
+ xml.tag! :amount, amount(money), :currency => options[:currency] || currency(money)
217
174
  end
218
175
  end
219
176
  end
@@ -296,7 +253,7 @@ module ActiveMerchant
296
253
  end
297
254
  xml.tag! :TxnDetails do
298
255
  xml.tag! :merchantreference, format_reference_number(options[:order_id])
299
- xml.tag! :amount, amount(money), :currency => currency(money)
256
+ xml.tag! :amount, amount(money), :currency => options[:currency] || currency(money)
300
257
  end
301
258
  end
302
259
  end
@@ -404,19 +361,6 @@ module ActiveMerchant
404
361
  )
405
362
  end
406
363
 
407
- # Find the currency of the Money object passed
408
- #
409
- # Parameters:
410
- # -money: The money object that we are looking at
411
- #
412
- # Returns:
413
- # -string: The three digit currency code (These are
414
- # ISO 4217 codes)
415
- #
416
- def currency(money)
417
- money.respond_to?(:currency) ? money.currency : 'GBP'
418
- end
419
-
420
364
  # Returns a date string in the format Datacash expects
421
365
  #
422
366
  # Parameters:
@@ -0,0 +1,256 @@
1
+ require 'rexml/document'
2
+
3
+ module ActiveMerchant #:nodoc:
4
+ module Billing #:nodoc:
5
+
6
+ class EfsnetGateway < Gateway
7
+ attr_reader :url
8
+ attr_reader :response
9
+ attr_reader :options
10
+
11
+ self.supported_countries = ['US']
12
+ self.supported_cardtypes = [:visa, :master, :american_express, :discover]
13
+ self.homepage_url = 'http://www.concordefsnet.com/'
14
+ self.display_name = 'Efsnet'
15
+
16
+ TEST_URL = 'https://testefsnet.concordebiz.com/efsnet.dll'
17
+ LIVE_URL = 'https://efsnet.concordebiz.com/efsnet.dll'
18
+
19
+ # login is your Store ID
20
+ # password is your Store Key
21
+ def initialize(options = {})
22
+ requires!(options, :login, :password)
23
+
24
+ @options = options
25
+ @url = test? ? TEST_URL : LIVE_URL
26
+
27
+ super
28
+ end
29
+
30
+ def test?
31
+ @options[:test] || Base.gateway_mode == :test
32
+ end
33
+
34
+ def authorize(money, creditcard, options = {})
35
+ request = build_credit_card_request(money, creditcard, options)
36
+ commit(:credit_card_authorize, request)
37
+ end
38
+
39
+ def purchase(money, creditcard, options = {})
40
+ request = build_credit_card_request(money, creditcard, options)
41
+ commit(:credit_card_charge, request)
42
+ end
43
+
44
+ def capture(money, identification, options = {})
45
+ request = build_refund_or_settle_request(money, identification, options)
46
+ commit(:credit_card_settle, request)
47
+ end
48
+
49
+ def credit(money, identification_or_credit_card, options = {})
50
+ if identification_or_credit_card.is_a?(String)
51
+ # Perform authorization reversal
52
+ request = build_refund_or_settle_request(money, identification_or_credit_card, options)
53
+ commit(:credit_card_refund, request)
54
+ else
55
+ # Perform credit
56
+ request = build_credit_card_request(money, identification_or_credit_card, options)
57
+ commit(:credit_card_credit, request)
58
+ end
59
+ end
60
+
61
+ def void(identification, options = {})
62
+ requires!(options, :order_id)
63
+ original_transaction_id, original_transaction_amount = identification.split(";")
64
+ commit(:void_transaction, {:reference_number => options[:order_id], :transaction_ID => original_transaction_id})
65
+ end
66
+
67
+ def voice_authorize(money, authorization_code, creditcard, options = {})
68
+ options[:authorization_number] = authorization_code
69
+ request = build_credit_card_request(money, creditcard, options)
70
+ commit(:credit_card_voice_authorize, request)
71
+ end
72
+
73
+ def force(money, authorization_code, creditcard, options = {})
74
+ options[:authorization_number] = authorization_code
75
+ request = build_credit_card_request(money, creditcard, options)
76
+ commit(:credit_card_capture, request)
77
+ end
78
+
79
+ def system_check
80
+ commit(:system_check, {})
81
+ end
82
+
83
+ private
84
+
85
+ def build_refund_or_settle_request(money, identification, options = {})
86
+ original_transaction_id, original_transaction_amount = identification.split(";")
87
+
88
+ requires!(options, :order_id)
89
+
90
+ post = {
91
+ :reference_number => options[:order_id],
92
+ :transaction_amount => amount(money),
93
+ :original_transaction_amount => original_transaction_amount,
94
+ :original_transaction_ID => original_transaction_id,
95
+ :client_ip_address => options[:ip]
96
+ }
97
+ end
98
+
99
+ def build_credit_card_request(money, creditcard, options = {})
100
+ requires!(options, :order_id)
101
+
102
+ post = {
103
+ :reference_number => options[:order_id],
104
+ :authorization_number => options[:authorization_number],
105
+ :transaction_amount => amount(money),
106
+ :client_ip_address => options[:ip]
107
+
108
+ }
109
+ add_creditcard(post,creditcard)
110
+ add_address(post,options)
111
+ post
112
+ end
113
+
114
+ def add_address(post,options)
115
+ if address = options[:billing_address] || options[:address]
116
+ if address[:address2]
117
+ post[:billing_address] = address[:address1].to_s << ' ' << address[:address2].to_s
118
+ else
119
+ post[:billing_address] = address[:address1].to_s
120
+ end
121
+ post[:billing_city] = address[:city].to_s
122
+ post[:billing_state] = address[:state].blank? ? 'n/a' : address[:state]
123
+ post[:billing_postal_code] = address[:zip].to_s
124
+ post[:billing_country] = address[:country].to_s
125
+ end
126
+
127
+ if address = options[:shipping_address]
128
+ if address[:address2]
129
+ post[:shipping_address] = address[:address1].to_s << ' ' << address[:address2].to_s
130
+ else
131
+ post[:shipping_address] = address[:address1].to_s
132
+ end
133
+ post[:shipping_city] = address[:city].to_s
134
+ post[:shipping_state] = address[:state].blank? ? 'n/a' : address[:state]
135
+ post[:shipping_postal_code] = address[:zip].to_s
136
+ post[:shipping_country] = address[:country].to_s
137
+ end
138
+ end
139
+
140
+ def add_creditcard(post, creditcard)
141
+ post[:billing_name] = creditcard.name if creditcard.name
142
+ post[:account_number] = creditcard.number
143
+ post[:card_verification_value] = creditcard.verification_value if creditcard.verification_value?
144
+ post[:expiration_month] = sprintf("%.2i", creditcard.month)
145
+ post[:expiration_year] = sprintf("%.4i", creditcard.year)[-2..-1]
146
+ end
147
+
148
+
149
+ def commit(action, parameters)
150
+ if result = test_result_from_cc_number(parameters[:account_number])
151
+ return result
152
+ end
153
+
154
+ parameters.delete_if {|key,value| value.blank?}
155
+
156
+ headers = { 'Content-Type' => 'text/xml' }
157
+ data = ssl_post @url, post_data(action, parameters), headers
158
+
159
+ @response = parse(data)
160
+
161
+ success = (response[:response_code] and response[:response_code] == '0')
162
+ message = message_form(response[:result_message])
163
+
164
+ authorization = [ response[:transaction_id], parameters[:transaction_amount] ].compact.join(';')
165
+
166
+ Response.new(success, message, @response,
167
+ :test => test?,
168
+ :authorization => authorization
169
+ )
170
+ end
171
+
172
+ # Parse response xml into a convinient hash
173
+ def parse(xml)
174
+ #<Reply>
175
+ #<TransactionReply>
176
+ #<ResponseCode>0</ResponseCode>
177
+ #<ResultCode>00</ResultCode>
178
+ #<ResultMessage>APPROVED</ResultMessage>
179
+ #<TransactionID>200011125443</TransactionID>
180
+ #<AVSResponseCode>N</AVSResponseCode>
181
+ #<CVVResponseCode></CVVResponseCode>
182
+ #<ApprovalNumber>123456</ApprovalNumber>
183
+ #<AuthorizationNumber>123456</AuthorizationNumber>
184
+ #<TransactionDate>070728</TransactionDate>
185
+ #<TransactionTime>024734</TransactionTime>
186
+ #<ReferenceNumber>19786</ReferenceNumber>
187
+ #<AccountNumber>XXXXXXXXXXXX5454</AccountNumber>
188
+ #<TransactionAmount>1.00</TransactionAmount>
189
+ #</TransactionReply>
190
+ #</Reply>
191
+
192
+ response = {}
193
+
194
+ xml = REXML::Document.new(xml)
195
+
196
+ xml.elements.each('//Reply//TransactionReply/*') do |node|
197
+
198
+ response[node.name.underscore.to_sym] = normalize(node.text)
199
+
200
+ end unless xml.root.nil?
201
+
202
+ response
203
+ end
204
+
205
+ def post_data(action, parameters = {})
206
+ xml = REXML::Document.new("<?xml version='1.0' encoding='UTF-8'?>")
207
+ root = xml.add_element("Request")
208
+ root.attributes["StoreID"] = options[:login]
209
+ root.attributes["StoreKey"] = options[:password]
210
+ root.attributes["ApplicationID"] = 'ot 1.0'
211
+ transaction = root.add_element(action.to_s.camelize)
212
+
213
+ actions[action].each do |key|
214
+ transaction.add_element(key.to_s.camelize).text = parameters[key] unless parameters[key].blank?
215
+ end
216
+
217
+ xml.to_s
218
+ end
219
+
220
+ def message_form(message)
221
+ return 'Unspecified error' if message.blank?
222
+ message.gsub(/[^\w]/, ' ').split.join(" ").capitalize
223
+ end
224
+
225
+ # Make a ruby type out of the response string
226
+ def normalize(field)
227
+ case field
228
+ when "true" then true
229
+ when "false" then false
230
+ when "" then nil
231
+ when "null" then nil
232
+ else field
233
+ end
234
+ end
235
+
236
+ def actions
237
+ ACTIONS
238
+ end
239
+
240
+
241
+ CREDIT_CARD_FIELDS = [:authorization_number, :client_ip_address, :billing_address, :billing_city, :billing_state, :billing_postal_code, :billing_country, :billing_name, :card_verification_value, :expiration_month, :expiration_year, :reference_number, :transaction_amount, :account_number ]
242
+
243
+ ACTIONS = {
244
+ :credit_card_authorize => CREDIT_CARD_FIELDS,
245
+ :credit_card_charge => CREDIT_CARD_FIELDS,
246
+ :credit_card_voice_authorize => CREDIT_CARD_FIELDS,
247
+ :credit_card_capture => CREDIT_CARD_FIELDS,
248
+ :credit_card_credit => CREDIT_CARD_FIELDS << :original_transaction_amount,
249
+ :credit_card_refund => [:reference_number, :transaction_amount, :original_transaction_amount, :original_transaction_ID, :client_ip_address],
250
+ :void_transaction => [:reference_number, :transaction_ID],
251
+ :credit_card_settle => [:reference_number, :transaction_amount, :original_transaction_amount, :original_transaction_ID, :client_ip_address],
252
+ :system_check => [:system_check],
253
+ }
254
+ end
255
+ end
256
+ end