activemerchant 1.88.0 → 1.89.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 53339022ee833c22c93fb9958507b7650e40b9903cdeddf48bcac2874eeaa2bd
4
- data.tar.gz: 3c0dfd77791def2e65522466a32a9f6aacf4289f1585f39322b226f5ed3a582c
3
+ metadata.gz: fdeabb7b3450080d2817ffacaa19763da578a7af135d41539bff63857f92d8c5
4
+ data.tar.gz: ffc300e51e51b3895a3719c165d9732980885c3e47024f60929742fb0a6ce66c
5
5
  SHA512:
6
- metadata.gz: a07c6a56d9b28ee1bef9f93985d05e4a25dbb9e85f0d1432e0a89f30d6af8e57cd5b6d9f4b8b43b66d984cdfd6edecf056d7eac94ad331364f05a5758df09833
7
- data.tar.gz: 04a43d55813f193035fc7fc00d72597093cd8c2342a7fa880b283aab2db21d58c0516ae91f1f021189b8f805665e6502b41d38e1b8bc27306ce4cc2cf0e3938e
6
+ metadata.gz: 673d733fff52ede8aeb3c2da8d8452ad37d9b3efdf676686b8fbf2828b6556c5e44158ada81ec70f226b26626f59ffd5fcbca0a7e5e03ad0cb0dfc12a22e181d
7
+ data.tar.gz: 1197d9aa884da3d084e6e3e0d09700c29dcbdf8b9f7e003ea97f55fb369284ea718261ac4f1e7ca37154e8105c3282a7f641221062d2dae46a976f5939009873
data/CHANGELOG CHANGED
@@ -2,6 +2,23 @@
2
2
 
3
3
  == HEAD
4
4
 
5
+ == Version 1.89.0 (December 17, 2018)
6
+ * Worldpay: handle Visa and MasterCard payouts differently [bpollack] #3068
7
+ * QuickPay: update supported countries [ta] #3049
8
+ * WorldPay: set cardholder name to "3D" for 3DS transactions [bpollack] #3071
9
+ * Authorize.Net: Support refunds for bank accounts [nfarve] #3063
10
+ * Stripe: support specifying a reason for refunds [yosukehasumi] #3056
11
+ * Paybox Direct: add support for XPF currency [adam-stead] #2938
12
+ * TrustCommerce: Add ACH Ability [nfarve] #3073
13
+ * Payeezy: Support $0 for verify transactions [molbrown] #3074
14
+ * USA ePay: add support for recurring transactions, custom fields, and line items [lancecarlson] #3069
15
+ * Add dLocal gateway [curiousepic] #3709
16
+ * dLocal: Require secret_key [curiousepic] #3080
17
+ * Adyen: Implement 3DS [nfarve] #3076
18
+ * Adyen: Add 3DS Fix [nfarve] #3081
19
+ * Payeezy: Add `stored_credentials` [nfarve] #3083
20
+ * Fix CVC validation for 0 length CVC [filipebarcos] #3082
21
+
5
22
  == Version 1.88.0 (November 30, 2018)
6
23
  * Added ActiveSupport/Rails master support [Edouard-chin] #3065
7
24
 
@@ -26,7 +43,7 @@
26
43
  * CyberSource: update supported countries [bpollack] #3055
27
44
  * MiGS: update supported countries [bpollack] #3055
28
45
  * Clearhaus: update submission data format [bpollack] #3053
29
- * Forte: Allow void on capture #3059
46
+ * Forte: Allow void on capture [nfarve] #3059
30
47
 
31
48
  == Version 1.86.0 (October 26, 2018)
32
49
  * UsaEpayTransaction: Support UMcheckformat option for echecks [dtykocki] #3002
data/README.md CHANGED
@@ -199,7 +199,7 @@ The [ActiveMerchant Wiki](http://github.com/activemerchant/active_merchant/wikis
199
199
  * [QuickBooks Merchant Services](http://payments.intuit.com/) - US
200
200
  * [QuickBooks Payments](http://payments.intuit.com/) - US
201
201
  * [Quantum Gateway](http://www.quantumgateway.com) - US
202
- * [QuickPay](http://quickpay.net/) - DE, DK, ES, FI, FR, FO, GB, IS, NO, SE
202
+ * [QuickPay](http://quickpay.net/) - AT, BE, BG, CY, CZ, DE, DK, EE, ES, FI, FR, GB, GR, HR, HU, IE, IS, IT, LI, LT, LU, LV, MT, NL, NO, PL, PT, RO, SE SI, SK
203
203
  * [Qvalent](https://www.qvalent.com/) - AU
204
204
  * [Raven](http://www.deepcovelabs.com/raven) - AI, AN, AT, AU, BE, BG, BS, BZ, CA, CH, CR, CY, CZ, DE, DK, DM, DO, EE, EL, ES, FI, FR, GB, GG, GI, HK, HR, HU, IE, IL, IM, IN, IT, JE, KN, LI, LT, LU, LV, MH, MT, MY, NL, NO, NZ, PA, PE, PH, PL, PT, RO, RS, SC, SE, SG, SI, SK, UK, US, VG, ZA
205
205
  * [Realex](http://www.realexpayments.com/) - IE, GB, FR, BE, NL, LU, IT
@@ -362,7 +362,7 @@ module ActiveMerchant #:nodoc:
362
362
  unless valid_card_verification_value?(verification_value, brand)
363
363
  errors << [:verification_value, "should be #{card_verification_value_length(brand)} digits"]
364
364
  end
365
- elsif requires_verification_value?
365
+ elsif requires_verification_value? && !valid_card_verification_value?(verification_value, brand)
366
366
  errors << [:verification_value, 'is required']
367
367
  end
368
368
  errors
@@ -33,9 +33,13 @@ module ActiveMerchant #:nodoc:
33
33
  end
34
34
 
35
35
  def purchase(money, payment, options={})
36
- MultiResponse.run do |r|
37
- r.process { authorize(money, payment, options) }
38
- r.process { capture(money, r.authorization, options) }
36
+ if options[:execute_threed]
37
+ authorize(money, payment, options)
38
+ else
39
+ MultiResponse.run do |r|
40
+ r.process { authorize(money, payment, options) }
41
+ r.process { capture(money, r.authorization, options) }
42
+ end
39
43
  end
40
44
  end
41
45
 
@@ -48,6 +52,7 @@ module ActiveMerchant #:nodoc:
48
52
  add_shopper_interaction(post, payment, options)
49
53
  add_address(post, options)
50
54
  add_installments(post, options) if options[:installments]
55
+ add_3ds(post, options) if options[:execute_threed]
51
56
  commit('authorise', post)
52
57
  end
53
58
 
@@ -258,6 +263,11 @@ module ActiveMerchant #:nodoc:
258
263
  }
259
264
  end
260
265
 
266
+ def add_3ds(post, options)
267
+ post[:additionalData] = { executeThreeD: 'true' }
268
+ post[:browserInfo] = { userAgent: options[:user_agent], acceptHeader: options[:accept_header] }
269
+ end
270
+
261
271
  def parse(body)
262
272
  return {} if body.blank?
263
273
  JSON.parse(body)
@@ -315,7 +325,7 @@ module ActiveMerchant #:nodoc:
315
325
 
316
326
  def success_from(action, response)
317
327
  case action.to_s
318
- when 'authorise'
328
+ when 'authorise', 'authorise3d'
319
329
  ['Authorised', 'Received', 'RedirectShopper'].include?(response['resultCode'])
320
330
  when 'capture', 'refund', 'cancel'
321
331
  response['response'] == "[#{action}-received]"
@@ -339,9 +339,18 @@ module ActiveMerchant
339
339
  xml.transactionType('refundTransaction')
340
340
  xml.amount(amount.nil? ? 0 : amount(amount))
341
341
  xml.payment do
342
- xml.creditCard do
343
- xml.cardNumber(card_number || options[:card_number])
344
- xml.expirationDate('XXXX')
342
+ if options[:routing_number]
343
+ xml.bankAccount do
344
+ xml.accountType(options[:account_type])
345
+ xml.routingNumber(options[:routing_number])
346
+ xml.accountNumber(options[:account_number])
347
+ xml.nameOnAccount("#{options[:first_name]} #{options[:last_name]}")
348
+ end
349
+ else
350
+ xml.creditCard do
351
+ xml.cardNumber(card_number || options[:card_number])
352
+ xml.expirationDate('XXXX')
353
+ end
345
354
  end
346
355
  end
347
356
  xml.refTransId(transaction_id)
@@ -0,0 +1,226 @@
1
+ module ActiveMerchant #:nodoc:
2
+ module Billing #:nodoc:
3
+ class DLocalGateway < Gateway
4
+ self.test_url = 'https://sandbox.dlocal.com'
5
+ self.live_url = 'https://api.dlocal.com'
6
+
7
+ self.supported_countries = ['AR', 'BR', 'CL', 'CO', 'MX', 'PE', 'UY', 'TR']
8
+ self.default_currency = 'USD'
9
+ self.supported_cardtypes = [:visa, :master, :american_express, :discover, :jcb, :diners_club, :maestro]
10
+
11
+ self.homepage_url = 'https://dlocal.com/'
12
+ self.display_name = 'dLocal'
13
+
14
+ def initialize(options={})
15
+ requires!(options, :login, :trans_key, :secret_key)
16
+ super
17
+ end
18
+
19
+ def purchase(money, payment, options={})
20
+ post = {}
21
+ add_auth_purchase_params(post, money, payment, 'purchase', options)
22
+
23
+ commit('purchase', post, options)
24
+ end
25
+
26
+ def authorize(money, payment, options={})
27
+ post = {}
28
+ add_auth_purchase_params(post, money, payment, 'authorize', options)
29
+
30
+ commit('authorize', post, options)
31
+ end
32
+
33
+ def capture(money, authorization, options={})
34
+ post = {}
35
+ post[:payment_id] = authorization
36
+ add_invoice(post, money, options) if money
37
+ commit('capture', post, options)
38
+ end
39
+
40
+ def refund(money, authorization, options={})
41
+ post = {}
42
+ post[:payment_id] = authorization
43
+ post[:notification_url] = options[:notification_url]
44
+ add_invoice(post, money, options) if money
45
+ commit('refund', post, options)
46
+ end
47
+
48
+ def void(authorization, options={})
49
+ post = {}
50
+ post[:payment_id] = authorization
51
+ commit('void', post, options)
52
+ end
53
+
54
+ def verify(credit_card, options={})
55
+ MultiResponse.run(:use_first_response) do |r|
56
+ r.process { authorize(100, credit_card, options) }
57
+ r.process(:ignore_result) { void(r.authorization, options) }
58
+ end
59
+ end
60
+
61
+ def supports_scrubbing?
62
+ true
63
+ end
64
+
65
+ def scrub(transcript)
66
+ transcript.
67
+ gsub(%r((X-Trans-Key: )\w+), '\1[FILTERED]').
68
+ gsub(%r((\"number\\\":\\\")\d+), '\1[FILTERED]').
69
+ gsub(%r((\"cvv\\\":\\\")\d+), '\1[FILTERED]')
70
+ end
71
+
72
+ private
73
+
74
+ def add_auth_purchase_params(post, money, card, action, options)
75
+ add_invoice(post, money, options)
76
+ post[:payment_method_id] = 'CARD'
77
+ post[:payment_method_flow] = 'DIRECT'
78
+ add_country(post, card, options)
79
+ add_payer(post, card, options)
80
+ add_card(post, card, action, options)
81
+ post[:order_id] = options[:order_id] || generate_unique_id
82
+ post[:description] = options[:description] if options[:description]
83
+ end
84
+
85
+ def add_invoice(post, money, options)
86
+ post[:amount] = amount(money)
87
+ post[:currency] = (options[:currency] || currency(money))
88
+ end
89
+
90
+ def add_country(post, card, options)
91
+ return unless address = options[:billing_address] || options[:address]
92
+ post[:country] = lookup_country_code(address[:country])
93
+ end
94
+
95
+ def lookup_country_code(country)
96
+ Country.find(country).code(:alpha2)
97
+ end
98
+
99
+ def add_payer(post, card, options)
100
+ address = options[:billing_address] || options[:address]
101
+ post[:payer] = {}
102
+ post[:payer][:name] = card.name
103
+ post[:payer][:email] = options[:email] if options[:email]
104
+ post[:payer][:birth_date] = options[:birth_date] if options[:birth_date]
105
+ post[:payer][:phone] = address[:phone] if address[:phone]
106
+ post[:payer][:document] = options[:document] if options[:document]
107
+ post[:payer][:document2] = options[:document2] if options[:document2]
108
+ post[:payer][:user_reference] = options[:user_reference] if options[:user_reference]
109
+ post[:payer][:address] = add_address(post, card, options)
110
+ end
111
+
112
+ def add_address(post, card, options)
113
+ return unless address = options[:billing_address] || options[:address]
114
+ address_object = {}
115
+ address_object[:state] = address[:state] if address[:state]
116
+ address_object[:city] = address[:city] if address[:city]
117
+ address_object[:zip_code] = address[:zip_code] if address[:zip_code]
118
+ address_object[:street] = address[:street] if address[:street]
119
+ address_object[:number] = address[:number] if address[:number]
120
+ address_object
121
+ end
122
+
123
+ def add_card(post, card, action, options={})
124
+ post[:card] = {}
125
+ post[:card][:holder_name] = card.name
126
+ post[:card][:expiration_month] = card.month
127
+ post[:card][:expiration_year] = card.year
128
+ post[:card][:number] = card.number
129
+ post[:card][:cvv] = card.verification_value
130
+ post[:card][:descriptor] = options[:dynamic_descriptor] if options[:dynamic_descriptor]
131
+ post[:card][:capture] = (action == 'purchase')
132
+ end
133
+
134
+ def parse(body)
135
+ JSON.parse(body)
136
+ end
137
+
138
+ def commit(action, parameters, options={})
139
+ url = url(action, parameters, options)
140
+ post = post_data(action, parameters)
141
+ begin
142
+ raw = ssl_post(url, post, headers(post, options))
143
+ response = parse(raw)
144
+ rescue ResponseError => e
145
+ raw = e.response.body
146
+ response = parse(raw)
147
+ end
148
+
149
+ Response.new(
150
+ success_from(action, response),
151
+ message_from(action, response),
152
+ response,
153
+ authorization: authorization_from(response),
154
+ avs_result: AVSResult.new(code: response['some_avs_response_key']),
155
+ cvv_result: CVVResult.new(response['some_cvv_response_key']),
156
+ test: test?,
157
+ error_code: error_code_from(action, response)
158
+ )
159
+ end
160
+
161
+ # A refund may not be immediate, and return a status_code of 100, "Pending".
162
+ # Since we aren't handling async notifications of eventual success,
163
+ # we count 100 as a success.
164
+ def success_from(action, response)
165
+ return false unless response['status_code']
166
+ ['100', '200', '400', '600'].include? response['status_code'].to_s
167
+ end
168
+
169
+ def message_from(action, response)
170
+ response['status_detail'] || response['message']
171
+ end
172
+
173
+ def authorization_from(response)
174
+ response['id']
175
+ end
176
+
177
+ def error_code_from(action, response)
178
+ return if success_from(action, response)
179
+ code = response['status_code'] || response['code']
180
+ code&.to_s
181
+ end
182
+
183
+ def url(action, parameters, options={})
184
+ "#{(test? ? test_url : live_url)}/#{endpoint(action, parameters, options)}/"
185
+ end
186
+
187
+ def endpoint(action, parameters, options)
188
+ case action
189
+ when 'purchase'
190
+ 'secure_payments'
191
+ when 'authorize'
192
+ 'secure_payments'
193
+ when 'refund'
194
+ 'refunds'
195
+ when 'capture'
196
+ "payments/#{parameters[:payment_id]}/capture"
197
+ when 'void'
198
+ "payments/#{parameters[:payment_id]}/cancel"
199
+ end
200
+ end
201
+
202
+ def headers(post, options={})
203
+ timestamp = Time.now.utc.iso8601
204
+ headers = {
205
+ 'Content-Type' => 'application/json',
206
+ 'X-Date' => timestamp,
207
+ 'X-Login' => @options[:login],
208
+ 'X-Trans-Key' => @options[:trans_key],
209
+ 'Authorization' => signature(post, timestamp)
210
+ }
211
+ headers.merge('X-Idempotency-Key' => options[:idempotency_key]) if options[:idempotency_key]
212
+ headers
213
+ end
214
+
215
+ def signature(post, timestamp)
216
+ content = "#{@options[:login]}#{timestamp}#{post}"
217
+ digest = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), @options[:secret_key], content)
218
+ "V2-HMAC-SHA256, Signature: #{digest}"
219
+ end
220
+
221
+ def post_data(action, parameters = {})
222
+ parameters.to_json
223
+ end
224
+ end
225
+ end
226
+ end
@@ -187,6 +187,7 @@ module ActiveMerchant #:nodoc:
187
187
  requires!(options, :merchant_id)
188
188
  requires!(options, :login, :password) unless options[:ip_authentication]
189
189
  super
190
+ @options[:merchant_id] = @options[:merchant_id].to_s
190
191
  end
191
192
 
192
193
  # A – Authorization request
@@ -34,7 +34,8 @@ module ActiveMerchant #:nodoc:
34
34
  'CHF'=> '756',
35
35
  'GBP'=> '826',
36
36
  'USD'=> '840',
37
- 'EUR'=> '978'
37
+ 'EUR'=> '978',
38
+ 'XPF'=> '953'
38
39
  }
39
40
 
40
41
  SUCCESS_CODES = ['00000']
@@ -39,6 +39,7 @@ module ActiveMerchant
39
39
  add_address(params, options)
40
40
  add_amount(params, amount, options)
41
41
  add_soft_descriptors(params, options)
42
+ add_stored_credentials(params, options)
42
43
 
43
44
  commit(params, options)
44
45
  end
@@ -52,6 +53,7 @@ module ActiveMerchant
52
53
  add_address(params, options)
53
54
  add_amount(params, amount, options)
54
55
  add_soft_descriptors(params, options)
56
+ add_stored_credentials(params, options)
55
57
 
56
58
  commit(params, options)
57
59
  end
@@ -94,7 +96,7 @@ module ActiveMerchant
94
96
 
95
97
  def verify(credit_card, options={})
96
98
  MultiResponse.run(:use_first_response) do |r|
97
- r.process { authorize(100, credit_card, options) }
99
+ r.process { authorize(0, credit_card, options) }
98
100
  r.process(:ignore_result) { void(r.authorization, options) }
99
101
  end
100
102
  end
@@ -244,6 +246,17 @@ module ActiveMerchant
244
246
  params[:soft_descriptors] = options[:soft_descriptors] if options[:soft_descriptors]
245
247
  end
246
248
 
249
+ def add_stored_credentials(params, options)
250
+ if options[:sequence]
251
+ params[:stored_credentials] = {}
252
+ params[:stored_credentials][:cardbrand_original_transaction_id] = options[:cardbrand_original_transaction_id] if options[:cardbrand_original_transaction_id]
253
+ params[:stored_credentials][:sequence] = options[:sequence]
254
+ params[:stored_credentials][:initiator] = options[:initiator] if options[:initiator]
255
+ params[:stored_credentials][:is_scheduled] = options[:is_scheduled]
256
+ params[:stored_credentials][:auth_type_override] = options[:auth_type_override] if options[:auth_type_override]
257
+ end
258
+ end
259
+
247
260
  def commit(params, options)
248
261
  url = base_url(options) + endpoint(params)
249
262
 
@@ -147,6 +147,7 @@ module ActiveMerchant #:nodoc:
147
147
  post[:refund_application_fee] = true if options[:refund_application_fee]
148
148
  post[:reverse_transfer] = options[:reverse_transfer] if options[:reverse_transfer]
149
149
  post[:metadata] = options[:metadata] if options[:metadata]
150
+ post[:reason] = options[:reason] if options[:reason]
150
151
  post[:expand] = [:charge]
151
152
 
152
153
  MultiResponse.run(:first) do |r|
@@ -153,6 +153,7 @@ module ActiveMerchant #:nodoc:
153
153
  }
154
154
 
155
155
  add_order_id(parameters, options)
156
+ add_aggregator(parameters, options)
156
157
  add_customer_data(parameters, options)
157
158
  add_payment_source(parameters, creditcard_or_billing_id)
158
159
  add_addresses(parameters, options)
@@ -167,6 +168,7 @@ module ActiveMerchant #:nodoc:
167
168
  }
168
169
 
169
170
  add_order_id(parameters, options)
171
+ add_aggregator(parameters, options)
170
172
  add_customer_data(parameters, options)
171
173
  add_payment_source(parameters, creditcard_or_billing_id)
172
174
  add_addresses(parameters, options)
@@ -181,6 +183,7 @@ module ActiveMerchant #:nodoc:
181
183
  :amount => amount(money),
182
184
  :transid => authorization,
183
185
  }
186
+ add_aggregator(parameters, options)
184
187
 
185
188
  commit('postauth', parameters)
186
189
  end
@@ -192,6 +195,7 @@ module ActiveMerchant #:nodoc:
192
195
  :amount => amount(money),
193
196
  :transid => identification
194
197
  }
198
+ add_aggregator(parameters, options)
195
199
 
196
200
  commit('credit', parameters)
197
201
  end
@@ -219,6 +223,7 @@ module ActiveMerchant #:nodoc:
219
223
  parameters = {
220
224
  :transid => authorization,
221
225
  }
226
+ add_aggregator(parameters, options)
222
227
 
223
228
  commit('reversal', parameters)
224
229
  end
@@ -300,19 +305,36 @@ module ActiveMerchant #:nodoc:
300
305
  transcript.
301
306
  gsub(%r((Authorization: Basic )\w+), '\1[FILTERED]').
302
307
  gsub(%r((&?cc=)\d*(&?)), '\1[FILTERED]\2').
308
+ gsub(%r((&?password=)[^&]+(&?)), '\1[FILTERED]\2').
303
309
  gsub(%r((&?cvv=)\d*(&?)), '\1[FILTERED]\2')
304
310
  end
305
311
 
306
312
  private
307
313
 
314
+ def add_aggregator(params, options)
315
+ if @options[:aggregator_id]
316
+ params[:aggregators] = 1
317
+ params[:aggregator1] = @options[:aggregator_id]
318
+ end
319
+ end
320
+
308
321
  def add_payment_source(params, source)
309
322
  if source.is_a?(String)
310
323
  add_billing_id(params, source)
324
+ elsif card_brand(source) == 'check'
325
+ add_check(params, source)
311
326
  else
312
327
  add_creditcard(params, source)
313
328
  end
314
329
  end
315
330
 
331
+ def add_check(params, check)
332
+ params[:media] = 'ach'
333
+ params[:routing] = check.routing_number
334
+ params[:account] = check.account_number
335
+ params[:savings] = 'y' if check.account_type == 'savings'
336
+ end
337
+
316
338
  def add_creditcard(params, creditcard)
317
339
  params[:media] = 'cc'
318
340
  params[:name] = creditcard.name
@@ -54,6 +54,9 @@ module ActiveMerchant #:nodoc:
54
54
  add_customer_data(post, options)
55
55
  end
56
56
  add_split_payments(post, options)
57
+ add_recurring_fields(post, options)
58
+ add_custom_fields(post, options)
59
+ add_line_items(post, options)
57
60
  add_test_mode(post, options)
58
61
 
59
62
  commit(:authorization, post)
@@ -70,6 +73,9 @@ module ActiveMerchant #:nodoc:
70
73
  add_customer_data(post, options)
71
74
  end
72
75
  add_split_payments(post, options)
76
+ add_recurring_fields(post, options)
77
+ add_custom_fields(post, options)
78
+ add_line_items(post, options)
73
79
  add_test_mode(post, options)
74
80
 
75
81
  payment.respond_to?(:routing_number) ? commit(:check_purchase, post) : commit(:purchase, post)
@@ -198,6 +204,7 @@ module ActiveMerchant #:nodoc:
198
204
  def add_payment(post, payment, options={})
199
205
  if payment.respond_to?(:routing_number)
200
206
  post[:checkformat] = options[:check_format] if options[:check_format]
207
+ post[:accounttype] = options[:account_type] if options[:account_type]
201
208
  post[:account] = payment.account_number
202
209
  post[:routing] = payment.routing_number
203
210
  post[:name] = payment.name unless payment.name.blank?
@@ -231,6 +238,50 @@ module ActiveMerchant #:nodoc:
231
238
  post['onError'] = options[:on_error] || 'Void'
232
239
  end
233
240
 
241
+ def add_recurring_fields(post, options)
242
+ return unless options[:recurring_fields].is_a?(Hash)
243
+ options[:recurring_fields].each do |key, value|
244
+ if value == true
245
+ value = 'yes'
246
+ elsif value == false
247
+ next
248
+ end
249
+
250
+ if key == :bill_amount
251
+ value = amount(value)
252
+ end
253
+
254
+ post[key.to_s.delete('_')] = value
255
+ end
256
+ end
257
+
258
+ # see: https://wiki.usaepay.com/developer/transactionapi#merchant_defined_custom_fields
259
+ def add_custom_fields(post, options)
260
+ return unless options[:custom_fields].is_a?(Hash)
261
+ options[:custom_fields].each do |index, custom|
262
+ post["custom#{index}"] = custom
263
+ end
264
+ end
265
+
266
+ # see: https://wiki.usaepay.com/developer/transactionapi#line_item_details
267
+ def add_line_items(post, options)
268
+ return unless options[:line_items].is_a?(Array)
269
+ options[:line_items].each_with_index do |line_item, index|
270
+ %w(product_ref_num sku name description taxable tax_rate tax_amount commodity_code discount_rate discount_amount).each do |key|
271
+ post["line#{index}#{key.delete('_')}"] = line_item[key.to_sym] if line_item.has_key?(key.to_sym)
272
+ end
273
+
274
+ {
275
+ quantity: 'qty',
276
+ unit: 'um',
277
+ }.each do |key, umkey|
278
+ post["line#{index}#{umkey}"] = line_item[key.to_sym] if line_item.has_key?(key.to_sym)
279
+ end
280
+
281
+ post["line#{index}cost"] = amount(line_item[:cost])
282
+ end
283
+ end
284
+
234
285
  def parse(body)
235
286
  fields = {}
236
287
  for line in body.split('&')
@@ -119,7 +119,7 @@ module ActiveMerchant #:nodoc:
119
119
  end
120
120
 
121
121
  def credit_request(money, payment_method, options)
122
- commit('credit', build_authorization_request(money, payment_method, options), :ok, options)
122
+ commit('credit', build_authorization_request(money, payment_method, options), :ok, 'SENT_FOR_REFUND', options)
123
123
  end
124
124
 
125
125
  def build_request
@@ -237,7 +237,7 @@ module ActiveMerchant #:nodoc:
237
237
  xml.tag! 'date', 'month' => format(payment_method.month, :two_digits), 'year' => format(payment_method.year, :four_digits)
238
238
  end
239
239
 
240
- xml.tag! 'cardHolderName', payment_method.name
240
+ xml.tag! 'cardHolderName', options[:execute_threed] ? '3D' : payment_method.name
241
241
  xml.tag! 'cvc', payment_method.verification_value
242
242
 
243
243
  add_address(xml, (options[:billing_address] || options[:address]))
@@ -1,3 +1,3 @@
1
1
  module ActiveMerchant
2
- VERSION = '1.88.0'
2
+ VERSION = '1.89.0'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activemerchant
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.88.0
4
+ version: 1.89.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tobias Luetke
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-12-04 00:00:00.000000000 Z
11
+ date: 2018-12-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -201,6 +201,7 @@ files:
201
201
  - lib/active_merchant/billing/gateways/ct_payment.rb
202
202
  - lib/active_merchant/billing/gateways/culqi.rb
203
203
  - lib/active_merchant/billing/gateways/cyber_source.rb
204
+ - lib/active_merchant/billing/gateways/d_local.rb
204
205
  - lib/active_merchant/billing/gateways/data_cash.rb
205
206
  - lib/active_merchant/billing/gateways/dibs.rb
206
207
  - lib/active_merchant/billing/gateways/digitzs.rb