activemerchant 1.56.0 → 1.66.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (113) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +331 -0
  3. data/README.md +9 -9
  4. data/lib/active_merchant/billing/check.rb +3 -0
  5. data/lib/active_merchant/billing/credit_card.rb +8 -3
  6. data/lib/active_merchant/billing/credit_card_methods.rb +41 -1
  7. data/lib/active_merchant/billing/gateway.rb +14 -6
  8. data/lib/active_merchant/billing/gateways/adyen.rb +228 -0
  9. data/lib/active_merchant/billing/gateways/authorize_net.rb +157 -44
  10. data/lib/active_merchant/billing/gateways/authorize_net_cim.rb +7 -4
  11. data/lib/active_merchant/billing/gateways/barclaycard_smartpay.rb +283 -0
  12. data/lib/active_merchant/billing/gateways/beanstream/beanstream_core.rb +68 -2
  13. data/lib/active_merchant/billing/gateways/blue_pay.rb +2 -2
  14. data/lib/active_merchant/billing/gateways/blue_snap.rb +348 -0
  15. data/lib/active_merchant/billing/gateways/bpoint.rb +1 -1
  16. data/lib/active_merchant/billing/gateways/braintree_blue.rb +58 -20
  17. data/lib/active_merchant/billing/gateways/bridge_pay.rb +37 -8
  18. data/lib/active_merchant/billing/gateways/card_stream.rb +161 -40
  19. data/lib/active_merchant/billing/gateways/cashnet.rb +1 -0
  20. data/lib/active_merchant/billing/gateways/checkout_v2.rb +5 -2
  21. data/lib/active_merchant/billing/gateways/citrus_pay.rb +24 -0
  22. data/lib/active_merchant/billing/gateways/clearhaus.rb +24 -40
  23. data/lib/active_merchant/billing/gateways/conekta.rb +6 -1
  24. data/lib/active_merchant/billing/gateways/creditcall.rb +1 -1
  25. data/lib/active_merchant/billing/gateways/credorax.rb +310 -0
  26. data/lib/active_merchant/billing/gateways/culqi.rb +279 -0
  27. data/lib/active_merchant/billing/gateways/cyber_source.rb +80 -64
  28. data/lib/active_merchant/billing/gateways/data_cash.rb +10 -304
  29. data/lib/active_merchant/billing/gateways/digitzs.rb +292 -0
  30. data/lib/active_merchant/billing/gateways/elavon.rb +40 -26
  31. data/lib/active_merchant/billing/gateways/element.rb +356 -0
  32. data/lib/active_merchant/billing/gateways/fat_zebra.rb +16 -2
  33. data/lib/active_merchant/billing/gateways/firstdata_e4.rb +6 -1
  34. data/lib/active_merchant/billing/gateways/forte.rb +10 -2
  35. data/lib/active_merchant/billing/gateways/global_collect.rb +311 -0
  36. data/lib/active_merchant/billing/gateways/global_transport.rb +1 -0
  37. data/lib/active_merchant/billing/gateways/iats_payments.rb +13 -0
  38. data/lib/active_merchant/billing/gateways/in_context_paypal_express.rb +15 -0
  39. data/lib/active_merchant/billing/gateways/iveri.rb +251 -0
  40. data/lib/active_merchant/billing/gateways/jetpay.rb +33 -19
  41. data/lib/active_merchant/billing/gateways/kushki.rb +217 -0
  42. data/lib/active_merchant/billing/gateways/latitude19.rb +416 -0
  43. data/lib/active_merchant/billing/gateways/linkpoint.rb +2 -0
  44. data/lib/active_merchant/billing/gateways/litle.rb +29 -13
  45. data/lib/active_merchant/billing/gateways/mastercard.rb +268 -0
  46. data/lib/active_merchant/billing/gateways/maxipago.rb +145 -122
  47. data/lib/active_merchant/billing/gateways/merchant_e_solutions.rb +15 -1
  48. data/lib/active_merchant/billing/gateways/merchant_warrior.rb +10 -7
  49. data/lib/active_merchant/billing/gateways/mercury.rb +13 -5
  50. data/lib/active_merchant/billing/gateways/metrics_global.rb +1 -1
  51. data/lib/active_merchant/billing/gateways/migs.rb +23 -1
  52. data/lib/active_merchant/billing/gateways/monei.rb +1 -1
  53. data/lib/active_merchant/billing/gateways/moneris.rb +21 -1
  54. data/lib/active_merchant/billing/gateways/nab_transact.rb +12 -0
  55. data/lib/active_merchant/billing/gateways/ncr_secure_pay.rb +165 -0
  56. data/lib/active_merchant/billing/gateways/netbanx.rb +245 -0
  57. data/lib/active_merchant/billing/gateways/nmi.rb +30 -9
  58. data/lib/active_merchant/billing/gateways/omise.rb +9 -5
  59. data/lib/active_merchant/billing/gateways/openpay.rb +10 -1
  60. data/lib/active_merchant/billing/gateways/opp.rb +362 -0
  61. data/lib/active_merchant/billing/gateways/orbital.rb +28 -7
  62. data/lib/active_merchant/billing/gateways/pagarme.rb +248 -0
  63. data/lib/active_merchant/billing/gateways/pay_junction_v2.rb +190 -0
  64. data/lib/active_merchant/billing/gateways/payeezy.rb +61 -12
  65. data/lib/active_merchant/billing/gateways/payflow/payflow_common_api.rb +1 -1
  66. data/lib/active_merchant/billing/gateways/payflow.rb +6 -0
  67. data/lib/active_merchant/billing/gateways/payment_express.rb +1 -1
  68. data/lib/active_merchant/billing/gateways/paymill.rb +29 -11
  69. data/lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb +1 -1
  70. data/lib/active_merchant/billing/gateways/paypal_express.rb +1 -6
  71. data/lib/active_merchant/billing/gateways/payu_in.rb +3 -2
  72. data/lib/active_merchant/billing/gateways/payu_latam.rb +402 -0
  73. data/lib/active_merchant/billing/gateways/pin.rb +6 -3
  74. data/lib/active_merchant/billing/gateways/pro_pay.rb +326 -0
  75. data/lib/active_merchant/billing/gateways/psl_card.rb +3 -3
  76. data/lib/active_merchant/billing/gateways/quickpay/quickpay_common.rb +1 -1
  77. data/lib/active_merchant/billing/gateways/quickpay/quickpay_v10.rb +0 -2
  78. data/lib/active_merchant/billing/gateways/quickpay/quickpay_v4to7.rb +1 -1
  79. data/lib/active_merchant/billing/gateways/quickpay.rb +3 -3
  80. data/lib/active_merchant/billing/gateways/qvalent.rb +44 -1
  81. data/lib/active_merchant/billing/gateways/redsys.rb +3 -0
  82. data/lib/active_merchant/billing/gateways/s5.rb +8 -5
  83. data/lib/active_merchant/billing/gateways/safe_charge.rb +220 -0
  84. data/lib/active_merchant/billing/gateways/sage.rb +397 -128
  85. data/lib/active_merchant/billing/gateways/sage_pay.rb +45 -20
  86. data/lib/active_merchant/billing/gateways/secure_net.rb +0 -5
  87. data/lib/active_merchant/billing/gateways/secure_pay.rb +1 -1
  88. data/lib/active_merchant/billing/gateways/secure_pay_au.rb +12 -0
  89. data/lib/active_merchant/billing/gateways/securion_pay.rb +46 -17
  90. data/lib/active_merchant/billing/gateways/stripe.rb +125 -29
  91. data/lib/active_merchant/billing/gateways/telr.rb +275 -0
  92. data/lib/active_merchant/billing/gateways/tns.rb +13 -222
  93. data/lib/active_merchant/billing/gateways/trans_first.rb +40 -16
  94. data/lib/active_merchant/billing/gateways/trans_first_transaction_express.rb +606 -0
  95. data/lib/active_merchant/billing/gateways/usa_epay_advanced.rb +114 -9
  96. data/lib/active_merchant/billing/gateways/vanco.rb +14 -10
  97. data/lib/active_merchant/billing/gateways/visanet_peru.rb +209 -0
  98. data/lib/active_merchant/billing/gateways/wepay.rb +73 -38
  99. data/lib/active_merchant/billing/gateways/wirecard.rb +1 -0
  100. data/lib/active_merchant/billing/gateways/world_net.rb +344 -0
  101. data/lib/active_merchant/billing/gateways/worldpay.rb +48 -16
  102. data/lib/active_merchant/billing/network_tokenization_credit_card.rb +15 -0
  103. data/lib/active_merchant/country.rb +6 -4
  104. data/lib/active_merchant/posts_data.rb +1 -1
  105. data/lib/active_merchant/version.rb +1 -1
  106. metadata +32 -13
  107. data/lib/active_merchant/billing/gateways/app55.rb +0 -176
  108. data/lib/active_merchant/billing/gateways/barclays_epdq.rb +0 -314
  109. data/lib/active_merchant/billing/gateways/certo_direct.rb +0 -278
  110. data/lib/active_merchant/billing/gateways/sage/sage_bankcard.rb +0 -89
  111. data/lib/active_merchant/billing/gateways/sage/sage_core.rb +0 -115
  112. data/lib/active_merchant/billing/gateways/sage/sage_vault.rb +0 -149
  113. data/lib/active_merchant/billing/gateways/sage/sage_virtual_check.rb +0 -97
@@ -17,7 +17,7 @@ module ActiveMerchant #:nodoc:
17
17
  super
18
18
  end
19
19
 
20
- def purchase(money, payment_method, options = {})
20
+ def purchase(money, payment_method, options={})
21
21
  action_with_token(:purchase, money, payment_method, options)
22
22
  end
23
23
 
@@ -48,7 +48,7 @@ module ActiveMerchant #:nodoc:
48
48
  end
49
49
 
50
50
  def store(credit_card, options={})
51
- save_card(credit_card)
51
+ save_card(credit_card, options)
52
52
  end
53
53
 
54
54
  def supports_scrubbing
@@ -62,13 +62,27 @@ module ActiveMerchant #:nodoc:
62
62
  gsub(/(account.verification=)(\d*)/, '\1[FILTERED]')
63
63
  end
64
64
 
65
+ def verify_credentials
66
+ begin
67
+ ssl_get(live_url + "transactions/nonexistent", headers)
68
+ rescue ResponseError => e
69
+ return false if e.response.code.to_i == 401
70
+ end
71
+
72
+ true
73
+ end
74
+
65
75
  private
66
76
 
67
- def add_credit_card(post, credit_card)
77
+ def add_credit_card(post, credit_card, options)
78
+ post['account.holder'] = (credit_card.try(:name) || "")
68
79
  post['account.number'] = credit_card.number
69
80
  post['account.expiry.month'] = sprintf("%.2i", credit_card.month)
70
81
  post['account.expiry.year'] = sprintf("%.4i", credit_card.year)
71
82
  post['account.verification'] = credit_card.verification_value
83
+ post['account.email'] = (options[:email] || nil)
84
+ post['presentation.amount3D'] = (options[:money] || nil)
85
+ post['presentation.currency3D'] = (options[:currency] || currency( options[:money]))
72
86
  end
73
87
 
74
88
  def headers
@@ -112,12 +126,13 @@ module ActiveMerchant #:nodoc:
112
126
  end
113
127
 
114
128
  def action_with_token(action, money, payment_method, options)
129
+ options[:money] = money
115
130
  case payment_method
116
- when String
117
- self.send("#{action}_with_token", money, payment_method, options)
118
- else
119
- MultiResponse.run do |r|
120
- r.process { save_card(payment_method) }
131
+ when String
132
+ self.send("#{action}_with_token", money, payment_method, options)
133
+ else
134
+ MultiResponse.run do |r|
135
+ r.process { save_card(payment_method, options) }
121
136
  r.process { self.send("#{action}_with_token", money, r.authorization, options) }
122
137
  end
123
138
  end
@@ -143,10 +158,10 @@ module ActiveMerchant #:nodoc:
143
158
  commit(:post, 'preauthorizations', post)
144
159
  end
145
160
 
146
- def save_card(credit_card)
161
+ def save_card(credit_card, options)
147
162
  post = {}
148
163
 
149
- add_credit_card(post, credit_card)
164
+ add_credit_card(post, credit_card, options)
150
165
  post['channel.id'] = @options[:public_key]
151
166
  post['jsonPFunction'] = 'jsonPFunction'
152
167
  post['transaction.mode'] = (test? ? 'CONNECTOR_TEST' : 'LIVE')
@@ -154,7 +169,7 @@ module ActiveMerchant #:nodoc:
154
169
  begin
155
170
  raw_response = ssl_request(:get, "#{save_card_url}?#{post_data(post)}", nil, {})
156
171
  rescue ResponseError => e
157
- return Response.new(false, e.response.body, e.response.body, {})
172
+ return Response.new(false, e.response.body)
158
173
  end
159
174
 
160
175
  response_for_save_from(raw_response)
@@ -209,6 +224,7 @@ module ActiveMerchant #:nodoc:
209
224
  20203 => "Reversed due to complaint by buyer",
210
225
  20204 => "Payment has been refunded",
211
226
  20300 => "Reversal has been canceled",
227
+ 22000 => "Initiation of transaction successful",
212
228
 
213
229
  30000 => "Transaction still in progress",
214
230
  30100 => "Transaction has been accepted",
@@ -248,6 +264,8 @@ module ActiveMerchant #:nodoc:
248
264
  40420 => "Problem with address data",
249
265
  40500 => "Permission error with acquirer API",
250
266
  40510 => "Rate limit reached for acquirer API",
267
+ 42000 => "Initiation of transaction failed",
268
+ 42410 => "Initiation of transaction expired",
251
269
 
252
270
  50000 => "Problem with back end",
253
271
  50001 => "Country blacklisted",
@@ -620,7 +620,7 @@ module ActiveMerchant #:nodoc:
620
620
  add_optional_fields(xml,
621
621
  %w{n2:NoteText n2:PaymentAction
622
622
  n2:TransactionId n2:AllowedPaymentMethod
623
- n2:PaymentRequestID },
623
+ n2:PaymentRequestID n2:SoftDescriptor },
624
624
  options)
625
625
  end
626
626
 
@@ -26,12 +26,11 @@ module ActiveMerchant #:nodoc:
26
26
  'TW' => 'zh_TW'
27
27
  }
28
28
 
29
- CURRENCIES_WITHOUT_FRACTIONS = %w(BRL HUF JPY MYR TWD TRY)
30
-
31
29
  self.test_redirect_url = 'https://www.sandbox.paypal.com/cgi-bin/webscr'
32
30
  self.supported_countries = ['US']
33
31
  self.homepage_url = 'https://www.paypal.com/cgi-bin/webscr?cmd=xpt/merchant/ExpressCheckoutIntro-outside'
34
32
  self.display_name = 'PayPal Express Checkout'
33
+ self.currencies_without_fractions = %w(HUF JPY TWD)
35
34
 
36
35
  def setup_authorization(money, options = {})
37
36
  requires!(options, :return_url, :cancel_return_url)
@@ -86,10 +85,6 @@ module ActiveMerchant #:nodoc:
86
85
  end
87
86
 
88
87
  private
89
- def non_fractional_currency?(currency)
90
- CURRENCIES_WITHOUT_FRACTIONS.include?(currency.to_s)
91
- end
92
-
93
88
  def build_get_details_request(token)
94
89
  xml = Builder::XmlMarkup.new :indent => 2
95
90
  xml.tag! 'GetExpressCheckoutDetailsReq', 'xmlns' => PAYPAL_NAMESPACE do
@@ -11,7 +11,7 @@ module ActiveMerchant #:nodoc:
11
11
 
12
12
  self.supported_countries = ['IN']
13
13
  self.default_currency = 'INR'
14
- self.supported_cardtypes = [:visa, :master, :american_express, :diners_club]
14
+ self.supported_cardtypes = [:visa, :master, :american_express, :diners_club, :maestro]
15
15
 
16
16
  self.homepage_url = 'https://www.payu.in/'
17
17
  self.display_name = 'PayU India'
@@ -135,7 +135,8 @@ module ActiveMerchant #:nodoc:
135
135
  visa: "VISA",
136
136
  master: "MAST",
137
137
  american_express: "AMEX",
138
- diners_club: "DINR"
138
+ diners_club: "DINR",
139
+ maestro: "MAES"
139
140
  }
140
141
 
141
142
  def add_payment(post, payment)
@@ -0,0 +1,402 @@
1
+ require 'digest/md5'
2
+
3
+ module ActiveMerchant #:nodoc:
4
+ module Billing #:nodoc:
5
+ class PayuLatamGateway < Gateway
6
+ self.display_name = "PayU Latam"
7
+ self.homepage_url = "http://www.payulatam.com"
8
+
9
+ self.test_url = "https://sandbox.api.payulatam.com/payments-api/4.0/service.cgi"
10
+ self.live_url = "https://api.payulatam.com/payments-api/4.0/service.cgi"
11
+
12
+ self.supported_countries = ["AR", "BR", "CL", "CO", "MX", "PA", "PE"]
13
+ self.default_currency = "USD"
14
+ self.money_format = :dollars
15
+ self.supported_cardtypes = [:visa, :master, :american_express, :diners_club]
16
+
17
+ BRAND_MAP = {
18
+ "visa" => "VISA",
19
+ "master" => "MASTERCARD",
20
+ "american_express" => "AMEX",
21
+ "diners_club" => "DINERS"
22
+ }
23
+
24
+ MINIMUMS = {
25
+ "ARS" => 1700,
26
+ "BRL" => 600,
27
+ "MXN" => 3900,
28
+ "PEN" => 500
29
+ }
30
+
31
+ def initialize(options={})
32
+ requires!(options, :merchant_id, :account_id, :api_login, :api_key)
33
+ super
34
+ end
35
+
36
+ def purchase(amount, payment_method, options={})
37
+ post = {}
38
+ auth_or_sale(post, 'AUTHORIZATION_AND_CAPTURE', amount, payment_method, options)
39
+ commit('purchase', post)
40
+ end
41
+
42
+ def authorize(amount, payment_method, options={})
43
+ post = {}
44
+ auth_or_sale(post, 'AUTHORIZATION', amount, payment_method, options)
45
+ commit('auth', post)
46
+ end
47
+
48
+ def capture(amount, authorization, options={})
49
+ post = {}
50
+
51
+ add_credentials(post, 'SUBMIT_TRANSACTION')
52
+ add_transaction_type(post, 'CAPTURE')
53
+ add_reference(post, authorization)
54
+
55
+ commit('capture', post)
56
+ end
57
+
58
+ def void(authorization, options={})
59
+ post = {}
60
+
61
+ add_credentials(post, 'SUBMIT_TRANSACTION')
62
+ add_transaction_type(post, 'VOID')
63
+ add_reference(post, authorization)
64
+
65
+ commit('void', post)
66
+ end
67
+
68
+ def refund(amount, authorization, options={})
69
+ post = {}
70
+
71
+ add_credentials(post, 'SUBMIT_TRANSACTION')
72
+ add_transaction_type(post, 'REFUND')
73
+ add_reference(post, authorization)
74
+
75
+ commit('refund', post)
76
+ end
77
+
78
+ def verify(credit_card, options={})
79
+ minimum = MINIMUMS[options[:currency].upcase] if options[:currency]
80
+ amount = minimum || 100
81
+
82
+ MultiResponse.run(:use_first_response) do |r|
83
+ r.process { authorize(amount, credit_card, options) }
84
+ r.process(:ignore_result) { void(r.authorization, options) }
85
+ end
86
+ end
87
+
88
+ def store(payment_method, options = {})
89
+ post = {}
90
+
91
+ add_credentials(post, 'CREATE_TOKEN')
92
+ add_payment_method_to_be_tokenized(post, payment_method)
93
+
94
+ commit('store', post)
95
+ end
96
+
97
+ def verify_credentials
98
+ post = {}
99
+ add_credentials(post, 'GET_PAYMENT_METHODS')
100
+ response = commit('verify_credentials', post)
101
+ response.success?
102
+ end
103
+
104
+ def supports_scrubbing?
105
+ true
106
+ end
107
+
108
+ def scrub(transcript)
109
+ transcript.
110
+ gsub(%r((\"creditCard\\\":{\\\"number\\\":\\\")\d+), '\1[FILTERED]').
111
+ gsub(%r((\"securityCode\\\":\\\")\d+), '\1[FILTERED]').
112
+ gsub(%r((\"apiKey\\\":\\\")\w+), '\1[FILTERED]')
113
+ end
114
+
115
+ private
116
+
117
+ def auth_or_sale(post, transaction_type, amount, payment_method, options)
118
+ add_credentials(post, 'SUBMIT_TRANSACTION')
119
+ add_transaction_type(post, transaction_type)
120
+ add_order(post, options)
121
+ add_buyer(post, options)
122
+ add_invoice(post, amount, options)
123
+ add_signature(post)
124
+ add_payment_method(post, payment_method, options)
125
+ add_payer(post, options)
126
+ add_extra_parameters(post, options)
127
+ end
128
+
129
+ def add_credentials(post, command)
130
+ post[:test] = test? unless command == 'CREATE_TOKEN'
131
+ post[:language] = 'en'
132
+ post[:command] = command
133
+ merchant = {}
134
+ merchant[:apiLogin] = @options[:api_login]
135
+ merchant[:apiKey] = @options[:api_key]
136
+ post[:merchant] = merchant
137
+ end
138
+
139
+ def add_transaction_type(post, type)
140
+ transaction = {}
141
+ transaction[:type] = type
142
+ post[:transaction] = transaction
143
+ end
144
+
145
+ def add_order(post, options)
146
+ order = {}
147
+ order[:accountId] = @options[:account_id]
148
+ order[:referenceCode] = options[:order_id] || generate_unique_id
149
+ order[:description] = options[:description] || 'unspecified'
150
+ order[:language] = 'en'
151
+ post[:transaction][:order] = order
152
+ end
153
+
154
+ def add_buyer(post, options)
155
+ if address = options[:shipping_address]
156
+ buyer = {}
157
+ buyer[:fullName] = address[:name]
158
+ shipping_address = {}
159
+ shipping_address[:street1] = address[:address1]
160
+ shipping_address[:street2] = address[:address2]
161
+ shipping_address[:city] = address[:city]
162
+ shipping_address[:state] = address[:state]
163
+ shipping_address[:country] = address[:country]
164
+ shipping_address[:postalCode] = address[:zip]
165
+ shipping_address[:phone] = address[:phone]
166
+ buyer[:shippingAddress] = shipping_address
167
+ post[:transaction][:order][:buyer] = buyer
168
+ end
169
+ end
170
+
171
+ def add_invoice(post, money, options)
172
+ tx_value = {}
173
+ tx_value[:value] = amount(money)
174
+ tx_value[:currency] = options[:currency] || currency(money)
175
+
176
+ additional_values = {}
177
+ additional_values[:TX_VALUE] = tx_value
178
+
179
+ post[:transaction][:order][:additionalValues] = additional_values
180
+ end
181
+
182
+ def add_signature(post)
183
+ post[:transaction][:order][:signature] = signature_from(post)
184
+ end
185
+
186
+ def signature_from(post)
187
+ signature_string = [
188
+ @options[:api_key],
189
+ @options[:merchant_id],
190
+ post[:transaction][:order][:referenceCode],
191
+ post[:transaction][:order][:additionalValues][:TX_VALUE][:value],
192
+ post[:transaction][:order][:additionalValues][:TX_VALUE][:currency]
193
+ ].compact.join("~")
194
+
195
+ Digest::MD5.hexdigest(signature_string)
196
+ end
197
+
198
+ def add_payment_method(post, payment_method, options)
199
+ if payment_method.is_a?(String)
200
+ brand, token = split_authorization(payment_method)
201
+ credit_card = {}
202
+ credit_card[:securityCode] = options[:cvv] if options[:cvv]
203
+ credit_card[:processWithoutCvv2] = true if options[:cvv].blank?
204
+ post[:transaction][:creditCard] = credit_card
205
+ post[:transaction][:creditCardTokenId] = token
206
+ post[:transaction][:paymentMethod] = brand.upcase
207
+ else
208
+ credit_card = {}
209
+ credit_card[:number] = payment_method.number
210
+ credit_card[:securityCode] = add_security_code(payment_method, options)
211
+ credit_card[:expirationDate] = format(payment_method.year, :four_digits).to_s + '/' + format(payment_method.month, :two_digits).to_s
212
+ credit_card[:name] = payment_method.name.strip
213
+ credit_card[:processWithoutCvv2] = true if add_process_without_cvv2(payment_method, options)
214
+ post[:transaction][:creditCard] = credit_card
215
+ post[:transaction][:paymentMethod] = BRAND_MAP[payment_method.brand.to_s]
216
+ end
217
+ end
218
+
219
+ def add_security_code(payment_method, options)
220
+ return payment_method.verification_value unless payment_method.verification_value.blank?
221
+ return options[:cvv] unless options[:cvv].blank?
222
+ return "0000" if BRAND_MAP[payment_method.brand.to_s] == "AMEX"
223
+ "000"
224
+ end
225
+
226
+ def add_process_without_cvv2(payment_method, options)
227
+ return true if payment_method.verification_value.blank? && options[:cvv].blank?
228
+ false
229
+ end
230
+
231
+ def add_payer(post, options)
232
+ if address = options[:billing_address]
233
+ payer = {}
234
+ post[:transaction][:paymentCountry] = address[:country]
235
+ payer[:fullName] = address[:name]
236
+ payer[:contactPhone] = address[:phone]
237
+ billing_address = {}
238
+ billing_address[:street1] = address[:address1]
239
+ billing_address[:street2] = address[:address2]
240
+ billing_address[:city] = address[:city]
241
+ billing_address[:state] = address[:state]
242
+ billing_address[:country] = address[:country]
243
+ billing_address[:postalCode] = address[:zip]
244
+ billing_address[:phone] = address[:phone]
245
+ payer[:billingAddress] = billing_address
246
+ post[:transaction][:payer] = payer
247
+ end
248
+ end
249
+
250
+ def add_extra_parameters(post, options)
251
+ extra_parameters = {}
252
+ extra_parameters[:INSTALLMENTS_NUMBER] = options[:installments_number] || 1
253
+ post[:transaction][:extraParameters] = extra_parameters
254
+ end
255
+
256
+ def add_reference(post, authorization)
257
+ order_id, transaction_id = split_authorization(authorization)
258
+ order = {}
259
+ order[:id] = order_id
260
+ post[:transaction][:order] = order
261
+ post[:transaction][:parentTransactionId] = transaction_id
262
+ post[:transaction][:reason] = 'n/a'
263
+ end
264
+
265
+ def add_payment_method_to_be_tokenized(post, payment_method)
266
+ credit_card_token = {}
267
+ credit_card_token[:payerId] = generate_unique_id
268
+ credit_card_token[:name] = payment_method.name.strip
269
+ credit_card_token[:identificationNumber] = generate_unique_id
270
+ credit_card_token[:paymentMethod] = BRAND_MAP[payment_method.brand.to_s]
271
+ credit_card_token[:number] = payment_method.number
272
+ credit_card_token[:expirationDate] = format(payment_method.year, :four_digits).to_s + '/' + format(payment_method.month, :two_digits).to_s
273
+ credit_card_token[:securityCode] = payment_method.verification_value
274
+ post[:creditCardToken] = credit_card_token
275
+ end
276
+
277
+ def commit(action, params)
278
+ begin
279
+ raw_response = ssl_post(url, post_data(params), headers)
280
+ response = parse(raw_response)
281
+ rescue ResponseError => e
282
+ raw_response = e.response.body
283
+ response_error(raw_response)
284
+ rescue JSON::ParserError
285
+ unparsable_response(raw_response)
286
+ else
287
+ success = success_from(action, response)
288
+ Response.new(
289
+ success,
290
+ message_from(action, success, response),
291
+ response,
292
+ authorization: success ? authorization_from(action, response) : nil,
293
+ error_code: success ? nil : error_from(action, response),
294
+ test: test?
295
+ )
296
+ end
297
+ end
298
+
299
+ def headers
300
+ {
301
+ "Content-Type" => "application/json",
302
+ "Accept" => "application/json"
303
+ }
304
+ end
305
+
306
+ def post_data(params)
307
+ params.to_json
308
+ end
309
+
310
+ def url
311
+ test? ? test_url : live_url
312
+ end
313
+
314
+ def parse(body)
315
+ JSON.parse(body)
316
+ end
317
+
318
+ def success_from(action, response)
319
+ case action
320
+ when 'store'
321
+ response["code"] == "SUCCESS" && response["creditCardToken"] && response["creditCardToken"]["creditCardTokenId"].present?
322
+ when 'verify_credentials'
323
+ response["code"] == "SUCCESS"
324
+ when 'refund'
325
+ response["code"] == "SUCCESS" && response["transactionResponse"] && (response["transactionResponse"]["state"] == "PENDING" || response["transactionResponse"]["state"] == "APPROVED")
326
+ else
327
+ response["code"] == "SUCCESS" && response["transactionResponse"] && (response["transactionResponse"]["state"] == "APPROVED")
328
+ end
329
+ end
330
+
331
+ def message_from(action, success, response)
332
+ case action
333
+ when 'store'
334
+ return response["code"] if success
335
+ error_description = response["creditCardToken"]["errorDescription"] if response["creditCardToken"]
336
+ response["error"] || error_description || "FAILED"
337
+ when 'verify_credentials'
338
+ return "VERIFIED" if success
339
+ "FAILED"
340
+ else
341
+ response_message = response["transactionResponse"]["responseMessage"] if response["transactionResponse"]
342
+ response_code = response["transactionResponse"]["responseCode"] if response["transactionResponse"]
343
+ return response_code if success
344
+ response["error"] || response_message || response_code || "FAILED"
345
+ end
346
+ end
347
+
348
+ def authorization_from(action, response)
349
+ case action
350
+ when 'store'
351
+ [
352
+ response["creditCardToken"]["paymentMethod"],
353
+ response["creditCardToken"]["creditCardTokenId"]
354
+ ].compact.join("|")
355
+ when 'verify_credentials'
356
+ nil
357
+ else
358
+ [
359
+ response["transactionResponse"]["orderId"],
360
+ response["transactionResponse"]["transactionId"]
361
+ ].compact.join("|")
362
+ end
363
+ end
364
+
365
+ def split_authorization(authorization)
366
+ authorization.split("|")
367
+ end
368
+
369
+ def error_from(action, response)
370
+ case action
371
+ when 'store'
372
+ response["creditCardToken"]["errorDescription"] if response["creditCardToken"]
373
+ when 'verify_credentials'
374
+ response["error"] || "FAILED"
375
+ else
376
+ response["transactionResponse"]["errorCode"] || response["transactionResponse"]["responseCode"] if response["transactionResponse"]
377
+ end
378
+ end
379
+
380
+ def response_error(raw_response)
381
+ begin
382
+ response = parse(raw_response)
383
+ rescue JSON::ParserError
384
+ unparsable_response(raw_response)
385
+ else
386
+ return Response.new(
387
+ false,
388
+ message_from('', false, response),
389
+ response,
390
+ :test => test?
391
+ )
392
+ end
393
+ end
394
+
395
+ def unparsable_response(raw_response)
396
+ message = "Invalid JSON response received from PayuLatamGateway. Please contact PayuLatamGateway if you continue to receive this message."
397
+ message += " (The raw response returned by the API was #{raw_response.inspect})"
398
+ return Response.new(false, message)
399
+ end
400
+ end
401
+ end
402
+ end
@@ -29,6 +29,7 @@ module ActiveMerchant #:nodoc:
29
29
  add_creditcard(post, creditcard)
30
30
  add_address(post, creditcard, options)
31
31
  add_capture(post, options)
32
+ add_metadata(post, options)
32
33
 
33
34
  commit(:post, 'charges', post, options)
34
35
  end
@@ -44,9 +45,7 @@ module ActiveMerchant #:nodoc:
44
45
  commit(:post, 'customers', post, options)
45
46
  end
46
47
 
47
- # Refund a transaction, note that the money attribute is ignored at the
48
- # moment as the API does not support partial refunds. The parameter is
49
- # kept for compatibility reasons
48
+ # Refund a transaction
50
49
  def refund(money, token, options = {})
51
50
  commit(:post, "charges/#{CGI.escape(token)}/refunds", { :amount => amount(money) }, options)
52
51
  end
@@ -143,6 +142,10 @@ module ActiveMerchant #:nodoc:
143
142
  end
144
143
  end
145
144
 
145
+ def add_metadata(post, options)
146
+ post[:metadata] = options[:metadata] if options[:metadata]
147
+ end
148
+
146
149
  def headers(params = {})
147
150
  result = {
148
151
  "Content-Type" => "application/json",