yetanothernguyen-activemerchant 1.16.0 → 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.
Files changed (86) hide show
  1. data/CHANGELOG +95 -0
  2. data/CONTRIBUTORS +29 -0
  3. data/lib/active_merchant/billing/credit_card.rb +105 -19
  4. data/lib/active_merchant/billing/credit_card_methods.rb +5 -1
  5. data/lib/active_merchant/billing/gateway.rb +1 -1
  6. data/lib/active_merchant/billing/gateways/authorize_net.rb +24 -2
  7. data/lib/active_merchant/billing/gateways/authorize_net_cim.rb +104 -18
  8. data/lib/active_merchant/billing/gateways/beanstream/beanstream_core.rb +110 -4
  9. data/lib/active_merchant/billing/gateways/beanstream.rb +29 -1
  10. data/lib/active_merchant/billing/gateways/braintree_blue.rb +9 -4
  11. data/lib/active_merchant/billing/gateways/braintree_orange.rb +4 -0
  12. data/lib/active_merchant/billing/gateways/card_save.rb +23 -0
  13. data/lib/active_merchant/billing/gateways/certo_direct.rb +279 -0
  14. data/lib/active_merchant/billing/gateways/efsnet.rb +9 -9
  15. data/lib/active_merchant/billing/gateways/elavon.rb +2 -1
  16. data/lib/active_merchant/billing/gateways/epay.rb +12 -6
  17. data/lib/active_merchant/billing/gateways/eway_managed.rb +46 -12
  18. data/lib/active_merchant/billing/gateways/exact.rb +5 -0
  19. data/lib/active_merchant/billing/gateways/ideal/ideal_base.rb +3 -3
  20. data/lib/active_merchant/billing/gateways/ipay88.rb +157 -0
  21. data/lib/active_merchant/billing/gateways/iridium.rb +3 -3
  22. data/lib/active_merchant/billing/gateways/itransact.rb +450 -0
  23. data/lib/active_merchant/billing/gateways/merchant_e_solutions.rb +1 -0
  24. data/lib/active_merchant/billing/gateways/moneris.rb +4 -0
  25. data/lib/active_merchant/billing/gateways/nab_transact.rb +244 -0
  26. data/lib/active_merchant/billing/gateways/ogone.rb +94 -56
  27. data/lib/active_merchant/billing/gateways/optimal_payment.rb +277 -0
  28. data/lib/active_merchant/billing/gateways/orbital.rb +57 -34
  29. data/lib/active_merchant/billing/gateways/pay_junction.rb +6 -1
  30. data/lib/active_merchant/billing/gateways/payflow/payflow_common_api.rb +1 -0
  31. data/lib/active_merchant/billing/gateways/payflow/payflow_express_response.rb +2 -2
  32. data/lib/active_merchant/billing/gateways/payflow.rb +10 -2
  33. data/lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb +8 -5
  34. data/lib/active_merchant/billing/gateways/paypal_digital_goods.rb +43 -0
  35. data/lib/active_merchant/billing/gateways/paypal_express.rb +93 -40
  36. data/lib/active_merchant/billing/gateways/paypal_express_common.rb +8 -3
  37. data/lib/active_merchant/billing/gateways/qbms.rb +4 -0
  38. data/lib/active_merchant/billing/gateways/quickpay.rb +97 -22
  39. data/lib/active_merchant/billing/gateways/realex.rb +5 -1
  40. data/lib/active_merchant/billing/gateways/samurai.rb +121 -0
  41. data/lib/active_merchant/billing/gateways/secure_pay_au.rb +136 -49
  42. data/lib/active_merchant/billing/gateways/secure_pay_tech.rb +1 -1
  43. data/lib/active_merchant/billing/gateways/skip_jack.rb +7 -2
  44. data/lib/active_merchant/billing/gateways/stripe.rb +51 -19
  45. data/lib/active_merchant/billing/gateways/usa_epay.rb +13 -184
  46. data/lib/active_merchant/billing/gateways/usa_epay_advanced.rb +1496 -0
  47. data/lib/active_merchant/billing/gateways/usa_epay_transaction.rb +206 -0
  48. data/lib/active_merchant/billing/gateways/verifi.rb +2 -2
  49. data/lib/active_merchant/billing/gateways/viaklix.rb +1 -1
  50. data/lib/active_merchant/billing/gateways/worldpay.rb +1 -1
  51. data/lib/active_merchant/billing/integrations/action_view_helper.rb +6 -2
  52. data/lib/active_merchant/billing/integrations/authorize_net_sim/helper.rb +228 -0
  53. data/lib/active_merchant/billing/integrations/authorize_net_sim/notification.rb +340 -0
  54. data/lib/active_merchant/billing/integrations/authorize_net_sim.rb +38 -0
  55. data/lib/active_merchant/billing/integrations/direc_pay/helper.rb +4 -4
  56. data/lib/active_merchant/billing/integrations/dwolla/helper.rb +31 -0
  57. data/lib/active_merchant/billing/integrations/dwolla/notification.rb +55 -0
  58. data/lib/active_merchant/billing/integrations/dwolla/return.rb +38 -0
  59. data/lib/active_merchant/billing/integrations/dwolla.rb +30 -0
  60. data/lib/active_merchant/billing/integrations/helper.rb +19 -2
  61. data/lib/active_merchant/billing/integrations/ipay88/helper.rb +120 -0
  62. data/lib/active_merchant/billing/integrations/ipay88/return.rb +121 -0
  63. data/lib/active_merchant/billing/integrations/ipay88.rb +40 -0
  64. data/lib/active_merchant/billing/integrations/nochex.rb +1 -1
  65. data/lib/active_merchant/billing/integrations/payflow_link/helper.rb +100 -0
  66. data/lib/active_merchant/billing/integrations/payflow_link/notification.rb +78 -0
  67. data/lib/active_merchant/billing/integrations/payflow_link.rb +21 -0
  68. data/lib/active_merchant/billing/integrations/sage_pay_form/encryption.rb +4 -4
  69. data/lib/active_merchant/billing/integrations/sage_pay_form/helper.rb +18 -2
  70. data/lib/active_merchant/billing/integrations/two_checkout.rb +1 -2
  71. data/lib/active_merchant/railtie.rb +7 -7
  72. data/lib/active_merchant/railtie.rb.orig +19 -0
  73. data/lib/active_merchant/version.rb +1 -1
  74. data/lib/active_merchant.rb +23 -10
  75. data/lib/active_merchant.rb.orig +78 -0
  76. metadata +147 -63
  77. data/lib/active_merchant/common/connection.rb +0 -177
  78. data/lib/active_merchant/common/country.rb +0 -328
  79. data/lib/active_merchant/common/error.rb +0 -26
  80. data/lib/active_merchant/common/post_data.rb +0 -24
  81. data/lib/active_merchant/common/posts_data.rb +0 -63
  82. data/lib/active_merchant/common/requires_parameters.rb +0 -16
  83. data/lib/active_merchant/common/utils.rb +0 -22
  84. data/lib/active_merchant/common/validateable.rb +0 -81
  85. data/lib/active_merchant/common.rb +0 -14
  86. data/lib/certs/cacert.pem +0 -7815
@@ -41,6 +41,12 @@ module ActiveMerchant #:nodoc:
41
41
  commit 'DoExpressCheckoutPayment', build_sale_or_authorization_request('Sale', money, options)
42
42
  end
43
43
 
44
+ def reference_transaction(money, options = {})
45
+ requires!(options, :reference_id, :payment_type, :invoice_id, :description, :ip)
46
+
47
+ commit 'DoReferenceTransaction', build_reference_transaction_request('Sale', money, options)
48
+ end
49
+
44
50
  private
45
51
  def build_get_details_request(token)
46
52
  xml = Builder::XmlMarkup.new :indent => 2
@@ -80,6 +86,8 @@ module ActiveMerchant #:nodoc:
80
86
  xml.tag! 'n2:ButtonSource', application_id.to_s.slice(0,32) unless application_id.blank?
81
87
  xml.tag! 'n2:InvoiceID', options[:order_id]
82
88
  xml.tag! 'n2:OrderDescription', options[:description]
89
+
90
+ add_items_xml(xml, options, currency_code) if options[:items]
83
91
  end
84
92
  end
85
93
  end
@@ -96,12 +104,40 @@ module ActiveMerchant #:nodoc:
96
104
  xml.tag! 'SetExpressCheckoutRequest', 'xmlns:n2' => EBAY_NAMESPACE do
97
105
  xml.tag! 'n2:Version', API_VERSION
98
106
  xml.tag! 'n2:SetExpressCheckoutRequestDetails' do
107
+ xml.tag! 'n2:ReturnURL', options[:return_url]
108
+ xml.tag! 'n2:CancelURL', options[:cancel_return_url]
99
109
  if options[:max_amount]
100
110
  xml.tag! 'n2:MaxAmount', localized_amount(options[:max_amount], currency_code), 'currencyID' => currency_code
101
111
  end
112
+ xml.tag! 'n2:NoShipping', options[:no_shipping] ? '1' : '0'
113
+ xml.tag! 'n2:AddressOverride', options[:address_override] ? '1' : '0'
114
+ xml.tag! 'n2:LocaleCode', options[:locale] unless options[:locale].blank?
115
+ xml.tag! 'n2:BrandName', options[:brand_name] unless options[:brand_name].blank?
116
+ # Customization of the payment page
117
+ xml.tag! 'n2:PageStyle', options[:page_style] unless options[:page_style].blank?
118
+ xml.tag! 'n2:cpp-header-image', options[:header_image] unless options[:header_image].blank?
119
+ xml.tag! 'n2:cpp-header-border-color', options[:header_border_color] unless options[:header_border_color].blank?
120
+ xml.tag! 'n2:cpp-header-back-color', options[:header_background_color] unless options[:header_background_color].blank?
121
+ xml.tag! 'n2:cpp-payflow-color', options[:background_color] unless options[:background_color].blank?
122
+ if options[:allow_guest_checkout]
123
+ xml.tag! 'n2:SolutionType', 'Sole'
124
+ xml.tag! 'n2:LandingPage', 'Billing'
125
+ end
126
+ xml.tag! 'n2:BuyerEmail', options[:email] unless options[:email].blank?
127
+
128
+ if options[:billing_agreement]
129
+ xml.tag! 'n2:BillingAgreementDetails' do
130
+ xml.tag! 'n2:BillingType', options[:billing_agreement][:type]
131
+ xml.tag! 'n2:BillingAgreementDescription', options[:billing_agreement][:description]
132
+ xml.tag! 'n2:PaymentType', options[:billing_agreement][:payment_type] || 'InstantOnly'
133
+ end
134
+ end
135
+
102
136
  if !options[:allow_note].nil?
103
137
  xml.tag! 'n2:AllowNote', options[:allow_note] ? '1' : '0'
104
138
  end
139
+ xml.tag! 'n2:CallbackURL', options[:callback_url] unless options[:callback_url].blank?
140
+
105
141
  xml.tag! 'n2:PaymentDetails' do
106
142
  xml.tag! 'n2:OrderTotal', amount(money).to_f.zero? ? localized_amount(100, currency_code) : localized_amount(money, currency_code), 'currencyID' => currency_code
107
143
  # All of the values must be included together and add up to the order total
@@ -115,53 +151,26 @@ module ActiveMerchant #:nodoc:
115
151
  xml.tag! 'n2:OrderDescription', options[:description]
116
152
  xml.tag! 'n2:InvoiceID', options[:order_id]
117
153
 
118
- if options[:items]
119
- options[:items].each do |item|
120
- xml.tag! 'n2:PaymentDetailsItem' do
121
- xml.tag! 'n2:Name', item[:name]
122
- xml.tag! 'n2:Number', item[:number]
123
- xml.tag! 'n2:Quantity', item[:quantity]
124
- if item[:amount]
125
- xml.tag! 'n2:Amount', localized_amount(item[:amount], currency_code), 'currencyID' => currency_code
126
- end
127
- xml.tag! 'n2:Description', item[:description]
128
- xml.tag! 'n2:ItemURL', item[:url]
129
- end
130
- end
131
- end
132
154
  add_address(xml, 'n2:ShipToAddress', options[:shipping_address] || options[:address])
133
155
 
156
+ add_items_xml(xml, options, currency_code) if options[:items]
157
+
134
158
  xml.tag! 'n2:PaymentAction', action
159
+ xml.tag! 'n2:Custom', options[:custom] unless options[:custom].blank?
135
160
  end
136
161
 
137
- xml.tag! 'n2:AddressOverride', options[:address_override] ? '1' : '0'
138
- xml.tag! 'n2:NoShipping', options[:no_shipping] ? '1' : '0'
139
- xml.tag! 'n2:ReturnURL', options[:return_url]
140
- xml.tag! 'n2:CancelURL', options[:cancel_return_url]
141
- xml.tag! 'n2:IPAddress', options[:ip] unless options[:ip].blank?
142
- xml.tag! 'n2:BuyerEmail', options[:email] unless options[:email].blank?
143
-
144
- if options[:billing_agreement]
145
- xml.tag! 'n2:BillingAgreementDetails' do
146
- xml.tag! 'n2:BillingType', options[:billing_agreement][:type]
147
- xml.tag! 'n2:BillingAgreementDescription', options[:billing_agreement][:description]
148
- xml.tag! 'n2:PaymentType', options[:billing_agreement][:payment_type] || 'InstantOnly'
162
+ if options[:shipping_options]
163
+ options[:shipping_options].each do |shipping_option|
164
+ xml.tag! 'n2:FlatRateShippingOptions' do
165
+ xml.tag! 'n2:ShippingOptionIsDefault', shipping_option[:default]
166
+ xml.tag! 'n2:ShippingOptionAmount', localized_amount(shipping_option[:amount], currency_code), 'currencyID' => currency_code
167
+ xml.tag! 'n2:ShippingOptionName', shipping_option[:name]
168
+ end
149
169
  end
150
170
  end
151
-
152
- # Customization of the payment page
153
- xml.tag! 'n2:PageStyle', options[:page_style] unless options[:page_style].blank?
154
- xml.tag! 'n2:cpp-header-image', options[:header_image] unless options[:header_image].blank?
155
- xml.tag! 'n2:cpp-header-back-color', options[:header_background_color] unless options[:header_background_color].blank?
156
- xml.tag! 'n2:cpp-header-border-color', options[:header_border_color] unless options[:header_border_color].blank?
157
- xml.tag! 'n2:cpp-payflow-color', options[:background_color] unless options[:background_color].blank?
158
-
159
- if options[:allow_guest_checkout]
160
- xml.tag! 'n2:SolutionType', 'Sole'
161
- xml.tag! 'n2:LandingPage', 'Billing'
162
- end
163
-
164
- xml.tag! 'n2:LocaleCode', options[:locale] unless options[:locale].blank?
171
+
172
+ xml.tag! 'n2:CallbackTimeout', options[:callback_timeout] unless options[:callback_timeout].blank?
173
+ xml.tag! 'n2:CallbackVersion', options[:callback_version] unless options[:callback_version].blank?
165
174
  end
166
175
  end
167
176
  end
@@ -169,9 +178,53 @@ module ActiveMerchant #:nodoc:
169
178
  xml.target!
170
179
  end
171
180
 
181
+ def build_reference_transaction_request(action, money, options)
182
+ currency_code = options[:currency] || currency(money)
183
+
184
+ xml = Builder::XmlMarkup.new :indent => 2
185
+ xml.tag! 'DoReferenceTransactionReq', 'xmlns' => PAYPAL_NAMESPACE do
186
+ xml.tag! 'DoReferenceTransactionRequest', 'xmlns:n2' => EBAY_NAMESPACE do
187
+ xml.tag! 'n2:Version', API_VERSION
188
+ xml.tag! 'n2:DoReferenceTransactionRequestDetails' do
189
+ xml.tag! 'n2:ReferenceID', options[:reference_id]
190
+ xml.tag! 'n2:PaymentAction', action
191
+ xml.tag! 'n2:PaymentType', options[:payment_type] || 'Any'
192
+ xml.tag! 'n2:PaymentDetails' do
193
+ xml.tag! 'n2:OrderTotal', amount(money).to_f.zero? ? localized_amount(100, currency_code) : localized_amount(money, currency_code), 'currencyID' => currency_code
194
+ xml.tag! 'n2:OrderDescription', options[:description]
195
+ xml.tag! 'n2:InvoiceID', options[:invoice_id]
196
+ xml.tag! 'n2:ButtonSource', 'ActiveMerchant'
197
+ xml.tag! 'n2:NotifyURL', ''
198
+ end
199
+ xml.tag! 'n2:IPAddress', options[:ip]
200
+ end
201
+ end
202
+ end
203
+
204
+ xml.target!
205
+ end
206
+
172
207
  def build_response(success, message, response, options = {})
173
208
  PaypalExpressResponse.new(success, message, response, options)
174
209
  end
210
+
211
+ private
212
+
213
+ def add_items_xml(xml, options, currency_code)
214
+ options[:items].each do |item|
215
+ xml.tag! 'n2:PaymentDetailsItem' do
216
+ xml.tag! 'n2:Name', item[:name]
217
+ xml.tag! 'n2:Number', item[:number]
218
+ xml.tag! 'n2:Quantity', item[:quantity]
219
+ if item[:amount]
220
+ xml.tag! 'n2:Amount', localized_amount(item[:amount], currency_code), 'currencyID' => currency_code
221
+ end
222
+ xml.tag! 'n2:Description', item[:description]
223
+ xml.tag! 'n2:ItemURL', item[:url]
224
+ xml.tag! 'n2:ItemCategory', item[:category] if item[:category]
225
+ end
226
+ end
227
+ end
175
228
  end
176
229
  end
177
230
  end
@@ -2,8 +2,13 @@ module ActiveMerchant
2
2
  module Billing
3
3
  module PaypalExpressCommon
4
4
  def self.included(base)
5
- base.cattr_accessor :test_redirect_url
6
- base.cattr_accessor :live_redirect_url
5
+ if base.respond_to?(:class_attribute)
6
+ base.class_attribute :test_redirect_url
7
+ base.class_attribute :live_redirect_url
8
+ else
9
+ base.class_inheritable_accessor :test_redirect_url
10
+ base.class_inheritable_accessor :live_redirect_url
11
+ end
7
12
  base.live_redirect_url = 'https://www.paypal.com/cgibin/webscr'
8
13
  end
9
14
 
@@ -22,4 +27,4 @@ module ActiveMerchant
22
27
  end
23
28
  end
24
29
  end
25
- end
30
+ end
@@ -115,6 +115,10 @@ module ActiveMerchant #:nodoc:
115
115
  commit(:query, nil, {})
116
116
  end
117
117
 
118
+ def test?
119
+ @options[:test] || super
120
+ end
121
+
118
122
  private
119
123
 
120
124
  def hosted?
@@ -8,30 +8,91 @@ module ActiveMerchant #:nodoc:
8
8
 
9
9
  self.default_currency = 'DKK'
10
10
  self.money_format = :cents
11
- self.supported_cardtypes = [ :dankort, :forbrugsforeningen, :visa, :master, :american_express, :diners_club, :jcb, :maestro ]
11
+ self.supported_cardtypes = [:dankort, :forbrugsforeningen, :visa, :master, :american_express, :diners_club, :jcb, :maestro]
12
12
  self.supported_countries = ['DK', 'SE']
13
13
  self.homepage_url = 'http://quickpay.dk/'
14
14
  self.display_name = 'Quickpay'
15
15
 
16
- PROTOCOL = 3
17
-
18
16
  MD5_CHECK_FIELDS = {
19
- :authorize => [:protocol, :msgtype, :merchant, :ordernumber, :amount, :currency, :autocapture, :cardnumber, :expirationdate, :cvd, :cardtypelock, :testmode],
20
- :capture => [:protocol, :msgtype, :merchant, :amount, :transaction],
21
- :cancel => [:protocol, :msgtype, :merchant, :transaction],
22
- :refund => [:protocol, :msgtype, :merchant, :amount, :transaction],
23
- :subscribe => [:protocol, :msgtype, :merchant, :ordernumber, :cardnumber, :expirationdate, :cvd, :cardtypelock, :description, :testmode],
24
- :recurring => [:protocol, :msgtype, :merchant, :ordernumber, :amount, :currency, :autocapture, :transaction],
25
- :status => [:protocol, :msgtype, :merchant, :transaction],
26
- :chstatus => [:protocol, :msgtype, :merchant],
17
+ 3 => {
18
+ :authorize => %w(protocol msgtype merchant ordernumber amount
19
+ currency autocapture cardnumber expirationdate
20
+ cvd cardtypelock testmode),
21
+
22
+ :capture => %w(protocol msgtype merchant amount transaction),
23
+
24
+ :cancel => %w(protocol msgtype merchant transaction),
25
+
26
+ :refund => %w(protocol msgtype merchant amount transaction),
27
+
28
+ :subscribe => %w(protocol msgtype merchant ordernumber cardnumber
29
+ expirationdate cvd cardtypelock description testmode),
30
+
31
+ :recurring => %w(protocol msgtype merchant ordernumber amount
32
+ currency autocapture transaction),
33
+
34
+ :status => %w(protocol msgtype merchant transaction),
35
+
36
+ :chstatus => %w(protocol msgtype merchant)
37
+ },
38
+
39
+ 4 => {
40
+ :authorize => %w(protocol msgtype merchant ordernumber amount
41
+ currency autocapture cardnumber expirationdate cvd
42
+ cardtypelock testmode fraud_remote_addr
43
+ fraud_http_accept fraud_http_accept_language
44
+ fraud_http_accept_encoding fraud_http_accept_charset
45
+ fraud_http_referer fraud_http_user_agent apikey),
46
+
47
+ :capture => %w(protocol msgtype merchant amount transaction
48
+ fraud_remote_addr fraud_http_accept
49
+ fraud_http_accept_language fraud_http_accept_encoding
50
+ fraud_http_accept_charset fraud_http_referer
51
+ fraud_http_user_agent apikey),
52
+
53
+ :cancel => %w(protocol msgtype merchant transaction fraud_remote_addr
54
+ fraud_http_accept fraud_http_accept_language
55
+ fraud_http_accept_encoding fraud_http_accept_charset
56
+ fraud_http_referer fraud_http_user_agent apikey),
57
+
58
+ :refund => %w(protocol msgtype merchant amount transaction
59
+ fraud_remote_addr fraud_http_accept fraud_http_accept_language
60
+ fraud_http_accept_encoding fraud_http_accept_charset
61
+ fraud_http_referer fraud_http_user_agent apikey),
62
+
63
+ :subscribe => %w(protocol msgtype merchant ordernumber cardnumber
64
+ expirationdate cvd cardtypelock description testmode
65
+ fraud_remote_addr fraud_http_accept fraud_http_accept_language
66
+ fraud_http_accept_encoding fraud_http_accept_charset
67
+ fraud_http_referer fraud_http_user_agent apikey),
68
+
69
+ :recurring => %w(protocol msgtype merchant ordernumber amount currency
70
+ autocapture transaction fraud_remote_addr fraud_http_accept
71
+ fraud_http_accept_language fraud_http_accept_encoding
72
+ fraud_http_accept_charset fraud_http_referer
73
+ fraud_http_user_agent apikey),
74
+
75
+ :status => %w(protocol msgtype merchant transaction fraud_remote_addr
76
+ fraud_http_accept fraud_http_accept_language
77
+ fraud_http_accept_encoding fraud_http_accept_charset
78
+ fraud_http_referer fraud_http_user_agent apikey),
79
+
80
+ :chstatus => %w(protocol msgtype merchant fraud_remote_addr fraud_http_accept
81
+ fraud_http_accept_language fraud_http_accept_encoding
82
+ fraud_http_accept_charset fraud_http_referer
83
+ fraud_http_user_agent apikey)
84
+ }
27
85
  }
28
86
 
29
87
  APPROVED = '000'
30
88
 
31
89
  # The login is the QuickpayId
32
- # The password is the md5checkword from the Quickpay admin interface
90
+ # The password is the md5checkword from the Quickpay manager
91
+ # To use the API-key from the Quickpay manager, specify :api-key
92
+ # Using the API-key, requires that you use version 4. Specify :version => 4 in options.
33
93
  def initialize(options = {})
34
94
  requires!(options, :login, :password)
95
+ @protocol = options.delete(:version) || 3 # default to protocol version 3
35
96
  @options = options
36
97
  super
37
98
  end
@@ -43,6 +104,7 @@ module ActiveMerchant #:nodoc:
43
104
  add_invoice(post, options)
44
105
  add_creditcard_or_reference(post, credit_card_or_reference, options)
45
106
  add_autocapture(post, false)
107
+ add_fraud_parameters(post, options)
46
108
  add_testmode(post)
47
109
 
48
110
  commit(recurring_or_authorize(credit_card_or_reference), post)
@@ -54,6 +116,7 @@ module ActiveMerchant #:nodoc:
54
116
  add_amount(post, money, options)
55
117
  add_creditcard_or_reference(post, credit_card_or_reference, options)
56
118
  add_invoice(post, options)
119
+ add_fraud_parameters(post, options)
57
120
  add_autocapture(post, true)
58
121
 
59
122
  commit(recurring_or_authorize(credit_card_or_reference), post)
@@ -64,6 +127,7 @@ module ActiveMerchant #:nodoc:
64
127
 
65
128
  add_reference(post, authorization)
66
129
  add_amount_without_currency(post, money)
130
+ add_fraud_parameters(post, options)
67
131
 
68
132
  commit(:capture, post)
69
133
  end
@@ -72,6 +136,7 @@ module ActiveMerchant #:nodoc:
72
136
  post = {}
73
137
 
74
138
  add_reference(post, identification)
139
+ add_fraud_parameters(post, options)
75
140
 
76
141
  commit(:cancel, post)
77
142
  end
@@ -81,6 +146,7 @@ module ActiveMerchant #:nodoc:
81
146
 
82
147
  add_amount_without_currency(post, money)
83
148
  add_reference(post, identification)
149
+ add_fraud_parameters(post, options)
84
150
 
85
151
  commit(:refund, post)
86
152
  end
@@ -96,6 +162,7 @@ module ActiveMerchant #:nodoc:
96
162
  add_creditcard(post, creditcard, options)
97
163
  add_invoice(post, options)
98
164
  add_description(post, options)
165
+ add_fraud_parameters(post, options)
99
166
  add_testmode(post)
100
167
 
101
168
  commit(:subscribe, post)
@@ -148,8 +215,21 @@ module ActiveMerchant #:nodoc:
148
215
  end
149
216
 
150
217
  def add_testmode(post)
218
+ return if post[:transaction].present?
151
219
  post[:testmode] = test? ? '1' : '0'
152
220
  end
221
+
222
+ def add_fraud_parameters(post, options)
223
+ if @protocol == 4
224
+ post[:fraud_remote_addr] = options[:fraud_remote_addr] if options[:fraud_remote_addr]
225
+ post[:fraud_http_accept] = options[:fraud_http_accept] if options[:fraud_http_accept]
226
+ post[:fraud_http_accept_language] = options[:fraud_http_accept_language] if options[:fraud_http_accept_language]
227
+ post[:fraud_http_accept_encoding] = options[:fraud_http_accept_encoding] if options[:fraud_http_accept_encoding]
228
+ post[:fraud_http_accept_charset] = options[:fraud_http_accept_charset] if options[:fraud_http_accept_charset]
229
+ post[:fraud_http_referer] = options[:fraud_http_referer] if options[:fraud_http_referer]
230
+ post[:fraud_http_user_agent] = options[:fraud_http_user_agent] if options[:fraud_http_user_agent]
231
+ end
232
+ end
153
233
 
154
234
  def commit(action, params)
155
235
  response = parse(ssl_post(URL, post_data(action, params)))
@@ -177,27 +257,22 @@ module ActiveMerchant #:nodoc:
177
257
  end
178
258
 
179
259
  def message_from(response)
180
- case response[:qpstat]
181
- when '008' # Error in request data
182
- response[:qpstatmsg].to_s
183
- #.scan(/[A-Z][a-z0-9 \/]+/).to_sentence
184
- else
185
- response[:qpstatmsg].to_s
186
- end
260
+ response[:qpstatmsg].to_s
187
261
  end
188
262
 
189
263
  def post_data(action, params = {})
190
- params[:protocol] = PROTOCOL
264
+ params[:protocol] = @protocol
191
265
  params[:msgtype] = action.to_s
192
266
  params[:merchant] = @options[:login]
267
+ params[:apikey] = @options[:apikey] if @options[:apikey]
193
268
  params[:md5check] = generate_check_hash(action, params)
194
269
 
195
270
  params.collect { |key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join("&")
196
271
  end
197
272
 
198
273
  def generate_check_hash(action, params)
199
- string = MD5_CHECK_FIELDS[action].collect do |key|
200
- params[key]
274
+ string = MD5_CHECK_FIELDS[@protocol][action].collect do |key|
275
+ params[key.to_sym]
201
276
  end.join('')
202
277
 
203
278
  # Add the md5checkword
@@ -197,7 +197,7 @@ module ActiveMerchant
197
197
 
198
198
  if shipping_address
199
199
  xml.tag! 'address', 'type' => 'shipping' do
200
- xml.tag! 'code', shipping_address[:zip]
200
+ xml.tag! 'code', format_shipping_zip_code(shipping_address[:zip])
201
201
  xml.tag! 'country', shipping_address[:country]
202
202
  end
203
203
  end
@@ -247,6 +247,10 @@ module ActiveMerchant
247
247
  address.values_at(:zip, :address1).map{ |v| extract_digits(v) }.join('|')
248
248
  end
249
249
 
250
+ def format_shipping_zip_code(zip)
251
+ zip.to_s.gsub(/\W/, '')
252
+ end
253
+
250
254
  def extract_digits(string)
251
255
  return "" if string.nil?
252
256
  string.gsub(/[\D]/,'')
@@ -0,0 +1,121 @@
1
+ module ActiveMerchant #:nodoc:
2
+ module Billing #:nodoc:
3
+ class SamuraiGateway < Gateway
4
+
5
+ self.homepage_url = 'https://samurai.feefighters.com'
6
+ self.display_name = 'Samurai'
7
+ self.supported_countries = ['US']
8
+ self.supported_cardtypes = [:visa, :master, :american_express, :discover, :jcb, :diners_club]
9
+ self.default_currency = 'USD'
10
+ self.money_format = :dollars
11
+
12
+ def initialize(options = {})
13
+ begin
14
+ require 'samurai'
15
+ rescue LoadError
16
+ raise "Could not load the samurai gem (>= 0.2.25). Use `gem install samurai` to install it."
17
+ end
18
+
19
+ requires!(options, :login, :password, :processor_token)
20
+ @options = options
21
+ Samurai.options = {
22
+ :merchant_key => options[:login],
23
+ :merchant_password => options[:password],
24
+ :processor_token => options[:processor_token]
25
+ }
26
+ end
27
+
28
+ def test?
29
+ @options[:test] || super
30
+ end
31
+
32
+ def authorize(money, credit_card_or_vault_id, options = {})
33
+ token = payment_method_token(credit_card_or_vault_id, options)
34
+ return token if token.is_a?(Response)
35
+
36
+ authorize = Samurai::Processor.authorize(token, amount(money), processor_options(options))
37
+ handle_result(authorize)
38
+ end
39
+
40
+ def purchase(money, credit_card_or_vault_id, options = {})
41
+ token = payment_method_token(credit_card_or_vault_id, options)
42
+ return token if token.is_a?(Response)
43
+
44
+ purchase = Samurai::Processor.purchase(token, amount(money), processor_options(options))
45
+ handle_result(purchase)
46
+ end
47
+
48
+ def capture(money, authorization_id, options = {})
49
+ transaction = Samurai::Transaction.find(authorization_id)
50
+ handle_result(transaction.capture(amount(money)))
51
+ end
52
+
53
+ def refund(money, transaction_id, options = {})
54
+ transaction = Samurai::Transaction.find(transaction_id)
55
+ handle_result(transaction.credit(amount(money)))
56
+ end
57
+
58
+ def void(transaction_id, options = {})
59
+ transaction = Samurai::Transaction.find(transaction_id)
60
+ handle_result(transaction.void)
61
+ end
62
+
63
+ def store(creditcard, options = {})
64
+ address = options[:billing_address] || options[:address] || {}
65
+
66
+ result = Samurai::PaymentMethod.create({
67
+ :card_number => creditcard.number,
68
+ :expiry_month => creditcard.month.to_s.rjust(2, "0"),
69
+ :expiry_year => creditcard.year.to_s,
70
+ :cvv => creditcard.verification_value,
71
+ :first_name => creditcard.first_name,
72
+ :last_name => creditcard.last_name,
73
+ :address_1 => address[:address1],
74
+ :address_2 => address[:address2],
75
+ :city => address[:city],
76
+ :zip => address[:zip],
77
+ :sandbox => test?
78
+ })
79
+ result.retain if options[:retain] && result.is_sensitive_data_valid && result.payment_method_token
80
+
81
+ Response.new(result.is_sensitive_data_valid,
82
+ message_from_result(result),
83
+ { :payment_method_token => result.is_sensitive_data_valid && result.payment_method_token })
84
+ end
85
+
86
+ private
87
+
88
+ def payment_method_token(credit_card_or_vault_id, options)
89
+ return credit_card_or_vault_id if credit_card_or_vault_id.is_a?(String)
90
+ store_result = store(credit_card_or_vault_id, options)
91
+ store_result.success? ? store_result.params["payment_method_token"] : store_result
92
+ end
93
+
94
+ def handle_result(result)
95
+ response_params, response_options = {}, {}
96
+ if result.success?
97
+ response_options[:test] = test?
98
+ response_options[:authorization] = result.reference_id
99
+ response_params[:reference_id] = result.reference_id
100
+ response_params[:transaction_token] = result.transaction_token
101
+ response_params[:payment_method_token] = result.payment_method.payment_method_token
102
+ end
103
+
104
+ response_options[:avs_result] = { :code => result.processor_response && result.processor_response.avs_result_code }
105
+ response_options[:cvv_result] = result.processor_response && result.processor_response.cvv_result_code
106
+
107
+ message = message_from_result(result)
108
+ Response.new(result.success?, message, response_params, response_options)
109
+ end
110
+
111
+ def message_from_result(result)
112
+ return "OK" if result.success?
113
+ result.errors.map {|_, messages| messages }.join(" ")
114
+ end
115
+
116
+ def processor_options(options)
117
+ options.slice(:billing_reference, :customer_reference, :custom, :descriptor)
118
+ end
119
+ end
120
+ end
121
+ end