activemerchant 1.97.0 → 1.98.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: 5d0f7d776b87d565598558755d845eb264dbee972e2076cb73bca68c4ee33c78
4
- data.tar.gz: d08dd14ebabb954845e8a8b951b1ebb66c6d92e1148f4b4187cbe5e47b8cbd36
3
+ metadata.gz: acfbb780d39dd416b823a9abef4cdcf4de902ec75210ed78e6771314d00b069b
4
+ data.tar.gz: 95e9bf94b3610b33d843fd82af8e4f204380e7c53557d24141b654c553160d9f
5
5
  SHA512:
6
- metadata.gz: 879f72d1da257d47280e668b29238481031287c534868458029f31ffc8bf9498c3385cc90794e2f9391f3c74854b29a4a6d52ce43bb7b51e1d2b1d6f08379ccc
7
- data.tar.gz: 70d1898a7869e96841d29d102a44e5b9b5da34c5685185f8a6e57901123af3e81a26f7889a75d942553b8dd8eb83b70c4ac4515e96ad6f7460ccb816d9801394
6
+ metadata.gz: 6222cdad43482972e2a799981936dc1d8114ccbede88604880d350650f7b81422b6551a07375dd1a7e06ef562d4f128c332dabc2fc16ebb7b635f774de18a54e
7
+ data.tar.gz: 2f9fe3fe9dfe17fc045f0a3e97940ae4b38a461c48f0416a26ed4b5a4e2bb549464911fbe7527392c8dfbcbbee16bfa82266e3ad644060199ee9552b5b82659b
data/CHANGELOG CHANGED
@@ -1,6 +1,35 @@
1
1
  = ActiveMerchant CHANGELOG
2
2
 
3
3
  == HEAD
4
+ == Version 1.98.0 (Sep 9, 2019)
5
+ * Stripe Payment Intents: Add new gateway [britth] #3290
6
+ * Stripe: Send cardholder name and address when creating sources for 3DS 1.0 [jknipp] #3300
7
+ * Checkout_v2: Support for native 3DS2.0 [nfarve] #3303
8
+ * Adds new Maestro BINs [tanyajajodia] #3305
9
+ * eWAY Rapid: If no address is available, default to the name associated with the payment method when setting the Customer fields [jasonxp] #3306
10
+ * eWAY Rapid: Fix a bug in which the email was not set in Customer fields if no address was provided [jasonxp] #3306
11
+ * eWAY Rapid: Support both `phone` and `phone_number` fields under the `shipping_address` option [jasonxp] #3306
12
+ * PayU Latam: Add support for the `merchant_buyer_id` field in the `options` and `buyer` hashes [jasonxp] #3308
13
+ * Update Braintree Gem [curiousepic] #3311
14
+ * Fat Zebra: Send metadata for purchase and authorize [montdidier] #3101
15
+ * TrustCommerce: Add support for custom fields [jasonxp] #3313
16
+ * Stripe Payment Intents: Support option fields `transfer_destination` and `transfer_amount` and remove `transfer_data` hash [britth] #3317
17
+ * Barclaycard Smartpay: Add support for `shopperStatement` gateway-specific field [jasonxp] #3319
18
+ * Stripe Payment Intents: Add support for billing_details on payment methods [britth] #3320
19
+ * BlueSnap: add standardized 3DS 2 auth fields [bayprogrammer] #3318
20
+ * Barclaycard Smartpay: Add app based 3DS requests for auth and purchase [britth] #3327
21
+ * Stripe Payment Intents, Checkout V2: Add support for `MOTO` flagging [britth] #3323
22
+ * Braintree Blue: Adding 3DS2 passthru support [molbrown] #3328
23
+ * Global Collect: Add Cabal card [leila-alderman] #3310
24
+ * WorldPay: Add Cabal card [leila-alderman] #3316
25
+ * Decidir: Add Cabal card [leila-alderman] #3322
26
+ * PayU Latam: Add Cabal card [leila-alderman] #3324
27
+ * dLocal: Add Cabal card [leila-alderman] #3325
28
+ * BlueSnap: Add Cabal card [leila-alderman] #3326
29
+ * Adyen: added 3DS support through external [rikterbeek] #3294
30
+ * Worldpay: Add support for MOTO flagging [britth] #3329
31
+ * ePay: 3DS support [AllaWLie] #3321
32
+ * Checkout.com: added options[:metadata][:manual_entry] support for MOTO transactions [filipebarcos] #3330
4
33
 
5
34
  == Version 1.97.0 (Aug 15, 2019)
6
35
  * CyberSource: Add issuer `additionalData` gateway-specific field [jasonxp] #3296
@@ -206,6 +235,7 @@
206
235
  * Forte: Allow void on capture [nfarve] #3059
207
236
 
208
237
  == Version 1.86.0 (October 26, 2018)
238
+ * UsaEpayTransaction: Support UMcheckformat option for echecks [dtykocki] #3002
209
239
  * Global Collect: handle internal server errors [molbrown] #3005
210
240
  * Barclaycard Smartpay: allow third-party payouts for credits [bpollack] #3009
211
241
  * RuboCop: AlignHash [nfarve] #3004
@@ -66,6 +66,24 @@ module ActiveMerchant #:nodoc:
66
66
 
67
67
  # https://www.mastercard.us/content/dam/mccom/global/documents/mastercard-rules.pdf, page 73
68
68
  MAESTRO_RANGES = [
69
+ (561200..561269),
70
+ (561271..561299),
71
+ (561320..561356),
72
+ (581700..581751),
73
+ (581753..581800),
74
+ (589998..591259),
75
+ (591261..596770),
76
+ (596772..598744),
77
+ (598746..599999),
78
+ (600297..600314),
79
+ (600316..600335),
80
+ (600337..600362),
81
+ (600364..600382),
82
+ (601232..601254),
83
+ (601256..601276),
84
+ (601640..601652),
85
+ (601689..601700),
86
+ (602011..602050),
69
87
  (639000..639099),
70
88
  (670000..679999),
71
89
  ]
@@ -56,6 +56,7 @@ module ActiveMerchant #:nodoc:
56
56
  add_address(post, options)
57
57
  add_installments(post, options) if options[:installments]
58
58
  add_3ds(post, options)
59
+ add_3ds_authenticated_data(post, options)
59
60
  commit('authorise', post, options)
60
61
  end
61
62
 
@@ -342,6 +343,44 @@ module ActiveMerchant #:nodoc:
342
343
  end
343
344
  end
344
345
 
346
+ def add_3ds_authenticated_data(post, options)
347
+ if options[:three_d_secure] && options[:three_d_secure][:eci] && options[:three_d_secure][:xid]
348
+ add_3ds1_authenticated_data(post, options)
349
+ elsif options[:three_d_secure]
350
+ add_3ds2_authenticated_data(post, options)
351
+ end
352
+ end
353
+
354
+ def add_3ds1_authenticated_data(post, options)
355
+ three_d_secure_options = options[:three_d_secure]
356
+ post[:mpiData] = {
357
+ cavv: three_d_secure_options[:cavv],
358
+ cavvAlgorithm: three_d_secure_options[:cavv_algorithm],
359
+ eci: three_d_secure_options[:eci],
360
+ xid: three_d_secure_options[:xid],
361
+ directoryResponse: three_d_secure_options[:directory_response_status],
362
+ authenticationResponse: three_d_secure_options[:authentication_response_status]
363
+ }
364
+ end
365
+
366
+ def add_3ds2_authenticated_data(post, options)
367
+ three_d_secure_options = options[:three_d_secure]
368
+ # If the transaction was authenticated in a frictionless flow, send the transStatus from the ARes.
369
+ if(three_d_secure_options[:authentication_response_status].nil?)
370
+ authentication_response = three_d_secure_options[:directory_response_status]
371
+ else
372
+ authentication_response = three_d_secure_options[:authentication_response_status]
373
+ end
374
+ post[:mpiData] = {
375
+ threeDSVersion: three_d_secure_options[:version],
376
+ eci: three_d_secure_options[:eci],
377
+ cavv: three_d_secure_options[:cavv],
378
+ dsTransID: three_d_secure_options[:ds_transaction_id],
379
+ directoryResponse: three_d_secure_options[:directory_response_status],
380
+ authenticationResponse: authentication_response
381
+ }
382
+ end
383
+
345
384
  def parse(body)
346
385
  return {} if body.blank?
347
386
  JSON.parse(body)
@@ -37,6 +37,8 @@ module ActiveMerchant #:nodoc:
37
37
  post[:card] = credit_card_hash(creditcard)
38
38
  post[:billingAddress] = billing_address_hash(options) if options[:billing_address]
39
39
  post[:deliveryAddress] = shipping_address_hash(options) if options[:shipping_address]
40
+ post[:shopperStatement] = options[:shopper_statement] if options[:shopper_statement]
41
+
40
42
  add_3ds(post, options)
41
43
  commit('authorise', post)
42
44
  end
@@ -350,24 +352,12 @@ module ActiveMerchant #:nodoc:
350
352
 
351
353
  def add_3ds(post, options)
352
354
  if three_ds_2_options = options[:three_ds_2]
353
- if browser_info = three_ds_2_options[:browser_info]
354
- post[:browserInfo] = {
355
- acceptHeader: browser_info[:accept_header],
356
- colorDepth: browser_info[:depth],
357
- javaEnabled: browser_info[:java],
358
- language: browser_info[:language],
359
- screenHeight: browser_info[:height],
360
- screenWidth: browser_info[:width],
361
- timeZoneOffset: browser_info[:timezone],
362
- userAgent: browser_info[:user_agent]
363
- }
364
-
365
- if device_channel = three_ds_2_options[:channel]
366
- post[:threeDS2RequestData] = {
367
- deviceChannel: device_channel,
368
- notificationURL: three_ds_2_options[:notification_url]
369
- }
370
- end
355
+ device_channel = three_ds_2_options[:channel]
356
+ if device_channel == 'app'
357
+ post[:threeDS2RequestData] = { deviceChannel: device_channel }
358
+ else
359
+ add_browser_info(three_ds_2_options[:browser_info], post)
360
+ post[:threeDS2RequestData] = { deviceChannel: device_channel, notificationURL: three_ds_2_options[:notification_url] }
371
361
  end
372
362
  else
373
363
  return unless options[:execute_threed] || options[:threed_dynamic]
@@ -375,6 +365,20 @@ module ActiveMerchant #:nodoc:
375
365
  post[:additionalData] = { executeThreeD: 'true' } if options[:execute_threed]
376
366
  end
377
367
  end
368
+
369
+ def add_browser_info(browser_info, post)
370
+ return unless browser_info
371
+ post[:browserInfo] = {
372
+ acceptHeader: browser_info[:accept_header],
373
+ colorDepth: browser_info[:depth],
374
+ javaEnabled: browser_info[:java],
375
+ language: browser_info[:language],
376
+ screenHeight: browser_info[:height],
377
+ screenWidth: browser_info[:width],
378
+ timeZoneOffset: browser_info[:timezone],
379
+ userAgent: browser_info[:user_agent]
380
+ }
381
+ end
378
382
  end
379
383
  end
380
384
  end
@@ -8,7 +8,7 @@ module ActiveMerchant
8
8
  self.supported_countries = %w(US CA GB AT BE BG HR CY CZ DK EE FI FR DE GR HU IE IT LV LT LU MT NL PL PT RO SK SI ES SE AR BO BR BZ CL CO CR DO EC GF GP GT HN HT MF MQ MX NI PA PE PR PY SV UY VE)
9
9
 
10
10
  self.default_currency = 'USD'
11
- self.supported_cardtypes = [:visa, :master, :american_express, :discover, :jcb, :diners_club, :maestro, :naranja]
11
+ self.supported_cardtypes = [:visa, :master, :american_express, :discover, :jcb, :diners_club, :maestro, :naranja, :cabal]
12
12
 
13
13
  self.homepage_url = 'https://home.bluesnap.com/'
14
14
  self.display_name = 'BlueSnap'
@@ -223,6 +223,7 @@ module ActiveMerchant
223
223
  doc.send('merchant-transaction-id', truncate(options[:order_id], 50)) if options[:order_id]
224
224
  doc.send('soft-descriptor', options[:soft_descriptor]) if options[:soft_descriptor]
225
225
  add_description(doc, options[:description]) if options[:description]
226
+ add_3ds(doc, options[:three_d_secure]) if options[:three_d_secure]
226
227
  add_level_3_data(doc, options)
227
228
  end
228
229
 
@@ -237,6 +238,22 @@ module ActiveMerchant
237
238
  doc.zip(address[:zip]) if address[:zip]
238
239
  end
239
240
 
241
+ def add_3ds(doc, three_d_secure_options)
242
+ eci = three_d_secure_options[:eci]
243
+ cavv = three_d_secure_options[:cavv]
244
+ xid = three_d_secure_options[:xid]
245
+ ds_transaction_id = three_d_secure_options[:ds_transaction_id]
246
+ version = three_d_secure_options[:version]
247
+
248
+ doc.send('three-d-secure') do
249
+ doc.eci(eci) if eci
250
+ doc.cavv(cavv) if cavv
251
+ doc.xid(xid) if xid
252
+ doc.send('three-d-secure-version', version) if version
253
+ doc.send('ds-transaction-id', ds_transaction_id) if ds_transaction_id
254
+ end
255
+ end
256
+
240
257
  def add_level_3_data(doc, options)
241
258
  return unless options[:customer_reference_number]
242
259
  doc.send('level-3-data') do
@@ -630,13 +630,7 @@ module ActiveMerchant #:nodoc:
630
630
  }
631
631
  end
632
632
 
633
- if options[:three_d_secure]
634
- parameters[:three_d_secure_pass_thru] = {
635
- cavv: options[:three_d_secure][:cavv],
636
- eci_flag: options[:three_d_secure][:eci],
637
- xid: options[:three_d_secure][:xid],
638
- }
639
- end
633
+ add_3ds_info(parameters, options[:three_d_secure])
640
634
 
641
635
  parameters[:tax_amount] = options[:tax_amount] if options[:tax_amount]
642
636
  parameters[:tax_exempt] = options[:tax_exempt] if options[:tax_exempt]
@@ -651,6 +645,28 @@ module ActiveMerchant #:nodoc:
651
645
  parameters
652
646
  end
653
647
 
648
+ def add_3ds_info(parameters, three_d_secure_opts)
649
+ return if empty?(three_d_secure_opts)
650
+ pass_thru = {}
651
+
652
+ pass_thru[:three_d_secure_version] = three_d_secure_opts[:version] if three_d_secure_opts[:version]
653
+ pass_thru[:eci_flag] = three_d_secure_opts[:eci] if three_d_secure_opts[:eci]
654
+ pass_thru[:cavv_algorithm] = three_d_secure_opts[:cavv_algorithm] if three_d_secure_opts[:cavv_algorithm]
655
+ pass_thru[:cavv] = three_d_secure_opts[:cavv] if three_d_secure_opts[:cavv]
656
+ pass_thru[:directory_response] = three_d_secure_opts[:directory_response_status] if three_d_secure_opts[:directory_response_status]
657
+ pass_thru[:authentication_response] = three_d_secure_opts[:authentication_response_status] if three_d_secure_opts[:authentication_response_status]
658
+
659
+ parameters[:three_d_secure_pass_thru] = pass_thru.merge(xid_or_ds_trans_id(three_d_secure_opts))
660
+ end
661
+
662
+ def xid_or_ds_trans_id(three_d_secure_opts)
663
+ if three_d_secure_opts[:version].to_f >= 2
664
+ { ds_transaction_id: three_d_secure_opts[:ds_transaction_id] }
665
+ else
666
+ { xid: three_d_secure_opts[:xid] }
667
+ end
668
+ end
669
+
654
670
  def add_stored_credential_data(parameters, credit_card_or_vault_id, options)
655
671
  return unless (stored_credential = options[:stored_credential])
656
672
  parameters[:external_vault] = {}
@@ -68,6 +68,10 @@ module ActiveMerchant #:nodoc:
68
68
  end
69
69
  end
70
70
 
71
+ def verify_payment(authorization, option={})
72
+ commit(:verify_payment, authorization)
73
+ end
74
+
71
75
  def supports_scrubbing?
72
76
  true
73
77
  end
@@ -124,13 +128,19 @@ module ActiveMerchant #:nodoc:
124
128
  def add_transaction_data(post, options = {})
125
129
  post[:payment_type] = 'Regular' if options[:transaction_indicator] == 1
126
130
  post[:payment_type] = 'Recurring' if options[:transaction_indicator] == 2
131
+ post[:payment_type] = 'MOTO' if options[:transaction_indicator] == 3 || options.dig(:metadata, :manual_entry)
127
132
  post[:previous_payment_id] = options[:previous_charge_id] if options[:previous_charge_id]
128
133
  end
129
134
 
130
135
  def add_3ds(post, options)
131
- if options[:three_d_secure]
136
+ if options[:three_d_secure] || options[:execute_threed]
132
137
  post[:'3ds'] = {}
133
138
  post[:'3ds'][:enabled] = true
139
+ post[:success_url] = options[:callback_url] if options[:callback_url]
140
+ post[:failure_url] = options[:callback_url] if options[:callback_url]
141
+ end
142
+
143
+ if options[:three_d_secure]
134
144
  post[:'3ds'][:eci] = options[:three_d_secure][:eci] if options[:three_d_secure][:eci]
135
145
  post[:'3ds'][:cryptogram] = options[:three_d_secure][:cavv] if options[:three_d_secure][:cavv]
136
146
  post[:'3ds'][:version] = options[:three_d_secure][:version] if options[:three_d_secure][:version]
@@ -140,7 +150,7 @@ module ActiveMerchant #:nodoc:
140
150
 
141
151
  def commit(action, post, authorization = nil)
142
152
  begin
143
- raw_response = ssl_post(url(post, action, authorization), post.to_json, headers)
153
+ raw_response = (action == :verify_payment ? ssl_get("#{base_url}/payments/#{post}", headers) : ssl_post(url(post, action, authorization), post.to_json, headers))
144
154
  response = parse(raw_response)
145
155
  if action == :capture && response.key?('_links')
146
156
  response['id'] = response['_links']['payment']['href'].split('/')[-1]
@@ -215,7 +225,7 @@ module ActiveMerchant #:nodoc:
215
225
  end
216
226
 
217
227
  def success_from(response)
218
- response['response_summary'] == 'Approved' || !response.key?('response_summary') && response.key?('action_id')
228
+ response['response_summary'] == 'Approved' || response['approved'] == true || !response.key?('response_summary') && response.key?('action_id')
219
229
  end
220
230
 
221
231
  def message_from(succeeded, response)
@@ -6,7 +6,7 @@ module ActiveMerchant #:nodoc:
6
6
 
7
7
  self.supported_countries = ['AR', 'BR', 'CL', 'CO', 'MX', 'PE', 'UY', 'TR']
8
8
  self.default_currency = 'USD'
9
- self.supported_cardtypes = [:visa, :master, :american_express, :discover, :jcb, :diners_club, :maestro, :naranja]
9
+ self.supported_cardtypes = [:visa, :master, :american_express, :discover, :jcb, :diners_club, :maestro, :naranja, :cabal]
10
10
 
11
11
  self.homepage_url = 'https://dlocal.com/'
12
12
  self.display_name = 'dLocal'
@@ -7,7 +7,7 @@ module ActiveMerchant #:nodoc:
7
7
  self.supported_countries = ['AR']
8
8
  self.money_format = :cents
9
9
  self.default_currency = 'ARS'
10
- self.supported_cardtypes = [:visa, :master, :american_express, :diners_club]
10
+ self.supported_cardtypes = [:visa, :master, :american_express, :diners_club, :naranja, :cabal]
11
11
 
12
12
  self.homepage_url = 'http://www.decidir.com'
13
13
  self.display_name = 'Decidir'
@@ -99,7 +99,8 @@ module ActiveMerchant #:nodoc:
99
99
  transcript.
100
100
  gsub(%r((apikey: )\w+)i, '\1[FILTERED]').
101
101
  gsub(%r((\"card_number\\\":\\\")\d+), '\1[FILTERED]').
102
- gsub(%r((\"security_code\\\":\\\")\d+), '\1[FILTERED]')
102
+ gsub(%r((\"security_code\\\":\\\")\d+), '\1[FILTERED]').
103
+ gsub(%r((\"emv_issuer_data\\\":\\\")\d+), '\1[FILTERED]')
103
104
  end
104
105
 
105
106
  private
@@ -63,6 +63,7 @@ module ActiveMerchant #:nodoc:
63
63
  add_invoice(post, options)
64
64
  add_creditcard_or_reference(post, credit_card_or_reference)
65
65
  add_instant_capture(post, false)
66
+ add_3ds_auth(post, options)
66
67
 
67
68
  commit(:authorize, post)
68
69
  end
@@ -74,6 +75,7 @@ module ActiveMerchant #:nodoc:
74
75
  add_creditcard_or_reference(post, credit_card_or_reference)
75
76
  add_invoice(post, options)
76
77
  add_instant_capture(post, true)
78
+ add_3ds_auth(post, options)
77
79
 
78
80
  commit(:authorize, post)
79
81
  end
@@ -158,6 +160,16 @@ module ActiveMerchant #:nodoc:
158
160
  post[:instantcapture] = option ? 1 : 0
159
161
  end
160
162
 
163
+ def add_3ds_auth(post, options)
164
+ if options[:three_d_secure]
165
+ post[:eci] = options.dig(:three_d_secure, :eci)
166
+ post[:xid] = options.dig(:three_d_secure, :xid)
167
+ post[:cavv] = options.dig(:three_d_secure, :cavv)
168
+ post[:threeds_version] = options.dig(:three_d_secure, :version)
169
+ post[:ds_transaction_id] = options.dig(:three_d_secure, :ds_transaction_id)
170
+ end
171
+ end
172
+
161
173
  def commit(action, params)
162
174
  response = send("do_#{action}", params)
163
175
 
@@ -193,7 +205,6 @@ module ActiveMerchant #:nodoc:
193
205
  headers['Referer'] = (options[:password] || 'activemerchant.org')
194
206
 
195
207
  response = raw_ssl_request(:post, live_url + 'auth/default.aspx', authorize_post_data(params), headers)
196
-
197
208
  # Authorize gives the response back by redirecting with the values in
198
209
  # the URL query
199
210
  if location = response['Location']
@@ -268,7 +279,7 @@ module ActiveMerchant #:nodoc:
268
279
 
269
280
  def authorize_post_data(params = {})
270
281
  params[:language] = '2'
271
- params[:cms] = 'activemerchant'
282
+ params[:cms] = 'activemerchant_3ds'
272
283
  params[:accepturl] = live_url + 'auth/default.aspx?accept=1'
273
284
  params[:declineurl] = live_url + 'auth/default.aspx?decline=1'
274
285
  params[:merchantnumber] = @options[:login]
@@ -51,7 +51,7 @@ module ActiveMerchant #:nodoc:
51
51
  params = {}
52
52
  add_metadata(params, options)
53
53
  add_invoice(params, amount, options)
54
- add_customer_data(params, options)
54
+ add_customer_data(params, options, payment_method)
55
55
  add_credit_card(params, payment_method, options)
56
56
  params['Method'] = payment_method.respond_to?(:number) ? 'ProcessPayment' : 'TokenPayment'
57
57
  commit(url_for('Transaction'), params)
@@ -61,7 +61,7 @@ module ActiveMerchant #:nodoc:
61
61
  params = {}
62
62
  add_metadata(params, options)
63
63
  add_invoice(params, amount, options)
64
- add_customer_data(params, options)
64
+ add_customer_data(params, options, payment_method)
65
65
  add_credit_card(params, payment_method, options)
66
66
  params['Method'] = 'Authorise'
67
67
  commit(url_for('Authorisation'), params)
@@ -137,7 +137,7 @@ module ActiveMerchant #:nodoc:
137
137
  params = {}
138
138
  add_metadata(params, options)
139
139
  add_invoice(params, 0, options)
140
- add_customer_data(params, options)
140
+ add_customer_data(params, options, payment_method)
141
141
  add_credit_card(params, payment_method, options)
142
142
  params['Method'] = 'CreateTokenCustomer'
143
143
  commit(url_for('Transaction'), params)
@@ -166,7 +166,7 @@ module ActiveMerchant #:nodoc:
166
166
  params = {}
167
167
  add_metadata(params, options)
168
168
  add_invoice(params, 0, options)
169
- add_customer_data(params, options)
169
+ add_customer_data(params, options, payment_method)
170
170
  add_credit_card(params, payment_method, options)
171
171
  add_customer_token(params, customer_token)
172
172
  params['Method'] = 'UpdateTokenCustomer'
@@ -212,17 +212,48 @@ module ActiveMerchant #:nodoc:
212
212
  params['TransactionID'] = reference
213
213
  end
214
214
 
215
- def add_customer_data(params, options)
216
- params['Customer'] ||= {}
217
- add_address(params['Customer'], (options[:billing_address] || options[:address]), {:email => options[:email]})
218
- params['ShippingAddress'] = {}
219
- add_address(params['ShippingAddress'], options[:shipping_address], {:skip_company => true})
215
+ def add_customer_data(params, options, payment_method = nil)
216
+ add_customer_fields(params, options, payment_method)
217
+ add_shipping_fields(params, options)
218
+ end
219
+
220
+ def add_customer_fields(params, options, payment_method)
221
+ key = 'Customer'
222
+ params[key] ||= {}
223
+
224
+ customer_address = options[:billing_address] || options[:address]
225
+
226
+ add_name_and_email(params[key], customer_address, options[:email], payment_method)
227
+ add_address(params[key], customer_address)
228
+ end
229
+
230
+ def add_shipping_fields(params, options)
231
+ key = 'ShippingAddress'
232
+ params[key] = {}
233
+
234
+ add_name_and_email(params[key], options[:shipping_address], options[:email])
235
+ add_address(params[key], options[:shipping_address], {:skip_company => true})
236
+ end
237
+
238
+ def add_name_and_email(params, address, email, payment_method = nil)
239
+ if address.present?
240
+ params['FirstName'], params['LastName'] = split_names(address[:name])
241
+ elsif payment_method_name_available?(payment_method)
242
+ params['FirstName'] = payment_method.first_name
243
+ params['LastName'] = payment_method.last_name
244
+ end
245
+
246
+ params['Email'] = email
247
+ end
248
+
249
+ def payment_method_name_available?(payment_method)
250
+ payment_method.respond_to?(:first_name) && payment_method.respond_to?(:last_name) &&
251
+ payment_method.first_name.present? && payment_method.last_name.present?
220
252
  end
221
253
 
222
254
  def add_address(params, address, options={})
223
255
  return unless address
224
256
 
225
- params['FirstName'], params['LastName'] = split_names(address[:name])
226
257
  params['Title'] = address[:title]
227
258
  params['CompanyName'] = address[:company] unless options[:skip_company]
228
259
  params['Street1'] = truncate(address[:address1], 50)
@@ -231,9 +262,8 @@ module ActiveMerchant #:nodoc:
231
262
  params['State'] = address[:state]
232
263
  params['PostalCode'] = address[:zip]
233
264
  params['Country'] = address[:country].to_s.downcase
234
- params['Phone'] = address[:phone]
265
+ params['Phone'] = address[:phone] || address[:phone_number]
235
266
  params['Fax'] = address[:fax]
236
- params['Email'] = options[:email]
237
267
  end
238
268
 
239
269
  def add_credit_card(params, credit_card, options)
@@ -27,6 +27,7 @@ module ActiveMerchant #:nodoc:
27
27
  add_extra_options(post, options)
28
28
  add_order_id(post, options)
29
29
  add_ip(post, options)
30
+ add_metadata(post, options)
30
31
 
31
32
  commit(:post, 'purchases', post)
32
33
  end
@@ -39,6 +40,7 @@ module ActiveMerchant #:nodoc:
39
40
  add_extra_options(post, options)
40
41
  add_order_id(post, options)
41
42
  add_ip(post, options)
43
+ add_metadata(post, options)
42
44
 
43
45
  post[:capture] = false
44
46
 
@@ -138,6 +140,10 @@ module ActiveMerchant #:nodoc:
138
140
  post[:customer_ip] = options[:ip] || '127.0.0.1'
139
141
  end
140
142
 
143
+ def add_metadata(post, options)
144
+ post[:metadata] = options.fetch(:metadata, {})
145
+ end
146
+
141
147
  def commit(method, uri, parameters=nil)
142
148
  response = begin
143
149
  parse(ssl_request(method, get_url(uri), parameters.to_json, headers))
@@ -10,7 +10,7 @@ module ActiveMerchant #:nodoc:
10
10
  self.supported_countries = ['AD', 'AE', 'AG', 'AI', 'AL', 'AM', 'AO', 'AR', 'AS', 'AT', 'AU', 'AW', 'AX', 'AZ', 'BA', 'BB', 'BD', 'BE', 'BF', 'BG', 'BH', 'BI', 'BJ', 'BL', 'BM', 'BN', 'BO', 'BQ', 'BR', 'BS', 'BT', 'BW', 'BY', 'BZ', 'CA', 'CC', 'CD', 'CF', 'CH', 'CI', 'CK', 'CL', 'CM', 'CN', 'CO', 'CR', 'CU', 'CV', 'CW', 'CX', 'CY', 'CZ', 'DE', 'DJ', 'DK', 'DM', 'DO', 'DZ', 'EC', 'EE', 'EG', 'ER', 'ES', 'ET', 'FI', 'FJ', 'FK', 'FM', 'FO', 'FR', 'GA', 'GB', 'GD', 'GE', 'GF', 'GH', 'GI', 'GL', 'GM', 'GN', 'GP', 'GQ', 'GR', 'GS', 'GT', 'GU', 'GW', 'GY', 'HK', 'HN', 'HR', 'HT', 'HU', 'ID', 'IE', 'IL', 'IM', 'IN', 'IS', 'IT', 'JM', 'JO', 'JP', 'KE', 'KG', 'KH', 'KI', 'KM', 'KN', 'KR', 'KW', 'KY', 'KZ', 'LA', 'LB', 'LC', 'LI', 'LK', 'LR', 'LS', 'LT', 'LU', 'LV', 'MA', 'MC', 'MD', 'ME', 'MF', 'MG', 'MH', 'MK', 'MM', 'MN', 'MO', 'MP', 'MQ', 'MR', 'MS', 'MT', 'MU', 'MV', 'MW', 'MX', 'MY', 'MZ', 'NA', 'NC', 'NE', 'NG', 'NI', 'NL', 'NO', 'NP', 'NR', 'NU', 'NZ', 'OM', 'PA', 'PE', 'PF', 'PG', 'PH', 'PL', 'PN', 'PS', 'PT', 'PW', 'QA', 'RE', 'RO', 'RS', 'RU', 'RW', 'SA', 'SB', 'SC', 'SE', 'SG', 'SH', 'SI', 'SJ', 'SK', 'SL', 'SM', 'SN', 'SR', 'ST', 'SV', 'SZ', 'TC', 'TD', 'TG', 'TH', 'TJ', 'TL', 'TM', 'TN', 'TO', 'TR', 'TT', 'TV', 'TW', 'TZ', 'UA', 'UG', 'US', 'UY', 'UZ', 'VC', 'VE', 'VG', 'VI', 'VN', 'WF', 'WS', 'ZA', 'ZM', 'ZW']
11
11
  self.default_currency = 'USD'
12
12
  self.money_format = :cents
13
- self.supported_cardtypes = [:visa, :master, :american_express, :discover, :naranja]
13
+ self.supported_cardtypes = [:visa, :master, :american_express, :discover, :naranja, :cabal]
14
14
 
15
15
  def initialize(options={})
16
16
  requires!(options, :merchant_id, :api_key_id, :secret_api_key)
@@ -12,14 +12,15 @@ module ActiveMerchant #:nodoc:
12
12
  self.supported_countries = ['AR', 'BR', 'CL', 'CO', 'MX', 'PA', 'PE']
13
13
  self.default_currency = 'USD'
14
14
  self.money_format = :dollars
15
- self.supported_cardtypes = [:visa, :master, :american_express, :diners_club, :naranja]
15
+ self.supported_cardtypes = [:visa, :master, :american_express, :diners_club, :naranja, :cabal]
16
16
 
17
17
  BRAND_MAP = {
18
18
  'visa' => 'VISA',
19
19
  'master' => 'MASTERCARD',
20
20
  'american_express' => 'AMEX',
21
21
  'diners_club' => 'DINERS',
22
- 'naranja' => 'NARANJA'
22
+ 'naranja' => 'NARANJA',
23
+ 'cabal' => 'CABAL'
23
24
  }
24
25
 
25
26
  MINIMUMS = {
@@ -196,6 +197,7 @@ module ActiveMerchant #:nodoc:
196
197
  buyer[:fullName] = buyer_hash[:name]
197
198
  buyer[:dniNumber] = buyer_hash[:dni_number]
198
199
  buyer[:dniType] = buyer_hash[:dni_type]
200
+ buyer[:merchantBuyerId] = buyer_hash[:merchant_buyer_id]
199
201
  buyer[:cnpj] = buyer_hash[:cnpj] if @options[:payment_country] == 'BR'
200
202
  buyer[:emailAddress] = buyer_hash[:email]
201
203
  buyer[:contactPhone] = (options[:billing_address][:phone] if options[:billing_address]) || (options[:shipping_address][:phone] if options[:shipping_address]) || ''
@@ -204,6 +206,7 @@ module ActiveMerchant #:nodoc:
204
206
  buyer[:fullName] = payment_method.name.strip
205
207
  buyer[:dniNumber] = options[:dni_number]
206
208
  buyer[:dniType] = options[:dni_type]
209
+ buyer[:merchantBuyerId] = options[:merchant_buyer_id]
207
210
  buyer[:cnpj] = options[:cnpj] if @options[:payment_country] == 'BR'
208
211
  buyer[:emailAddress] = options[:email]
209
212
  buyer[:contactPhone] = (options[:billing_address][:phone] if options[:billing_address]) || (options[:shipping_address][:phone] if options[:shipping_address]) || ''
@@ -2,6 +2,8 @@ require 'active_support/core_ext/hash/slice'
2
2
 
3
3
  module ActiveMerchant #:nodoc:
4
4
  module Billing #:nodoc:
5
+ # This gateway uses an older version of the Stripe API.
6
+ # To utilize the updated {Payment Intents API}[https://stripe.com/docs/api/payment_intents], integrate with the StripePaymentIntents gateway
5
7
  class StripeGateway < Gateway
6
8
  self.live_url = 'https://api.stripe.com/v1/'
7
9
 
@@ -21,6 +23,8 @@ module ActiveMerchant #:nodoc:
21
23
  'unchecked' => 'P'
22
24
  }
23
25
 
26
+ DEFAULT_API_VERSION = '2015-04-07'
27
+
24
28
  self.supported_countries = %w(AT AU BE BR CA CH DE DK ES FI FR GB HK IE IT JP LU MX NL NO NZ PT SE SG US)
25
29
  self.default_currency = 'USD'
26
30
  self.money_format = :cents
@@ -300,8 +304,8 @@ module ActiveMerchant #:nodoc:
300
304
  add_amount(post, money, options, true)
301
305
  post[:type] = type
302
306
  if type == 'card'
303
- add_creditcard(post, payment, options)
304
- post[:card].delete(:name)
307
+ add_creditcard(post, payment, options, true)
308
+ add_source_owner(post, payment, options)
305
309
  elsif type == 'three_d_secure'
306
310
  post[:three_d_secure] = {card: payment}
307
311
  post[:redirect] = {return_url: options[:redirect_url]}
@@ -347,6 +351,12 @@ module ActiveMerchant #:nodoc:
347
351
  add_creditcard(post, payment, options)
348
352
  end
349
353
 
354
+ add_charge_details(post, money, payment, options)
355
+ post
356
+ end
357
+
358
+ # Used internally by Spreedly to populate the charge object for 3DS 1.0 transactions
359
+ def add_charge_details(post, money, payment, options)
350
360
  if emv_payment?(payment)
351
361
  add_statement_address(post, options)
352
362
  add_emv_metadata(post, payment)
@@ -449,7 +459,7 @@ module ActiveMerchant #:nodoc:
449
459
  post[:statement_address][:state] = statement_address[:state]
450
460
  end
451
461
 
452
- def add_creditcard(post, creditcard, options)
462
+ def add_creditcard(post, creditcard, options, use_sources = false)
453
463
  card = {}
454
464
  if emv_payment?(creditcard)
455
465
  add_emv_creditcard(post, creditcard.icc_data)
@@ -472,7 +482,7 @@ module ActiveMerchant #:nodoc:
472
482
  card[:exp_month] = creditcard.month
473
483
  card[:exp_year] = creditcard.year
474
484
  card[:cvc] = creditcard.verification_value if creditcard.verification_value?
475
- card[:name] = creditcard.name if creditcard.name
485
+ card[:name] = creditcard.name if creditcard.name && !use_sources
476
486
  end
477
487
 
478
488
  if creditcard.is_a?(NetworkTokenizationCreditCard)
@@ -482,7 +492,7 @@ module ActiveMerchant #:nodoc:
482
492
  end
483
493
  post[:card] = card
484
494
 
485
- add_address(post, options)
495
+ add_address(post, options) unless use_sources
486
496
  elsif creditcard.kind_of?(String)
487
497
  if options[:track_data]
488
498
  card[:swipe_data] = options[:track_data]
@@ -530,6 +540,25 @@ module ActiveMerchant #:nodoc:
530
540
  post[:metadata][:card_read_method] = creditcard.read_method if creditcard.respond_to?(:read_method)
531
541
  end
532
542
 
543
+ def add_source_owner(post, creditcard, options)
544
+ post[:owner] = {}
545
+ post[:owner][:name] = creditcard.name if creditcard.name
546
+ post[:owner][:email] = options[:email] if options[:email]
547
+
548
+ if address = options[:billing_address] || options[:address]
549
+ owner_address = {}
550
+ owner_address[:line1] = address[:address1] if address[:address1]
551
+ owner_address[:line2] = address[:address2] if address[:address2]
552
+ owner_address[:country] = address[:country] if address[:country]
553
+ owner_address[:postal_code] = address[:zip] if address[:zip]
554
+ owner_address[:state] = address[:state] if address[:state]
555
+ owner_address[:city] = address[:city] if address[:city]
556
+
557
+ post[:owner][:phone] = address[:phone] if address[:phone]
558
+ post[:owner][:address] = owner_address
559
+ end
560
+ end
561
+
533
562
  def parse(body)
534
563
  JSON.parse(body)
535
564
  end
@@ -589,7 +618,7 @@ module ActiveMerchant #:nodoc:
589
618
  end
590
619
 
591
620
  def api_version(options)
592
- options[:version] || @options[:version] || '2015-04-07'
621
+ options[:version] || @options[:version] || self.class::DEFAULT_API_VERSION
593
622
  end
594
623
 
595
624
  def api_request(method, endpoint, parameters = nil, options = {})
@@ -632,8 +661,8 @@ module ActiveMerchant #:nodoc:
632
661
  return response.fetch('error', {})['charge'] unless success
633
662
 
634
663
  if url == 'customers'
635
- [response['id'], response['sources']['data'].first['id']].join('|')
636
- elsif method == :post && url.match(/customers\/.*\/cards/)
664
+ [response['id'], response.dig('sources', 'data').first&.dig('id')].join('|')
665
+ elsif method == :post && (url.match(/customers\/.*\/cards/) || url.match(/payment_methods\/.*\/attach/))
637
666
  [response['customer'], response['id']].join('|')
638
667
  else
639
668
  response['id']
@@ -0,0 +1,267 @@
1
+ require 'active_support/core_ext/hash/slice'
2
+
3
+ module ActiveMerchant #:nodoc:
4
+ module Billing #:nodoc:
5
+ # This gateway uses the current Stripe {Payment Intents API}[https://stripe.com/docs/api/payment_intents].
6
+ # For the legacy API, see the Stripe gateway
7
+ class StripePaymentIntentsGateway < StripeGateway
8
+
9
+ self.supported_countries = %w(AT AU BE BR CA CH DE DK ES FI FR GB HK IE IT JP LU MX NL NO NZ PT SE SG US)
10
+
11
+ ALLOWED_METHOD_STATES = %w[automatic manual].freeze
12
+ ALLOWED_CANCELLATION_REASONS = %w[duplicate fraudulent requested_by_customer abandoned].freeze
13
+ CREATE_INTENT_ATTRIBUTES = %i[description statement_descriptor receipt_email save_payment_method]
14
+ CONFIRM_INTENT_ATTRIBUTES = %i[receipt_email return_url save_payment_method setup_future_usage off_session]
15
+ UPDATE_INTENT_ATTRIBUTES = %i[description statement_descriptor receipt_email setup_future_usage]
16
+ DEFAULT_API_VERSION = '2019-05-16'
17
+
18
+ def create_intent(money, payment_method, options = {})
19
+ post = {}
20
+ add_amount(post, money, options, true)
21
+ add_capture_method(post, options)
22
+ add_confirmation_method(post, options)
23
+ add_customer(post, options)
24
+ add_payment_method_token(post, payment_method, options)
25
+ add_metadata(post, options)
26
+ add_return_url(post, options)
27
+ add_connected_account(post, options)
28
+ add_shipping_address(post, options)
29
+ setup_future_usage(post, options)
30
+ add_exemption(post, options)
31
+
32
+ CREATE_INTENT_ATTRIBUTES.each do |attribute|
33
+ add_whitelisted_attribute(post, options, attribute)
34
+ end
35
+
36
+ commit(:post, 'payment_intents', post, options)
37
+ end
38
+
39
+ def show_intent(intent_id, options)
40
+ commit(:get, "payment_intents/#{intent_id}", nil, options)
41
+ end
42
+
43
+ def confirm_intent(intent_id, payment_method, options = {})
44
+ post = {}
45
+ add_payment_method_token(post, payment_method, options)
46
+ CONFIRM_INTENT_ATTRIBUTES.each do |attribute|
47
+ add_whitelisted_attribute(post, options, attribute)
48
+ end
49
+
50
+ commit(:post, "payment_intents/#{intent_id}/confirm", post, options)
51
+ end
52
+
53
+ def create_payment_method(payment_method, options = {})
54
+ post = {}
55
+ post[:type] = 'card'
56
+ post[:card] = {}
57
+ post[:card][:number] = payment_method.number
58
+ post[:card][:exp_month] = payment_method.month
59
+ post[:card][:exp_year] = payment_method.year
60
+ post[:card][:cvc] = payment_method.verification_value if payment_method.verification_value
61
+ add_billing_address(post, options)
62
+
63
+ commit(:post, 'payment_methods', post, options)
64
+ end
65
+
66
+ def update_intent(money, intent_id, payment_method, options = {})
67
+ post = {}
68
+ post[:amount] = money if money
69
+
70
+ add_payment_method_token(post, payment_method, options)
71
+ add_payment_method_types(post, options)
72
+ add_customer(post, options)
73
+ add_metadata(post, options)
74
+ add_shipping_address(post, options)
75
+ add_connected_account(post, options)
76
+
77
+ UPDATE_INTENT_ATTRIBUTES.each do |attribute|
78
+ add_whitelisted_attribute(post, options, attribute)
79
+ end
80
+
81
+ commit(:post, "payment_intents/#{intent_id}", post, options)
82
+ end
83
+
84
+ def authorize(money, payment_method, options = {})
85
+ create_intent(money, payment_method, options.merge!(confirm: true, capture_method: 'manual'))
86
+ end
87
+
88
+ def purchase(money, payment_method, options = {})
89
+ create_intent(money, payment_method, options.merge!(confirm: true, capture_method: 'automatic'))
90
+ end
91
+
92
+ def capture(money, intent_id, options = {})
93
+ post = {}
94
+ post[:amount_to_capture] = money
95
+ add_connected_account(post, options)
96
+ commit(:post, "payment_intents/#{intent_id}/capture", post, options)
97
+ end
98
+
99
+ def void(intent_id, options = {})
100
+ post = {}
101
+ post[:cancellation_reason] = options[:cancellation_reason] if ALLOWED_CANCELLATION_REASONS.include?(options[:cancellation_reason])
102
+ commit(:post, "payment_intents/#{intent_id}/cancel", post, options)
103
+ end
104
+
105
+ def refund(money, intent_id, options = {})
106
+ intent = commit(:get, "payment_intents/#{intent_id}", nil, options)
107
+ charge_id = intent.params.dig('charges', 'data')[0].dig('id')
108
+ super(money, charge_id, options)
109
+ end
110
+
111
+ # Note: Not all payment methods are currently supported by the {Payment Methods API}[https://stripe.com/docs/payments/payment-methods]
112
+ # Current implementation will create a PaymentMethod object if the method is a token or credit card
113
+ # All other types will default to legacy Stripe store
114
+ def store(payment_method, options = {})
115
+ params = {}
116
+ post = {}
117
+
118
+ # If customer option is provided, create a payment method and attach to customer id
119
+ # Otherwise, create a customer, then attach
120
+ if payment_method.is_a?(StripePaymentToken) || payment_method.is_a?(ActiveMerchant::Billing::CreditCard)
121
+ add_payment_method_token(params, payment_method, options)
122
+ if options[:customer]
123
+ customer_id = options[:customer]
124
+ else
125
+ post[:validate] = options[:validate] unless options[:validate].nil?
126
+ post[:description] = options[:description] if options[:description]
127
+ post[:email] = options[:email] if options[:email]
128
+ customer = commit(:post, 'customers', post, options)
129
+ customer_id = customer.params['id']
130
+ end
131
+ commit(:post, "payment_methods/#{params[:payment_method]}/attach", { customer: customer_id }, options)
132
+ else
133
+ super(payment, options)
134
+ end
135
+ end
136
+
137
+ def unstore(identification, options = {}, deprecated_options = {})
138
+ if identification.include?('pm_')
139
+ _, payment_method = identification.split('|')
140
+ commit(:post, "payment_methods/#{payment_method}/detach", nil, options)
141
+ else
142
+ super(identification, options, deprecated_options)
143
+ end
144
+ end
145
+
146
+ private
147
+
148
+ def add_whitelisted_attribute(post, options, attribute)
149
+ post[attribute] = options[attribute] if options[attribute]
150
+ post
151
+ end
152
+
153
+ def add_capture_method(post, options)
154
+ capture_method = options[:capture_method].to_s
155
+ post[:capture_method] = capture_method if ALLOWED_METHOD_STATES.include?(capture_method)
156
+ post
157
+ end
158
+
159
+ def add_confirmation_method(post, options)
160
+ confirmation_method = options[:confirmation_method].to_s
161
+ post[:confirmation_method] = confirmation_method if ALLOWED_METHOD_STATES.include?(confirmation_method)
162
+ post
163
+ end
164
+
165
+ def add_customer(post, options)
166
+ customer = options[:customer].to_s
167
+ post[:customer] = customer if customer.start_with?('cus_')
168
+ post
169
+ end
170
+
171
+ def add_return_url(post, options)
172
+ return unless options[:confirm]
173
+ post[:confirm] = options[:confirm]
174
+ post[:return_url] = options[:return_url] if options[:return_url]
175
+ post
176
+ end
177
+
178
+ def add_payment_method_token(post, payment_method, options)
179
+ return if payment_method.nil?
180
+
181
+ if payment_method.is_a?(ActiveMerchant::Billing::CreditCard)
182
+ p = create_payment_method(payment_method, options)
183
+ payment_method = p.params['id']
184
+ end
185
+
186
+ if payment_method.is_a?(StripePaymentToken)
187
+ post[:payment_method] = payment_method.payment_data['id']
188
+ elsif payment_method.is_a?(String)
189
+ if payment_method.include?('|')
190
+ customer_id, payment_method_id = payment_method.split('|')
191
+ token = payment_method_id
192
+ post[:customer] = customer_id
193
+ else
194
+ token = payment_method
195
+ end
196
+ post[:payment_method] = token
197
+ end
198
+ end
199
+
200
+ def add_payment_method_types(post, options)
201
+ payment_method_types = options[:payment_method_types] if options[:payment_method_types]
202
+ return if payment_method_types.nil?
203
+
204
+ post[:payment_method_types] = Array(payment_method_types)
205
+ post
206
+ end
207
+
208
+ def add_exemption(post, options = {})
209
+ return unless options[:confirm]
210
+ post[:payment_method_options] ||= {}
211
+ post[:payment_method_options][:card] ||= {}
212
+ post[:payment_method_options][:card][:moto] = true if options[:moto]
213
+ end
214
+
215
+ def setup_future_usage(post, options = {})
216
+ post[:setup_future_usage] = options[:setup_future_usage] if %w( on_session off_session ).include?(options[:setup_future_usage])
217
+ post[:off_session] = options[:off_session] if options[:off_session] && options[:confirm] == true
218
+ post
219
+ end
220
+
221
+ def add_connected_account(post, options = {})
222
+ return unless options[:transfer_destination]
223
+ post[:transfer_data] = {}
224
+ post[:transfer_data][:destination] = options[:transfer_destination]
225
+ post[:transfer_data][:amount] = options[:transfer_amount] if options[:transfer_amount]
226
+ post[:on_behalf_of] = options[:on_behalf_of] if options[:on_behalf_of]
227
+ post[:transfer_group] = options[:transfer_group] if options[:transfer_group]
228
+ post[:application_fee_amount] = options[:application_fee] if options[:application_fee]
229
+ post
230
+ end
231
+
232
+ def add_billing_address(post, options = {})
233
+ return unless billing = options[:billing_address] || options[:address]
234
+ post[:billing_details] = {}
235
+ post[:billing_details][:address] = {}
236
+ post[:billing_details][:address][:city] = billing[:city] if billing[:city]
237
+ post[:billing_details][:address][:country] = billing[:country] if billing[:country]
238
+ post[:billing_details][:address][:line1] = billing[:address1] if billing[:address1]
239
+ post[:billing_details][:address][:line2] = billing[:address2] if billing[:address2]
240
+ post[:billing_details][:address][:postal_code] = billing[:zip] if billing[:zip]
241
+ post[:billing_details][:address][:state] = billing[:state] if billing[:state]
242
+ post[:billing_details][:email] = billing[:email] if billing[:email]
243
+ post[:billing_details][:name] = billing[:name] if billing[:name]
244
+ post[:billing_details][:phone] = billing[:phone] if billing[:phone]
245
+ post
246
+ end
247
+
248
+ def add_shipping_address(post, options = {})
249
+ return unless shipping = options[:shipping]
250
+ post[:shipping] = {}
251
+ post[:shipping][:address] = {}
252
+ post[:shipping][:address][:line1] = shipping[:address][:line1]
253
+ post[:shipping][:address][:city] = shipping[:address][:city] if shipping[:address][:city]
254
+ post[:shipping][:address][:country] = shipping[:address][:country] if shipping[:address][:country]
255
+ post[:shipping][:address][:line2] = shipping[:address][:line2] if shipping[:address][:line2]
256
+ post[:shipping][:address][:postal_code] = shipping[:address][:postal_code] if shipping[:address][:postal_code]
257
+ post[:shipping][:address][:state] = shipping[:address][:state] if shipping[:address][:state]
258
+
259
+ post[:shipping][:name] = shipping[:name]
260
+ post[:shipping][:carrier] = shipping[:carrier] if shipping[:carrier]
261
+ post[:shipping][:phone] = shipping[:phone] if shipping[:phone]
262
+ post[:shipping][:tracking_number] = shipping[:tracking_number] if shipping[:tracking_number]
263
+ post
264
+ end
265
+ end
266
+ end
267
+ end
@@ -159,6 +159,8 @@ module ActiveMerchant #:nodoc:
159
159
  add_customer_data(parameters, options)
160
160
  add_payment_source(parameters, creditcard_or_billing_id)
161
161
  add_addresses(parameters, options)
162
+ add_custom_fields(parameters, options)
163
+
162
164
  commit('preauth', parameters)
163
165
  end
164
166
 
@@ -174,6 +176,8 @@ module ActiveMerchant #:nodoc:
174
176
  add_customer_data(parameters, options)
175
177
  add_payment_source(parameters, creditcard_or_billing_id)
176
178
  add_addresses(parameters, options)
179
+ add_custom_fields(parameters, options)
180
+
177
181
  commit('sale', parameters)
178
182
  end
179
183
 
@@ -187,6 +191,7 @@ module ActiveMerchant #:nodoc:
187
191
  :transid => transaction_id,
188
192
  }
189
193
  add_aggregator(parameters, options)
194
+ add_custom_fields(parameters, options)
190
195
 
191
196
  commit('postauth', parameters)
192
197
  end
@@ -195,11 +200,14 @@ module ActiveMerchant #:nodoc:
195
200
  # that you want to refund, and a TC transid for the transaction that you are refunding.
196
201
  def refund(money, identification, options = {})
197
202
  transaction_id, _ = split_authorization(identification)
203
+
198
204
  parameters = {
199
205
  :amount => amount(money),
200
206
  :transid => transaction_id
201
207
  }
208
+
202
209
  add_aggregator(parameters, options)
210
+ add_custom_fields(parameters, options)
203
211
 
204
212
  commit('credit', parameters)
205
213
  end
@@ -233,7 +241,9 @@ module ActiveMerchant #:nodoc:
233
241
  parameters = {
234
242
  :transid => transaction_id,
235
243
  }
244
+
236
245
  add_aggregator(parameters, options)
246
+ add_custom_fields(parameters, options)
237
247
 
238
248
  commit(action, parameters)
239
249
  end
@@ -294,6 +304,8 @@ module ActiveMerchant #:nodoc:
294
304
 
295
305
  add_creditcard(parameters, creditcard)
296
306
  add_addresses(parameters, options)
307
+ add_custom_fields(parameters, options)
308
+
297
309
  commit('store', parameters)
298
310
  end
299
311
 
@@ -304,6 +316,8 @@ module ActiveMerchant #:nodoc:
304
316
  :billingid => identification,
305
317
  }
306
318
 
319
+ add_custom_fields(parameters, options)
320
+
307
321
  commit('unstore', parameters)
308
322
  end
309
323
 
@@ -321,6 +335,12 @@ module ActiveMerchant #:nodoc:
321
335
 
322
336
  private
323
337
 
338
+ def add_custom_fields(params, options)
339
+ options[:custom_fields]&.each do |key, value|
340
+ params[key.to_sym] = value
341
+ end
342
+ end
343
+
324
344
  def add_aggregator(params, options)
325
345
  if @options[:aggregator_id] || application_id != Gateway.application_id
326
346
  params[:aggregators] = 1
@@ -419,7 +439,7 @@ module ActiveMerchant #:nodoc:
419
439
  TCLink.send(parameters)
420
440
  else
421
441
  parse(ssl_post(self.live_url, post_data(parameters)))
422
- end
442
+ end
423
443
 
424
444
  # to be considered successful, transaction status must be either "approved" or "accepted"
425
445
  success = SUCCESS_TYPES.include?(data['status'])
@@ -463,7 +483,7 @@ module ActiveMerchant #:nodoc:
463
483
  end
464
484
 
465
485
  def split_authorization(authorization)
466
- authorization.split('|')
486
+ authorization&.split('|')
467
487
  end
468
488
  end
469
489
  end
@@ -7,7 +7,7 @@ module ActiveMerchant #:nodoc:
7
7
  self.default_currency = 'GBP'
8
8
  self.money_format = :cents
9
9
  self.supported_countries = %w(HK GB AU AD AR BE BR CA CH CN CO CR CY CZ DE DK ES FI FR GI GR HU IE IN IT JP LI LU MC MT MY MX NL NO NZ PA PE PL PT SE SG SI SM TR UM VA)
10
- self.supported_cardtypes = [:visa, :master, :american_express, :discover, :jcb, :maestro, :elo, :naranja]
10
+ self.supported_cardtypes = [:visa, :master, :american_express, :discover, :jcb, :maestro, :elo, :naranja, :cabal]
11
11
  self.currencies_without_fractions = %w(HUF IDR ISK JPY KRW)
12
12
  self.currencies_with_three_decimal_places = %w(BHD KWD OMR RSD TND)
13
13
  self.homepage_url = 'http://www.worldpay.com/'
@@ -23,6 +23,7 @@ module ActiveMerchant #:nodoc:
23
23
  'diners_club' => 'DINERS-SSL',
24
24
  'elo' => 'ELO-SSL',
25
25
  'naranja' => 'NARANJA-SSL',
26
+ 'cabal' => 'CABAL-SSL',
26
27
  'unknown' => 'CARD-SSL'
27
28
  }
28
29
 
@@ -206,6 +207,7 @@ module ActiveMerchant #:nodoc:
206
207
  if options[:instalments]
207
208
  add_instalments_data(xml, options)
208
209
  end
210
+ add_moto_flag(xml, options) if options.dig(:metadata, :manual_entry)
209
211
  end
210
212
  end
211
213
  end
@@ -422,6 +424,10 @@ module ActiveMerchant #:nodoc:
422
424
  end
423
425
  end
424
426
 
427
+ def add_moto_flag(xml, options)
428
+ xml.tag! 'dynamicInteractionType', 'type' => 'MOTO'
429
+ end
430
+
425
431
  def address_with_defaults(address)
426
432
  address ||= {}
427
433
  address.delete_if { |_, v| v.blank? }
@@ -1,3 +1,3 @@
1
1
  module ActiveMerchant
2
- VERSION = '1.97.0'
2
+ VERSION = '1.98.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.97.0
4
+ version: 1.98.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: 2019-08-15 00:00:00.000000000 Z
11
+ date: 2019-09-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -128,6 +128,20 @@ dependencies:
128
128
  - - ">="
129
129
  - !ruby/object:Gem::Version
130
130
  version: '0'
131
+ - !ruby/object:Gem::Dependency
132
+ name: pry
133
+ requirement: !ruby/object:Gem::Requirement
134
+ requirements:
135
+ - - ">="
136
+ - !ruby/object:Gem::Version
137
+ version: '0'
138
+ type: :development
139
+ prerelease: false
140
+ version_requirements: !ruby/object:Gem::Requirement
141
+ requirements:
142
+ - - ">="
143
+ - !ruby/object:Gem::Version
144
+ version: '0'
131
145
  description: Active Merchant is a simple payment abstraction library used in and sponsored
132
146
  by Shopify. It is written by Tobias Luetke, Cody Fauser, and contributors. The aim
133
147
  of the project is to feel natural to Ruby users and to abstract as many parts as
@@ -350,6 +364,7 @@ files:
350
364
  - lib/active_merchant/billing/gateways/so_easy_pay.rb
351
365
  - lib/active_merchant/billing/gateways/spreedly_core.rb
352
366
  - lib/active_merchant/billing/gateways/stripe.rb
367
+ - lib/active_merchant/billing/gateways/stripe_payment_intents.rb
353
368
  - lib/active_merchant/billing/gateways/swipe_checkout.rb
354
369
  - lib/active_merchant/billing/gateways/telr.rb
355
370
  - lib/active_merchant/billing/gateways/tns.rb