activemerchant 1.68.0 → 1.69.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
  SHA1:
3
- metadata.gz: 3ed51178560acbebf43bedcb1e5ce966b279c04a
4
- data.tar.gz: fb02cd941337c8fb5a2e2ae2626a25d967e86750
3
+ metadata.gz: 18a666ef1305439841f07f349cea750f02d7f40f
4
+ data.tar.gz: eb8b0cd504e5f154d2834126601b626dd316df89
5
5
  SHA512:
6
- metadata.gz: d8fe0383adc62eb2a6af23bbe0ab0155d9121994fc7b9b0fe05f84ad7e521e3fe62db4814fb1efc02c8889e88fb561bba0807dc8133b3e39ad04d167d5b28c15
7
- data.tar.gz: 2159f015c245a4ebd0dc2ba57808884f08b2923271c951c8ffd4d0b581139d1426c0cadaa6f66bb6a26de4d63a12c2dcc26cd0adafc6ac51229c04668a05b640
6
+ metadata.gz: '09a7fded5ef8b8cfe0bd7744e0799a59064b550bc6f5ea7f2b5cc7208f49eec7b70e7cecd12e965c4053eaf7cab576facefd731dd1f0e9fad33d2df90042ad0b'
7
+ data.tar.gz: b6706229fd82c2be6f028f569987b724d284c6e32ed7b5ec79724035e628c9367233fb0576a13b8a3f37c1689d6e075090240c7724d2011e6ab0104f1e6050e1
data/CHANGELOG CHANGED
@@ -2,6 +2,24 @@
2
2
 
3
3
  == HEAD
4
4
 
5
+ == Version 1.69.0 (July 12, 2017)
6
+ * WePay: Add payer_rbits and transaction_rbits optional fields [davidsantoso]
7
+ * Adyen: Use Active Merchant standard order_id option for reference [jasonwebster] #2483
8
+ * Correct calculation for three-exponent currencies [curiousepic] #2486
9
+ * SagePay: Use VPSTxId from authorization for refunds [dtykocki] #2489
10
+ * Payflow: Move PAYPAL-NVP header option to a class attribute on the payment gateway [deuxpi] #2492
11
+ * Optimal Payments: Pass CVD indicator accurately [curiousepic] #2491
12
+ * SagePay: Make Repeat purchase if payment is a past authorization [curiousepic] #2495
13
+ * Netbanx: map response errorCodes onto standard error code [iirving] #2456
14
+ * Netbanx: Update supported countries and cardtypes [iirving] #2456
15
+ * Barclaycard Smartpay: Support 0- and 3-exponent currencies [curiousepic] #2498
16
+ * CyberSource: Fix XSD schema validation issues [jasonwebster] #2497
17
+ * WorldPay: Support three-decimal currencies [curiousepic] #2501
18
+ * NMI: Add first and lastname to echeck transactions [dtykocki] #2499
19
+ * PayFlow: Add optional email field [davidsantoso] #2505
20
+ * Worldpay: Support Credit on CFT-enabled merchant IDs [curiousepic] #2503
21
+ * FirstPay: Add processor_id field [davidsantoso] #2506
22
+
5
23
  == Version 1.68.0 (June 27, 2017)
6
24
  * Authorize.Net: Return failed response if forced refund settlement fails [bizla] #2476
7
25
  * Authorize.net: Concatenate address1 and address2 [dtykocki] #2479
@@ -280,9 +280,9 @@ module ActiveMerchant #:nodoc:
280
280
  end
281
281
  elsif three_decimal_currency?(currency)
282
282
  if self.money_format == :cents
283
- (amount.to_i * 10).to_s
283
+ amount.to_s
284
284
  else
285
- sprintf("%.3f", amount.to_f)
285
+ sprintf("%.3f", (amount.to_f / 10))
286
286
  end
287
287
  end
288
288
  end
@@ -40,7 +40,7 @@ module ActiveMerchant #:nodoc:
40
40
  end
41
41
 
42
42
  def authorize(money, payment, options={})
43
- requires!(options, :reference)
43
+ requires!(options, :order_id)
44
44
  post = init_post(options)
45
45
  add_invoice(post, money, options)
46
46
  add_payment(post, payment)
@@ -118,7 +118,7 @@ module ActiveMerchant #:nodoc:
118
118
  value: amount(money),
119
119
  currency: options[:currency] || currency(money)
120
120
  }
121
- post[:reference] = options[:reference]
121
+ post[:reference] = options[:order_id]
122
122
  post[:amount] = amount
123
123
  end
124
124
 
@@ -145,7 +145,7 @@ module ActiveMerchant #:nodoc:
145
145
 
146
146
  def add_references(post, authorization, options = {})
147
147
  post[:originalReference] = authorization
148
- post[:reference] = options[:reference]
148
+ post[:reference] = options[:order_id]
149
149
  end
150
150
 
151
151
  def parse(body)
@@ -6,6 +6,7 @@ module ActiveMerchant #:nodoc:
6
6
 
7
7
  self.supported_countries = ['AL', 'AD', 'AM', 'AT', 'AZ', 'BY', 'BE', 'BA', 'BG', 'HR', 'CY', 'CZ', 'DK', 'EE', 'FI', 'FR', 'GE', 'DE', 'GR', 'HU', 'IS', 'IE', 'IT', 'KZ', 'LV', 'LI', 'LT', 'LU', 'MK', 'MT', 'MD', 'MC', 'ME', 'NL', 'NO', 'PL', 'PT', 'RO', 'RU', 'SM', 'RS', 'SK', 'SI', 'ES', 'SE', 'CH', 'TR', 'UA', 'GB', 'VA']
8
8
  self.default_currency = 'EUR'
9
+ self.currencies_with_three_decimal_places = %w(BHD KWD OMR RSD TND)
9
10
  self.money_format = :cents
10
11
  self.supported_cardtypes = [:visa, :master, :american_express, :discover, :diners_club, :jcb, :dankort, :maestro]
11
12
 
@@ -238,9 +239,10 @@ module ActiveMerchant #:nodoc:
238
239
  end
239
240
 
240
241
  def amount_hash(money, currency)
242
+ currency = currency || currency(money)
241
243
  hash = {}
242
- hash[:currency] = currency || currency(money)
243
- hash[:value] = amount(money) if money
244
+ hash[:currency] = currency
245
+ hash[:value] = localized_amount(money, currency) if money
244
246
  hash
245
247
  end
246
248
 
@@ -258,6 +258,7 @@ module ActiveMerchant #:nodoc:
258
258
  add_decision_manager_fields(xml, options)
259
259
  add_mdd_fields(xml, options)
260
260
  add_auth_service(xml, creditcard_or_reference, options)
261
+ add_payment_network_token(xml) if network_tokenization?(creditcard_or_reference)
261
262
  add_business_rules_data(xml, creditcard_or_reference, options)
262
263
  xml.target!
263
264
  end
@@ -293,6 +294,7 @@ module ActiveMerchant #:nodoc:
293
294
  add_check_service(xml)
294
295
  else
295
296
  add_purchase_service(xml, payment_method_or_reference, options)
297
+ add_payment_network_token(xml) if network_tokenization?(payment_method_or_reference)
296
298
  add_business_rules_data(xml, payment_method_or_reference, options) unless options[:pinless_debit_card]
297
299
  end
298
300
  xml.target!
@@ -355,6 +357,7 @@ module ActiveMerchant #:nodoc:
355
357
  add_check_service(xml, options)
356
358
  else
357
359
  add_purchase_service(xml, payment_method, options)
360
+ add_payment_network_token(xml) if network_tokenization?(payment_method)
358
361
  end
359
362
  end
360
363
  add_subscription_create_service(xml, options)
@@ -471,6 +474,8 @@ module ActiveMerchant #:nodoc:
471
474
  end
472
475
 
473
476
  def add_decision_manager_fields(xml, options)
477
+ return unless options[:decision_manager_enabled]
478
+
474
479
  xml.tag! 'decisionManager' do
475
480
  xml.tag! 'enabled', options[:decision_manager_enabled] if options[:decision_manager_enabled]
476
481
  xml.tag! 'profile', options[:decision_manager_profile] if options[:decision_manager_profile]
@@ -478,6 +483,8 @@ module ActiveMerchant #:nodoc:
478
483
  end
479
484
 
480
485
  def add_mdd_fields(xml, options)
486
+ return unless options.keys.any? { |key| key.to_s.start_with?("mdd_field") }
487
+
481
488
  xml.tag! 'merchantDefinedData' do
482
489
  (1..100).each do |each|
483
490
  key = "mdd_field_#{each}".to_sym
@@ -503,7 +510,7 @@ module ActiveMerchant #:nodoc:
503
510
 
504
511
  def add_auth_service(xml, payment_method, options)
505
512
  if network_tokenization?(payment_method)
506
- add_network_tokenization(xml, payment_method, options)
513
+ add_auth_network_tokenization(xml, payment_method, options)
507
514
  else
508
515
  xml.tag! 'ccAuthService', {'run' => 'true'}
509
516
  end
@@ -513,7 +520,7 @@ module ActiveMerchant #:nodoc:
513
520
  payment_method.is_a?(NetworkTokenizationCreditCard)
514
521
  end
515
522
 
516
- def add_network_tokenization(xml, payment_method, options)
523
+ def add_auth_network_tokenization(xml, payment_method, options)
517
524
  return unless network_tokenization?(payment_method)
518
525
 
519
526
  case card_brand(payment_method).to_sym
@@ -539,9 +546,11 @@ module ActiveMerchant #:nodoc:
539
546
  xml.tag!("xid", Base64.encode64(cryptogram[20...40]))
540
547
  end
541
548
  end
549
+ end
542
550
 
551
+ def add_payment_network_token(xml)
543
552
  xml.tag! 'paymentNetworkToken' do
544
- xml.tag!('transactionType', "1")
553
+ xml.tag!('transactionType', '1')
545
554
  end
546
555
  end
547
556
 
@@ -67,6 +67,7 @@ module ActiveMerchant #:nodoc:
67
67
  def add_customer_data(post, options)
68
68
  post[:owner_email] = options[:email] if options[:email]
69
69
  post[:remote_ip_address] = options[:ip] if options[:ip]
70
+ post[:processor_id] = options[:processor_id] if options[:processor_id]
70
71
  end
71
72
 
72
73
  def add_address(post, creditcard, options)
@@ -5,16 +5,23 @@ module ActiveMerchant #:nodoc:
5
5
  self.test_url = 'https://api.test.netbanx.com/'
6
6
  self.live_url = 'https://api.netbanx.com/'
7
7
 
8
- self.supported_countries = ['CA', 'US', 'GB']
8
+ self.supported_countries = %w(AF AX AL DZ AS AD AO AI AQ AG AR AM AW AU AT AZ BS BH BD BB BY BE BZ BJ BM BT BO BQ BA BW BV BR IO BN BG BF BI KH CM CA CV KY CF TD CL CN CX CC CO KM CG CD CK CR CI HR CU CW CY CZ DK DJ DM DO EC EG SV GQ ER EE ET FK FO FJ FI FR GF PF TF GA GM GE DE GH GI GR GL GD GP GU GT GG GN GW GY HT HM HN HK HU IS IN ID IR IQ IE IM IL IT JM JP JE JO KZ KE KI KP KR KW KG LA LV LB LS LR LY LI LT LU MO MK MG MW MY MV ML MT MH MQ MR MU YT MX FM MD MC MN ME MS MA MZ MM NA NR NP NC NZ NI NE NG NU NF MP NO OM PK PW PS PA PG PY PE PH PN PL PT PR QA RE RO RU RW BL SH KN LC MF VC WS SM ST SA SN RS SC SL SG SX SK SI SB SO ZA GS SS ES LK PM SD SR SJ SZ SE CH SY TW TJ TZ TH NL TL TG TK TO TT TN TR TM TC TV UG UA AE GB US UM UY UZ VU VA VE VN VG VI WF EH YE ZM ZW)
9
9
  self.default_currency = 'CAD'
10
- self.supported_cardtypes = [:visa, :master, :american_express, :discover]
10
+ self.supported_cardtypes = [
11
+ :american_express,
12
+ :diners_club,
13
+ :discover,
14
+ :jcb,
15
+ :master,
16
+ :maestro,
17
+ :visa
18
+ ]
19
+
11
20
  self.money_format = :cents
12
21
 
13
22
  self.homepage_url = 'https://processing.paysafe.com/'
14
23
  self.display_name = 'Netbanx by PaySafe'
15
24
 
16
- STANDARD_ERROR_CODE_MAPPING = {}
17
-
18
25
  def initialize(options={})
19
26
  requires!(options, :account_number, :api_key)
20
27
  super
@@ -110,9 +117,6 @@ module ActiveMerchant #:nodoc:
110
117
  def add_customer_data(post, options)
111
118
  post[:merchantCustomerId] = (options[:merchant_customer_id] || SecureRandom.uuid)
112
119
  post[:locale] = options[:locale]
113
- # if options[:billing_address]
114
- # post[:address] = map_address(options[:billing_address])
115
- # end
116
120
  end
117
121
 
118
122
  def add_credit_card(post, credit_card, options = {})
@@ -192,6 +196,7 @@ module ActiveMerchant #:nodoc:
192
196
  message_from(success, response),
193
197
  response,
194
198
  :test => test?,
199
+ :error_code => error_code_from(response),
195
200
  :authorization => authorization_from(success, get_url(uri), method, response)
196
201
  )
197
202
  end
@@ -240,6 +245,48 @@ module ActiveMerchant #:nodoc:
240
245
  'User-Agent' => "Netbanx-Paysafe v1.0/ActiveMerchant #{ActiveMerchant::VERSION}"
241
246
  }
242
247
  end
248
+
249
+ def error_code_from(response)
250
+ unless success_from(response)
251
+ case response['errorCode']
252
+ when '3002' then STANDARD_ERROR_CODE[:invalid_number] # You submitted an invalid card number or brand or combination of card number and brand with your request.
253
+ when '3004' then STANDARD_ERROR_CODE[:incorrect_zip] # The zip/postal code must be provided for an AVS check request.
254
+ when '3005' then STANDARD_ERROR_CODE[:incorrect_cvc] # You submitted an incorrect CVC value with your request.
255
+ when '3006' then STANDARD_ERROR_CODE[:expired_card] # You submitted an expired credit card number with your request.
256
+ when '3009' then STANDARD_ERROR_CODE[:card_declined] # Your request has been declined by the issuing bank.
257
+ when '3011' then STANDARD_ERROR_CODE[:card_declined] # Your request has been declined by the issuing bank because the card used is a restricted card. Contact the cardholder's credit card company for further investigation.
258
+ when '3012' then STANDARD_ERROR_CODE[:card_declined] # Your request has been declined by the issuing bank because the credit card expiry date submitted is invalid.
259
+ when '3013' then STANDARD_ERROR_CODE[:card_declined] # Your request has been declined by the issuing bank due to problems with the credit card account.
260
+ when '3014' then STANDARD_ERROR_CODE[:card_declined] # Your request has been declined - the issuing bank has returned an unknown response. Contact the card holder's credit card company for further investigation.
261
+ when '3015' then STANDARD_ERROR_CODE[:card_declined] # The bank has requested that you process the transaction manually by calling the cardholder's credit card company.
262
+ when '3016' then STANDARD_ERROR_CODE[:card_declined] # The bank has requested that you retrieve the card from the cardholder – it may be a lost or stolen card.
263
+ when '3017' then STANDARD_ERROR_CODE[:invalid_number] # You submitted an invalid credit card number with your request.
264
+ when '3022' then STANDARD_ERROR_CODE[:card_declined] # The card has been declined due to insufficient funds.
265
+ when '3023' then STANDARD_ERROR_CODE[:card_declined] # Your request has been declined by the issuing bank due to its proprietary card activity regulations.
266
+ when '3024' then STANDARD_ERROR_CODE[:card_declined] # Your request has been declined because the issuing bank does not permit the transaction for this card.
267
+ when '3032' then STANDARD_ERROR_CODE[:card_declined] # Your request has been declined by the issuing bank or external gateway because the card is probably in one of their negative databases.
268
+ when '3035' then STANDARD_ERROR_CODE[:card_declined] # Your request has been declined due to exceeded PIN attempts.
269
+ when '3036' then STANDARD_ERROR_CODE[:card_declined] # Your request has been declined due to an invalid issuer.
270
+ when '3037' then STANDARD_ERROR_CODE[:card_declined] # Your request has been declined because it is invalid.
271
+ when '3038' then STANDARD_ERROR_CODE[:card_declined] # Your request has been declined due to customer cancellation.
272
+ when '3039' then STANDARD_ERROR_CODE[:card_declined] # Your request has been declined due to an invalid authentication value.
273
+ when '3040' then STANDARD_ERROR_CODE[:card_declined] # Your request has been declined because the request type is not permitted on the card.
274
+ when '3041' then STANDARD_ERROR_CODE[:card_declined] # Your request has been declined due to a timeout.
275
+ when '3042' then STANDARD_ERROR_CODE[:card_declined] # Your request has been declined due to a cryptographic error.
276
+ when '3045' then STANDARD_ERROR_CODE[:invalid_expiry_date] # You submitted an invalid date format for this request.
277
+ when '3046' then STANDARD_ERROR_CODE[:card_declined] # The transaction was declined because the amount was set to zero.
278
+ when '3047' then STANDARD_ERROR_CODE[:card_declined] # The transaction was declined because the amount exceeds the floor limit.
279
+ when '3048' then STANDARD_ERROR_CODE[:card_declined] # The transaction was declined because the amount is less than the floor limit.
280
+ when '3049' then STANDARD_ERROR_CODE[:card_declined] # The bank has requested that you retrieve the card from the cardholder – the credit card has expired.
281
+ when '3050' then STANDARD_ERROR_CODE[:card_declined] # The bank has requested that you retrieve the card from the cardholder – fraudulent activity is suspected.
282
+ when '3051' then STANDARD_ERROR_CODE[:card_declined] # The bank has requested that you retrieve the card from the cardholder – contact the acquirer for more information.
283
+ when '3052' then STANDARD_ERROR_CODE[:card_declined] # The bank has requested that you retrieve the card from the cardholder – the credit card is restricted.
284
+ when '3053' then STANDARD_ERROR_CODE[:card_declined] # The bank has requested that you retrieve the card from the cardholder – please call the acquirer.
285
+ when '3054' then STANDARD_ERROR_CODE[:card_declined] # The transaction was declined due to suspected fraud.
286
+ else STANDARD_ERROR_CODE[:processing_error]
287
+ end
288
+ end
289
+ end
243
290
  end
244
291
  end
245
292
  end
@@ -146,6 +146,8 @@ module ActiveMerchant #:nodoc:
146
146
  post[:token_cryptogram] = payment_method.payment_cryptogram
147
147
  elsif(card_brand(payment_method) == 'check')
148
148
  post[:payment] = 'check'
149
+ post[:firstname] = payment_method.first_name
150
+ post[:lastname] = payment_method.last_name
149
151
  post[:checkname] = payment_method.name
150
152
  post[:checkaba] = payment_method.routing_number
151
153
  post[:checkaccount] = payment_method.account_number
@@ -259,9 +259,11 @@ module ActiveMerchant #:nodoc:
259
259
  if brand = card_type(@credit_card.brand)
260
260
  xml.tag! 'cardType' , brand
261
261
  end
262
- if @credit_card.verification_value
262
+ if @credit_card.verification_value?
263
263
  xml.tag! 'cvdIndicator' , '1' # Value Provided
264
264
  xml.tag! 'cvd' , @credit_card.verification_value
265
+ else
266
+ xml.tag! 'cvdIndicator' , '0'
265
267
  end
266
268
  end
267
269
  end
@@ -152,6 +152,7 @@ module ActiveMerchant #:nodoc:
152
152
  xml.tag! 'FreightAmt', options[:freightamt] unless options[:freightamt].blank?
153
153
  xml.tag! 'DutyAmt', options[:dutyamt] unless options[:dutyamt].blank?
154
154
  xml.tag! 'DiscountAmt', options[:discountamt] unless options[:discountamt].blank?
155
+ xml.tag! 'EMail', options[:email] unless options[:email].nil?
155
156
 
156
157
  billing_address = options[:billing_address] || options[:address]
157
158
  add_address(xml, 'BillTo', billing_address, options) if billing_address
@@ -25,6 +25,13 @@ module ActiveMerchant #:nodoc:
25
25
  # subsequent Responses will have a :duplicate parameter set in the params
26
26
  # hash.
27
27
  base.retry_safe = true
28
+
29
+ # Send Payflow requests to PayPal directly by activating the NVP protocol.
30
+ # Valid XMLPay documents may have issues being parsed correctly by
31
+ # Payflow but will be accepted by PayPal if a PAYPAL-NVP request header
32
+ # is declared.
33
+ base.class_attribute :use_paypal_nvp
34
+ base.use_paypal_nvp = false
28
35
  end
29
36
 
30
37
  XMLNS = 'http://www.paypal.com/XMLPay'
@@ -180,7 +187,7 @@ module ActiveMerchant #:nodoc:
180
187
  end
181
188
  end
182
189
 
183
- def build_headers(content_length, options = {})
190
+ def build_headers(content_length)
184
191
  headers = {
185
192
  "Content-Type" => "text/xml",
186
193
  "Content-Length" => content_length.to_s,
@@ -190,13 +197,13 @@ module ActiveMerchant #:nodoc:
190
197
  "X-VPS-Request-ID" => SecureRandom.hex(16)
191
198
  }
192
199
 
193
- headers.merge!("PAYPAL-NVP" => options[:paypal_nvp]) if options[:paypal_nvp]
200
+ headers.merge!("PAYPAL-NVP" => "Y") if self.use_paypal_nvp
194
201
  headers
195
202
  end
196
203
 
197
204
  def commit(request_body, options = {})
198
205
  request = build_request(request_body, options)
199
- headers = build_headers(request.size, options)
206
+ headers = build_headers(request.size)
200
207
 
201
208
  response = parse(ssl_post(test? ? self.test_url : self.live_url, request, headers))
202
209
 
@@ -88,7 +88,7 @@ module ActiveMerchant #:nodoc:
88
88
  add_customer_data(post, options)
89
89
  add_optional_data(post, options)
90
90
 
91
- commit((options[:repeat] ? :repeat : :purchase), post)
91
+ commit((past_purchase_reference?(payment_method) ? :repeat : :purchase), post)
92
92
  end
93
93
 
94
94
  def authorize(money, payment_method, options = {})
@@ -268,12 +268,14 @@ module ActiveMerchant #:nodoc:
268
268
  end
269
269
 
270
270
  def add_payment_method(post, payment_method, options)
271
- if options[:repeat]
272
- add_related_reference(post, payment_method)
273
- elsif payment_method.respond_to?(:number)
274
- add_credit_card(post, payment_method)
271
+ if payment_method.is_a?(String)
272
+ if past_purchase_reference?(payment_method)
273
+ add_related_reference(post, payment_method)
274
+ else
275
+ add_token_details(post, payment_method, options)
276
+ end
275
277
  else
276
- add_token_details(post, payment_method, options)
278
+ add_credit_card(post, payment_method)
277
279
  end
278
280
  end
279
281
 
@@ -359,9 +361,9 @@ module ActiveMerchant #:nodoc:
359
361
  response['Token']
360
362
  else
361
363
  [ params[:VendorTxCode],
362
- response["VPSTxId"],
364
+ response["VPSTxId"] || params[:VPSTxId],
363
365
  response["TxAuthNo"],
364
- response["SecurityKey"],
366
+ response["SecurityKey"] || params[:SecurityKey],
365
367
  action ].join(";")
366
368
  end
367
369
  end
@@ -422,6 +424,10 @@ module ActiveMerchant #:nodoc:
422
424
  post[key] = value if !value.blank? || options[:required]
423
425
  end
424
426
 
427
+ def past_purchase_reference?(payment_method)
428
+ return false unless payment_method.is_a?(String)
429
+ payment_method.split(';').last == 'purchase'
430
+ end
425
431
  end
426
432
 
427
433
  end
@@ -148,6 +148,8 @@ module ActiveMerchant #:nodoc:
148
148
  post[:preapproval_id] = options[:preapproval_id] if options[:preapproval_id]
149
149
  post[:prefill_info] = options[:prefill_info] if options[:prefill_info]
150
150
  post[:funding_sources] = options[:funding_sources] if options[:funding_sources]
151
+ post[:payer_rbits] = options[:payer_rbits] if options[:payer_rbits]
152
+ post[:transaction_rbits] = options[:transaction_rbits] if options[:transaction_rbits]
151
153
  add_fee(post, options)
152
154
  end
153
155
 
@@ -9,6 +9,7 @@ module ActiveMerchant #:nodoc:
9
9
  self.supported_countries = %w(HK GB AU AD BE CH CY CZ DE DK ES FI FR GI GR HU IE IL IT LI LU MC MT NL NO NZ PL PT SE SG SI SM TR UM VA)
10
10
  self.supported_cardtypes = [:visa, :master, :american_express, :discover, :jcb, :maestro, :laser, :switch]
11
11
  self.currencies_without_fractions = %w(HUF IDR ISK JPY KRW)
12
+ self.currencies_with_three_decimal_places = %w(BHD KWD OMR RSD TND)
12
13
  self.homepage_url = 'http://www.worldpay.com/'
13
14
  self.display_name = 'Worldpay Global'
14
15
 
@@ -71,6 +72,14 @@ module ActiveMerchant #:nodoc:
71
72
  void(authorization, options ) if response.params["last_event"] == "AUTHORISED"
72
73
  end
73
74
 
75
+ # Credits only function on a Merchant ID/login/profile flagged for Payouts
76
+ # aka Credit Fund Transfers (CFT), whereas normal purchases, refunds,
77
+ # and other transactions should be performed on a normal eCom-flagged
78
+ # merchant ID.
79
+ def credit(money, payment_method, options = {})
80
+ credit_request(money, payment_method, options.merge(:credit => true))
81
+ end
82
+
74
83
  def verify(credit_card, options={})
75
84
  MultiResponse.run(:use_first_response) do |r|
76
85
  r.process { authorize(100, credit_card, options) }
@@ -111,6 +120,10 @@ module ActiveMerchant #:nodoc:
111
120
  commit('refund', build_refund_request(money, authorization, options), :ok)
112
121
  end
113
122
 
123
+ def credit_request(money, payment_method, options)
124
+ commit('credit', build_authorization_request(money, payment_method, options), :ok)
125
+ end
126
+
114
127
  def build_request
115
128
  xml = Builder::XmlMarkup.new :indent => 2
116
129
  xml.instruct! :xml, :encoding => 'UTF-8'
@@ -194,7 +207,7 @@ module ActiveMerchant #:nodoc:
194
207
  amount_hash = {
195
208
  :value => localized_amount(money, currency),
196
209
  'currencyCode' => currency,
197
- 'exponent' => non_fractional_currency?(currency) ? 0 : 2
210
+ 'exponent' => currency_exponent(currency)
198
211
  }
199
212
 
200
213
  if options[:debit_credit_indicator]
@@ -216,7 +229,7 @@ module ActiveMerchant #:nodoc:
216
229
  end
217
230
  end
218
231
  else
219
- xml.tag! 'paymentDetails' do
232
+ xml.tag! 'paymentDetails', credit_fund_transfer_attribute(options) do
220
233
  xml.tag! CARD_CODES[card_brand(payment_method)] do
221
234
  xml.tag! 'cardNumber', payment_method.number
222
235
  xml.tag! 'expiryDate' do
@@ -365,10 +378,21 @@ module ActiveMerchant #:nodoc:
365
378
  (pair ? pair.last : nil)
366
379
  end
367
380
 
381
+ def credit_fund_transfer_attribute(options)
382
+ return unless options[:credit]
383
+ {'action' => "REFUND"}
384
+ end
385
+
368
386
  def encoded_credentials
369
387
  credentials = "#{@options[:login]}:#{@options[:password]}"
370
388
  "Basic #{[credentials].pack('m').strip}"
371
389
  end
390
+
391
+ def currency_exponent(currency)
392
+ return 0 if non_fractional_currency?(currency)
393
+ return 3 if three_decimal_currency?(currency)
394
+ return 2
395
+ end
372
396
  end
373
397
  end
374
398
  end
@@ -1,3 +1,3 @@
1
1
  module ActiveMerchant
2
- VERSION = "1.68.0"
2
+ VERSION = "1.69.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.68.0
4
+ version: 1.69.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: 2017-06-28 00:00:00.000000000 Z
11
+ date: 2017-07-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport