activemerchant 1.88.0 → 1.89.0

Sign up to get free protection for your applications and to get access to all the features.
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