activemerchant 1.62.0 → 1.63.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: 7495e19fc84deca42bc3878d9463044899a33b2e
4
- data.tar.gz: bc44737020062ba81039dfc19956b7c5a128ee40
3
+ metadata.gz: a16e6e0f311ac3b77069a4f05f5f257b6a69fc60
4
+ data.tar.gz: 666b86bb155b6ff98a608bf8c38714a54af46627
5
5
  SHA512:
6
- metadata.gz: 3fb5132fdfd23c6f1d772755285638231bef754099790c47c69f963133b7c1057c0d3c3f19b82c8b72226f5b61a294c7d2d30e283c570d2a5f81701886db491a
7
- data.tar.gz: be95c7d4600244ab3f2607f2a67ff1f4a325db60da1deb57834b5ea11eead17392a4d5d758d5595fcd76710c2a3e141a51e61e0de67191db8b2be58b1b07e867
6
+ metadata.gz: bd479af93c39120f8a447058524d56de326189f0f3fc26ace5af2681166761fc81a967a66368f9d50e4d7a5a0b64c7a4867c7f61dc2b37e368b0aa19141c87c2
7
+ data.tar.gz: b9f8ea0507a585f672f9abce5cf4c2359dbeeb781fe8cdda5e05413aa24fa638fc25a0f83279c4143e72278f8cf4e82f12a1987190390640a7c21ff52f488389
data/CHANGELOG CHANGED
@@ -2,6 +2,29 @@
2
2
 
3
3
  == HEAD
4
4
 
5
+ == Version 1.63.0 (February 2, 2017)
6
+ * Authorize.net: Add #unstore support [jimryan] #2293
7
+ * AuthorizeNet: Fix line items quirk [shasum]
8
+ * CardStream: Add dynamic descriptor option fields [curiousepic]
9
+ * CardStream: Support PEN currency [shasum]
10
+ * Culqi: Add new gateway [shasum]
11
+ * CyberSource: Add Lebanon to supported countries [shasum]
12
+ * Element: Add AVS and CVV codes to response [shasum]
13
+ * Firstdata E4 (Payeezy): Set correct ECI value for card present swipes [jasonwebster] #2318
14
+ * GlobalCollect: On purchase skip capture if not required [davidsantoso]
15
+ * PaymentExpress: Update supported countries [shasum]
16
+ * Remove leading or trailing whitespace from credit card name [davidsantoso]
17
+ * Remove support for Ruby 2.0 [jasonwebster]
18
+ * Secure Pay AU: Add scrubbing support to Secure Pay AU [bruno] #2253
19
+ * Stripe: Fix error in handling of track-only contactless EMV data [jasonwebster]
20
+ * Vanco: Update test URL [davidsantoso]
21
+ * WePay: Build fee structure correctly [curiousepic]
22
+ * WePay: Remove null address fields from request [davidsantoso]
23
+ * WePay: Update WePay to API version 2016-12-07 [davidsantoso]
24
+ * Wirecard: Send customer data in requests [davidsantoso]
25
+ * Worldpay: Add session id attribute [shasum]
26
+ * Worldpay: Do not default address when not provided [shasum]
27
+
5
28
  == Version 1.62.0 (December 5, 2016)
6
29
  * AuthorizeNet: Map to standard AVSResult codes [shasum]
7
30
  * CitrusPay: Add 3DSecureId field [davidsantoso]
@@ -245,7 +245,7 @@ module ActiveMerchant #:nodoc:
245
245
  #
246
246
  # @return [String] the full name of the card holder
247
247
  def name
248
- [first_name, last_name].compact.join(' ')
248
+ "#{first_name} #{last_name}".strip
249
249
  end
250
250
 
251
251
  def name=(full_name)
@@ -159,7 +159,6 @@ module ActiveMerchant
159
159
  add_payment_source(xml, payment)
160
160
  add_invoice(xml, options)
161
161
  add_customer_data(xml, payment, options)
162
- add_line_items(xml, options)
163
162
  add_settings(xml, payment, options)
164
163
  add_user_fields(xml, amount, options)
165
164
  end
@@ -181,6 +180,12 @@ module ActiveMerchant
181
180
  end
182
181
  end
183
182
 
183
+ def unstore(authorization)
184
+ customer_profile_id, _, _ = split_authorization(authorization)
185
+
186
+ delete_customer_profile(customer_profile_id)
187
+ end
188
+
184
189
  def verify_credentials
185
190
  response = commit(:verify_credentials) { }
186
191
  response.success?
@@ -233,7 +238,6 @@ module ActiveMerchant
233
238
  add_invoice(xml, options)
234
239
  add_customer_data(xml, payment, options)
235
240
  add_market_type_device_type(xml, payment, options)
236
- add_line_items(xml, options)
237
241
  add_settings(xml, payment, options)
238
242
  add_user_fields(xml, amount, options)
239
243
  end
@@ -347,19 +351,6 @@ module ActiveMerchant
347
351
  end
348
352
  end
349
353
 
350
- def add_line_items(xml, options)
351
- return unless options[:line_items]
352
- xml.lineItems do
353
- options[:line_items].each do |line_item|
354
- xml.lineItem do
355
- line_item.each do |key, value|
356
- xml.send(camel_case_lower(key), value)
357
- end
358
- end
359
- end
360
- end
361
- end
362
-
363
354
  def camel_case_lower(key)
364
355
  String(key).split('_').inject([]){ |buffer,e| buffer.push(buffer.empty? ? e : e.capitalize) }.join
365
356
  end
@@ -575,6 +566,19 @@ module ActiveMerchant
575
566
  xml.invoiceNumber(truncate(options[:order_id], 20))
576
567
  xml.description(truncate(options[:description], 255))
577
568
  end
569
+
570
+ # Authorize.net API requires lineItems to be placed directly after order tag
571
+ if options[:line_items]
572
+ xml.lineItems do
573
+ options[:line_items].each do |line_item|
574
+ xml.lineItem do
575
+ line_item.each do |key, value|
576
+ xml.send(camel_case_lower(key), value)
577
+ end
578
+ end
579
+ end
580
+ end
581
+ end
578
582
  end
579
583
 
580
584
  def create_customer_payment_profile(credit_card, options)
@@ -616,6 +620,12 @@ module ActiveMerchant
616
620
  end
617
621
  end
618
622
 
623
+ def delete_customer_profile(customer_profile_id)
624
+ commit(:cim_store_delete_customer) do |xml|
625
+ xml.customerProfileId(customer_profile_id)
626
+ end
627
+ end
628
+
619
629
  def names_from(payment_source, address, options)
620
630
  if payment_source && !payment_source.is_a?(PaymentToken) && !payment_source.is_a?(String)
621
631
  first_name, last_name = split_names(address[:name])
@@ -683,6 +693,8 @@ module ActiveMerchant
683
693
  "createCustomerProfileRequest"
684
694
  elsif action == :cim_store_update
685
695
  "createCustomerPaymentProfileRequest"
696
+ elsif action == :cim_store_delete_customer
697
+ "deleteCustomerProfileRequest"
686
698
  elsif action == :verify_credentials
687
699
  "authenticateTestRequest"
688
700
  elsif is_cim_action?(action)
@@ -827,7 +839,7 @@ module ActiveMerchant
827
839
  end
828
840
 
829
841
  def cim?(action)
830
- (action == :cim_store) || (action == :cim_store_update)
842
+ (action == :cim_store) || (action == :cim_store_update) || (action == :cim_store_delete_customer)
831
843
  end
832
844
 
833
845
  def transaction_id_from(authorization)
@@ -28,6 +28,7 @@ module ActiveMerchant #:nodoc:
28
28
  "MXN" => "484",
29
29
  "NOK" => "578",
30
30
  "NZD" => "554",
31
+ "PEN" => "604",
31
32
  "SEK" => "752",
32
33
  "SGD" => "702",
33
34
  "USD" => "840",
@@ -154,6 +155,8 @@ module ActiveMerchant #:nodoc:
154
155
  def add_invoice(post, credit_card_or_reference, money, options)
155
156
  add_pair(post, :transactionUnique, options[:order_id], :required => true)
156
157
  add_pair(post, :orderRef, options[:description] || options[:order_id], :required => true)
158
+ add_pair(post, :statementNarrative1, options[:merchant_name]) if options[:merchant_name]
159
+ add_pair(post, :statementNarrative2, options[:dynamic_descriptor]) if options[:dynamic_descriptor]
157
160
  if credit_card_or_reference.respond_to?(:number)
158
161
  if ['american_express', 'diners_club'].include?(card_brand(credit_card_or_reference).to_s)
159
162
  add_pair(post, :item1Quantity, 1)
@@ -0,0 +1,279 @@
1
+ require 'digest/md5'
2
+
3
+ module ActiveMerchant #:nodoc:
4
+ module Billing #:nodoc:
5
+ # Important note:
6
+ # ===
7
+ # Culqi merchant accounts are configured for either purchase or auth/capture
8
+ # modes. This is configured by Culqi when setting up a merchant account and
9
+ # largely depends on the transaction acquiring bank. Be sure to understand how
10
+ # your account was configured prior to using this gateway.
11
+ class CulqiGateway < Gateway
12
+ self.display_name = "Culqi"
13
+ self.homepage_url = "https://www.culqi.com"
14
+
15
+ self.test_url = "https://staging.paymentz.com/transaction/"
16
+ self.live_url = "https://secure.culqi.com/transaction/"
17
+
18
+ self.supported_countries = ["PE"]
19
+ self.default_currency = "PEN"
20
+ self.money_format = :dollars
21
+ self.supported_cardtypes = [:visa, :master, :diners_club, :american_express]
22
+
23
+ def initialize(options={})
24
+ requires!(options, :merchant_id, :terminal_id, :secret_key)
25
+ super
26
+ end
27
+
28
+ def purchase(amount, payment_method, options={})
29
+ authorize(amount, payment_method, options)
30
+ end
31
+
32
+ def authorize(amount, payment_method, options={})
33
+ if payment_method.is_a?(String)
34
+ action = :tokenpay
35
+ else
36
+ action = :authorize
37
+ end
38
+ post = {}
39
+ add_credentials(post)
40
+ add_invoice(action, post, amount, options)
41
+ add_payment_method(post, payment_method, action, options)
42
+ add_customer_data(post, options)
43
+ add_checksum(action, post)
44
+
45
+ commit(action, post)
46
+ end
47
+
48
+ def capture(amount, authorization, options={})
49
+ action = :capture
50
+ post = {}
51
+ add_credentials(post)
52
+ add_invoice(action, post, amount, options)
53
+ add_reference(post, authorization)
54
+ add_checksum(action, post)
55
+
56
+ commit(action, post)
57
+ end
58
+
59
+ def void(authorization, options={})
60
+ action = :void
61
+ post = {}
62
+ add_credentials(post)
63
+ add_invoice(action, post, nil, options)
64
+ add_reference(post, authorization)
65
+ add_checksum(action, post)
66
+
67
+ commit(action, post)
68
+ end
69
+
70
+ def refund(amount, authorization, options={})
71
+ action = :refund
72
+ post = {}
73
+ add_credentials(post)
74
+ add_invoice(action, post, amount, options)
75
+ add_reference(post, authorization)
76
+ add_checksum(action, post)
77
+
78
+ commit(action, post)
79
+ end
80
+
81
+ def verify(credit_card, options={})
82
+ MultiResponse.run(:use_first_response) do |r|
83
+ r.process { authorize(1000, credit_card, options) }
84
+ r.process(:ignore_result) { void(r.authorization, options) }
85
+ end
86
+ end
87
+
88
+ def verify_credentials
89
+ response = void("0", order_id: "0")
90
+ response.message.include? "Transaction not found"
91
+ end
92
+
93
+ def store(credit_card, options={})
94
+ action = :tokenize
95
+ post = {}
96
+ post[:partnerid] = options[:partner_id] if options[:partner_id]
97
+ post[:cardholderid] = options[:cardholder_id] if options[:cardholder_id]
98
+ add_credentials(post)
99
+ add_payment_method(post, credit_card, action, options)
100
+ add_customer_data(post, options)
101
+ add_checksum(action, post)
102
+
103
+ commit(action, post)
104
+ end
105
+
106
+ def invalidate(authorization, options={})
107
+ action = :invalidate
108
+ post = {}
109
+ post[:partnerid] = options[:partner_id] if options[:partner_id]
110
+ add_credentials(post)
111
+ post[:token] = authorization
112
+ add_checksum(action, post)
113
+
114
+ commit(action, post)
115
+ end
116
+
117
+ def supports_scrubbing?
118
+ true
119
+ end
120
+
121
+ def scrub(transcript)
122
+ transcript.
123
+ gsub(%r((cardnumber=)\d+), '\1[FILTERED]').
124
+ gsub(%r((cvv=)\d+), '\1[FILTERED]')
125
+ end
126
+
127
+ private
128
+
129
+ def add_credentials(post)
130
+ post[:toid] = @options[:merchant_id]
131
+ post[:totype] = 'Culqi'
132
+ post[:terminalid] = @options[:terminal_id]
133
+ post[:language] = 'ENG'
134
+ end
135
+
136
+ def add_invoice(action, post, money, options)
137
+ case action
138
+ when :capture
139
+ post[:captureamount] = amount(money)
140
+ when :refund
141
+ post[:refundamount] = amount(money)
142
+ post[:reason] = 'none'
143
+ else
144
+ post[:amount] = amount(money)
145
+ end
146
+
147
+ post[:description] = options[:order_id]
148
+ post[:redirecturl] = options[:redirect_url] || 'http://www.example.com'
149
+ end
150
+
151
+ def add_payment_method(post, payment_method, action, options)
152
+ if payment_method.is_a?(String)
153
+ post[:token] = payment_method
154
+ post[:cvv] = options[:cvv] if options[:cvv]
155
+ else
156
+ post[:cardnumber] = payment_method.number
157
+ post[:cvv] = payment_method.verification_value
158
+ post[:firstname], post[:lastname] = payment_method.name.split(' ')
159
+ if action == :tokenize
160
+ post[:expirymonth] = format(payment_method.month, :two_digits)
161
+ post[:expiryyear] = format(payment_method.year, :four_digits)
162
+ else
163
+ post[:expiry_month] = format(payment_method.month, :two_digits)
164
+ post[:expiry_year] = format(payment_method.year, :four_digits)
165
+ end
166
+ end
167
+ end
168
+
169
+ def add_customer_data(post, options)
170
+ post[:emailaddr] = options[:email] || 'unspecified@example.com'
171
+ if (billing_address = options[:billing_address] || options[:address])
172
+ post[:street] = [billing_address[:address1], billing_address[:address2]].join(' ')
173
+ post[:city] = billing_address[:city]
174
+ post[:state] = billing_address[:state]
175
+ post[:countrycode] = billing_address[:country]
176
+ post[:zip] = billing_address[:zip]
177
+ post[:telno] = billing_address[:phone]
178
+ post[:telnocc] = options[:telephone_country_code] || '051'
179
+ end
180
+ end
181
+
182
+ def add_checksum(action, post)
183
+ checksum_elements = case action
184
+ when :capture; [post[:toid], post[:trackingid], post[:captureamount], @options[:secret_key]]
185
+ when :void; [post[:toid], post[:description], post[:trackingid], @options[:secret_key]]
186
+ when :refund; [post[:toid], post[:trackingid], post[:refundamount], @options[:secret_key]]
187
+ when :tokenize; [post[:partnerid], post[:cardnumber], post[:cvv], @options[:secret_key]]
188
+ when :invalidate; [post[:partnerid], post[:token], @options[:secret_key]]
189
+ else [post[:toid], post[:totype], post[:amount], post[:description], post[:redirecturl],
190
+ post[:cardnumber] || post[:token], @options[:secret_key]]
191
+ end
192
+
193
+ post[:checksum] = Digest::MD5.hexdigest(checksum_elements.compact.join('|'))
194
+ end
195
+
196
+ def add_reference(post, authorization)
197
+ post[:trackingid] = authorization
198
+ end
199
+
200
+ ACTIONS = {
201
+ authorize: "SingleCallGenericServlet",
202
+ capture: "SingleCallGenericCaptureServlet",
203
+ void: "SingleCallGenericVoid",
204
+ refund: "SingleCallGenericReverse",
205
+ tokenize: "SingleCallTokenServlet",
206
+ invalidate: "SingleCallInvalidateToken",
207
+ tokenpay: "SingleCallTokenTransaction",
208
+ }
209
+
210
+ def commit(action, params)
211
+ response = begin
212
+ parse(ssl_post(url + ACTIONS[action], post_data(action, params), headers))
213
+ rescue ResponseError => e
214
+ parse(e.response.body)
215
+ end
216
+
217
+ success = success_from(response)
218
+
219
+ Response.new(
220
+ success,
221
+ message_from(response),
222
+ response,
223
+ authorization: success ? authorization_from(response) : nil,
224
+ cvv_result: success ? cvvresult_from(response) : nil,
225
+ error_code: success ? nil : error_from(response),
226
+ test: test?
227
+ )
228
+ end
229
+
230
+ def headers
231
+ {
232
+ "Accept" => "application/json",
233
+ "Content-Type" => "application/x-www-form-urlencoded;charset=UTF-8"
234
+ }
235
+ end
236
+
237
+ def post_data(action, params)
238
+ params.map {|k, v| "#{k}=#{CGI.escape(v.to_s)}"}.join('&')
239
+ end
240
+
241
+ def url
242
+ test? ? test_url : live_url
243
+ end
244
+
245
+ def parse(body)
246
+ begin
247
+ JSON.parse(body)
248
+ rescue JSON::ParserError
249
+ message = "Invalid JSON response received from CulqiGateway. Please contact CulqiGateway if you continue to receive this message."
250
+ message += "(The raw response returned by the API was #{body.inspect})"
251
+ {
252
+ "status" => "N",
253
+ "statusdescription" => message
254
+ }
255
+ end
256
+ end
257
+
258
+ def success_from(response)
259
+ response['status'] == 'Y'
260
+ end
261
+
262
+ def message_from(response)
263
+ response['statusdescription'] || response['statusDescription']
264
+ end
265
+
266
+ def authorization_from(response)
267
+ response['trackingid'] || response['token']
268
+ end
269
+
270
+ def cvvresult_from(response)
271
+ CVVResult.new(response['cvvresult'])
272
+ end
273
+
274
+ def error_from(response)
275
+ response['resultcode']
276
+ end
277
+ end
278
+ end
279
+ end
@@ -27,7 +27,7 @@ module ActiveMerchant #:nodoc:
27
27
  XSD_VERSION = "1.121"
28
28
 
29
29
  self.supported_cardtypes = [:visa, :master, :american_express, :discover]
30
- self.supported_countries = %w(US BR CA CN DK FI FR DE JP MX NO SE GB SG)
30
+ self.supported_countries = %w(US BR CA CN DK FI FR DE JP MX NO SE GB SG LB)
31
31
 
32
32
  self.default_currency = 'USD'
33
33
  self.currencies_without_fractions = %w(JPY)
@@ -274,6 +274,8 @@ module ActiveMerchant #:nodoc:
274
274
  message_from(response),
275
275
  response,
276
276
  authorization: authorization_from(action, response, amount),
277
+ avs_result: success_from(response) ? avs_from(response) : nil,
278
+ cvv_result: success_from(response) ? cvv_from(response) : nil,
277
279
  test: test?
278
280
  )
279
281
  end
@@ -294,6 +296,14 @@ module ActiveMerchant #:nodoc:
294
296
  response["expressresponsemessage"]
295
297
  end
296
298
 
299
+ def avs_from(response)
300
+ AVSResult.new(code: response["card"]["avsresponsecode"]) if response["card"]
301
+ end
302
+
303
+ def cvv_from(response)
304
+ CVVResult.new(response["card"]["cvvresponsecode"]) if response["card"]
305
+ end
306
+
297
307
  def split_authorization(authorization)
298
308
  authorization.split("|")
299
309
  end
@@ -226,9 +226,9 @@ module ActiveMerchant #:nodoc:
226
226
  end
227
227
 
228
228
  def add_credit_card(xml, credit_card, options)
229
-
230
229
  if credit_card.respond_to?(:track_data) && credit_card.track_data.present?
231
230
  xml.tag! "Track1", credit_card.track_data
231
+ xml.tag! "Ecommerce_Flag", "R"
232
232
  else
233
233
  xml.tag! "Card_Number", credit_card.number
234
234
  xml.tag! "Expiry_Date", expdate(credit_card)
@@ -23,7 +23,7 @@ module ActiveMerchant #:nodoc:
23
23
  def purchase(money, payment, options={})
24
24
  MultiResponse.run do |r|
25
25
  r.process { authorize(money, payment, options) }
26
- r.process { capture(money, r.authorization, options) }
26
+ r.process { capture(money, r.authorization, options) } unless capture_requested?(r)
27
27
  end
28
28
  end
29
29
 
@@ -290,6 +290,10 @@ EOS
290
290
  def nestable_hash
291
291
  Hash.new {|h,k| h[k] = Hash.new(&h.default_proc) }
292
292
  end
293
+
294
+ def capture_requested?(response)
295
+ response.params.try(:[], "payment").try(:[], "status") == "CAPTURE_REQUESTED"
296
+ end
293
297
  end
294
298
  end
295
299
  end
@@ -16,7 +16,7 @@ module ActiveMerchant #:nodoc:
16
16
  # However, regular accounts with DPS only support VISA and Mastercard
17
17
  self.supported_cardtypes = [ :visa, :master, :american_express, :diners_club, :jcb ]
18
18
 
19
- self.supported_countries = %w[ AU CA DE ES FR GB HK IE MY NL NZ SG US ZA ]
19
+ self.supported_countries = %w[ AU FJ GB HK IE MY NZ PG SG US ]
20
20
 
21
21
  self.homepage_url = 'http://www.paymentexpress.com/'
22
22
  self.display_name = 'PaymentExpress'
@@ -103,6 +103,18 @@ module ActiveMerchant #:nodoc:
103
103
  commit_periodic(build_periodic_item(:remove_triggered, options[:amount], nil, options))
104
104
  end
105
105
 
106
+ def supports_scrubbing?
107
+ true
108
+ end
109
+
110
+ def scrub(transcript)
111
+ transcript.
112
+ gsub(%r((<merchantID>).+(</merchantID>)), '\1[FILTERED]\2').
113
+ gsub(%r((<password>).+(</password>)), '\1[FILTERED]\2').
114
+ gsub(%r((<cardNumber>).+(</cardNumber>)), '\1[FILTERED]\2').
115
+ gsub(%r((<cvv>).+(</cvv>)), '\1[FILTERED]\2')
116
+ end
117
+
106
118
  private
107
119
 
108
120
  def build_purchase_request(money, credit_card, options)
@@ -380,7 +380,7 @@ module ActiveMerchant #:nodoc:
380
380
  card[:swipe_data] = creditcard.track_data
381
381
  card[:fallback_reason] = creditcard.fallback_reason if creditcard.fallback_reason
382
382
  card[:read_method] = "contactless" if creditcard.contactless_emv
383
- post[:read_method] = "contactless_magstripe_mode" if creditcard.contactless_magstripe
383
+ card[:read_method] = "contactless_magstripe_mode" if creditcard.contactless_magstripe
384
384
  else
385
385
  card[:number] = creditcard.number
386
386
  card[:exp_month] = creditcard.month
@@ -5,7 +5,7 @@ module ActiveMerchant
5
5
  class VancoGateway < Gateway
6
6
  include Empty
7
7
 
8
- self.test_url = 'https://www.vancodev.com/cgi-bin/wstest2.vps'
8
+ self.test_url = 'https://uat.vancopayments.com/cgi-bin/ws2.vps'
9
9
  self.live_url = 'https://myvanco.vancopayments.com/cgi-bin/ws2.vps'
10
10
 
11
11
  self.supported_countries = ['US']
@@ -10,6 +10,8 @@ module ActiveMerchant #:nodoc:
10
10
  self.default_currency = 'USD'
11
11
  self.display_name = 'WePay'
12
12
 
13
+ API_VERSION = "2016-12-07"
14
+
13
15
  def initialize(options = {})
14
16
  requires!(options, :client_id, :account_id, :access_token)
15
17
  super(options)
@@ -18,38 +20,47 @@ module ActiveMerchant #:nodoc:
18
20
  def purchase(money, payment_method, options = {})
19
21
  post = {}
20
22
  if payment_method.is_a?(String)
21
- purchase_with_token(post, money, payment_method, options)
23
+ MultiResponse.run do |r|
24
+ r.process { authorize_with_token(post, money, payment_method, options) }
25
+ r.process { capture(money, r.authorization, options) }
26
+ end
22
27
  else
23
28
  MultiResponse.run do |r|
24
29
  r.process { store(payment_method, options) }
25
- r.process { purchase_with_token(post, money, split_authorization(r.authorization).first, options) }
30
+ r.process { authorize_with_token(post, money, r.authorization, options) }
31
+ r.process { capture(money, r.authorization, options) }
26
32
  end
27
33
  end
28
34
  end
29
35
 
30
36
  def authorize(money, payment_method, options = {})
31
- post = {auto_capture: 0}
37
+ post = {}
32
38
  if payment_method.is_a?(String)
33
- purchase_with_token(post, money, payment_method, options)
39
+ authorize_with_token(post, money, payment_method, options)
34
40
  else
35
41
  MultiResponse.run do |r|
36
42
  r.process { store(payment_method, options) }
37
- r.process { purchase_with_token(post, money, split_authorization(r.authorization).first, options) }
43
+ r.process { authorize_with_token(post, money, r.authorization, options) }
38
44
  end
39
45
  end
40
46
  end
41
47
 
42
48
  def capture(money, identifier, options = {})
49
+ checkout_id, original_amount = split_authorization(identifier)
50
+
43
51
  post = {}
44
- post[:checkout_id] = split_authorization(identifier).first
45
- commit('/checkout/capture', post)
52
+ post[:checkout_id] = checkout_id
53
+ if(money && (original_amount != amount(money)))
54
+ post[:amount] = amount(money)
55
+ end
56
+ commit('/checkout/capture', post, options)
46
57
  end
47
58
 
48
59
  def void(identifier, options = {})
49
60
  post = {}
50
61
  post[:checkout_id] = split_authorization(identifier).first
51
62
  post[:cancel_reason] = (options[:description] || "Void")
52
- commit('/checkout/cancel', post)
63
+ commit('/checkout/cancel', post, options)
53
64
  end
54
65
 
55
66
  def refund(money, identifier, options = {})
@@ -61,10 +72,9 @@ module ActiveMerchant #:nodoc:
61
72
  post[:amount] = amount(money)
62
73
  end
63
74
  post[:refund_reason] = (options[:description] || "Refund")
64
- post[:app_fee] = options[:application_fee] if options[:application_fee]
65
75
  post[:payer_email_message] = options[:payer_email_message] if options[:payer_email_message]
66
76
  post[:payee_email_message] = options[:payee_email_message] if options[:payee_email_message]
67
- commit("/checkout/refund", post)
77
+ commit("/checkout/refund", post, options)
68
78
  end
69
79
 
70
80
  def store(creditcard, options = {})
@@ -76,53 +86,46 @@ module ActiveMerchant #:nodoc:
76
86
  post[:email] = options[:email] || "unspecified@example.com"
77
87
  post[:cc_number] = creditcard.number
78
88
  post[:cvv] = creditcard.verification_value unless options[:recurring]
79
- post[:expiration_month] = "#{creditcard.month}"
80
- post[:expiration_year] = "#{creditcard.year}"
89
+ post[:expiration_month] = creditcard.month
90
+ post[:expiration_year] = creditcard.year
81
91
  post[:original_ip] = options[:ip] if options[:ip]
82
92
  post[:original_device] = options[:device_fingerprint] if options[:device_fingerprint]
93
+
83
94
  if(billing_address = (options[:billing_address] || options[:address]))
84
- post[:address] = {
85
- "address1" => billing_address[:address1],
86
- "city" => billing_address[:city],
87
- "country" => billing_address[:country]
88
- }
89
- if(post[:country] == "US")
90
- post[:address]["zip"] = billing_address[:zip]
91
- post[:address]["state"] = billing_address[:state]
92
- else
93
- post[:address]["region"] = billing_address[:state]
94
- post[:address]["postcode"] = billing_address[:zip]
95
- end
95
+ post[:address] = {}
96
+ post[:address]["address1"] = billing_address[:address1] if billing_address[:address1]
97
+ post[:address]["city"] = billing_address[:city] if billing_address[:city]
98
+ post[:address]["country"] = billing_address[:country] if billing_address[:country]
99
+ post[:address]["region"] = billing_address[:state] if billing_address[:state]
100
+ post[:address]["postal_code"] = billing_address[:zip]
96
101
  end
97
102
 
98
103
  if options[:recurring] == true
99
104
  post[:client_secret] = @options[:client_secret]
100
- commit('/credit_card/transfer', post)
105
+ commit('/credit_card/transfer', post, options)
101
106
  else
102
- commit('/credit_card/create', post)
107
+ commit('/credit_card/create', post, options)
103
108
  end
104
109
  end
105
110
 
106
111
  private
107
112
 
108
- def purchase_with_token(post, money, token, options)
113
+ def authorize_with_token(post, money, token, options)
109
114
  add_token(post, token)
110
115
  add_product_data(post, money, options)
111
- commit('/checkout/create', post)
116
+ commit('/checkout/create', post, options)
112
117
  end
113
118
 
114
119
  def add_product_data(post, money, options)
115
120
  post[:account_id] = @options[:account_id]
116
121
  post[:amount] = amount(money)
117
122
  post[:short_description] = (options[:description] || "Purchase")
118
- post[:type] = (options[:type] || "GOODS")
123
+ post[:type] = (options[:type] || "goods")
119
124
  post[:currency] = (options[:currency] || currency(money))
120
125
  post[:long_description] = options[:long_description] if options[:long_description]
121
126
  post[:payer_email_message] = options[:payer_email_message] if options[:payer_email_message]
122
127
  post[:payee_email_message] = options[:payee_email_message] if options[:payee_email_message]
123
128
  post[:reference_id] = options[:order_id] if options[:order_id]
124
- post[:app_fee] = options[:application_fee] if options[:application_fee]
125
- post[:fee_payer] = options[:fee_payer] if options[:fee_payer]
126
129
  post[:redirect_uri] = options[:redirect_uri] if options[:redirect_uri]
127
130
  post[:callback_uri] = options[:callback_uri] if options[:callback_uri]
128
131
  post[:fallback_uri] = options[:fallback_uri] if options[:fallback_uri]
@@ -133,11 +136,26 @@ module ActiveMerchant #:nodoc:
133
136
  post[:preapproval_id] = options[:preapproval_id] if options[:preapproval_id]
134
137
  post[:prefill_info] = options[:prefill_info] if options[:prefill_info]
135
138
  post[:funding_sources] = options[:funding_sources] if options[:funding_sources]
139
+ add_fee(post, options)
136
140
  end
137
141
 
138
142
  def add_token(post, token)
139
- post[:payment_method_id] = token
140
- post[:payment_method_type] = "credit_card"
143
+ payment_method = {}
144
+ payment_method[:type] = "credit_card"
145
+ payment_method[:credit_card] = {
146
+ id: token,
147
+ auto_capture: false
148
+ }
149
+
150
+ post[:payment_method] = payment_method
151
+ end
152
+
153
+ def add_fee(post, options)
154
+ if options[:application_fee] || options[:fee_payer]
155
+ post[:fee] = {}
156
+ post[:fee][:app_fee] = options[:application_fee] if options[:application_fee]
157
+ post[:fee][:fee_payer] = options[:fee_payer] if options[:fee_payer]
158
+ end
141
159
  end
142
160
 
143
161
  def parse(response)
@@ -149,7 +167,7 @@ module ActiveMerchant #:nodoc:
149
167
  response = parse(ssl_post(
150
168
  ((test? ? test_url : live_url) + action),
151
169
  params.to_json,
152
- headers
170
+ headers(options)
153
171
  ))
154
172
  rescue ResponseError => e
155
173
  response = parse(e.response.body)
@@ -178,7 +196,8 @@ module ActiveMerchant #:nodoc:
178
196
  def authorization_from(response, params)
179
197
  return response["credit_card_id"].to_s if response["credit_card_id"]
180
198
 
181
- [response["checkout_id"], params[:amount]].join('|')
199
+ original_amount = response["amount"].nil? ? nil : sprintf("%0.02f", response["amount"])
200
+ [response["checkout_id"], original_amount].join('|')
182
201
  end
183
202
 
184
203
  def split_authorization(authorization)
@@ -192,14 +211,18 @@ module ActiveMerchant #:nodoc:
192
211
  return Response.new(false, message)
193
212
  end
194
213
 
195
- def headers
214
+ def headers(options)
196
215
  {
197
216
  "Content-Type" => "application/json",
198
217
  "User-Agent" => "ActiveMerchantBindings/#{ActiveMerchant::VERSION}",
199
- "Authorization" => "Bearer #{@options[:access_token]}"
218
+ "Authorization" => "Bearer #{@options[:access_token]}",
219
+ "Api-Version" => api_version(options)
200
220
  }
201
221
  end
222
+
223
+ def api_version(options)
224
+ options[:version] || API_VERSION
225
+ end
202
226
  end
203
227
  end
204
228
  end
205
-
@@ -239,6 +239,7 @@ module ActiveMerchant #:nodoc:
239
239
  when :reversal
240
240
  xml.tag! 'GuWID', options[:preauthorization]
241
241
  end
242
+ add_customer_data(xml, options)
242
243
  end
243
244
  end
244
245
  end
@@ -223,8 +223,11 @@ module ActiveMerchant #:nodoc:
223
223
 
224
224
  add_address(xml, (options[:billing_address] || options[:address]))
225
225
  end
226
- if options[:ip]
227
- xml.tag! 'session', 'shopperIPAddress' => options[:ip]
226
+ if options[:ip] && options[:session_id]
227
+ xml.tag! 'session', 'shopperIPAddress' => options[:ip], 'id' => options[:session_id]
228
+ else
229
+ xml.tag! 'session', 'shopperIPAddress' => options[:ip] if options[:ip]
230
+ xml.tag! 'session', 'id' => options[:session_id] if options[:session_id]
228
231
  end
229
232
  end
230
233
  end
@@ -238,6 +241,8 @@ module ActiveMerchant #:nodoc:
238
241
  end
239
242
 
240
243
  def add_address(xml, address)
244
+ return unless address
245
+
241
246
  address = address_with_defaults(address)
242
247
 
243
248
  xml.tag! 'cardAddress' do
@@ -1,3 +1,3 @@
1
1
  module ActiveMerchant
2
- VERSION = "1.62.0"
2
+ VERSION = "1.63.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.62.0
4
+ version: 1.63.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: 2016-12-05 00:00:00.000000000 Z
11
+ date: 2017-02-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -202,6 +202,7 @@ files:
202
202
  - lib/active_merchant/billing/gateways/conekta.rb
203
203
  - lib/active_merchant/billing/gateways/creditcall.rb
204
204
  - lib/active_merchant/billing/gateways/credorax.rb
205
+ - lib/active_merchant/billing/gateways/culqi.rb
205
206
  - lib/active_merchant/billing/gateways/cyber_source.rb
206
207
  - lib/active_merchant/billing/gateways/data_cash.rb
207
208
  - lib/active_merchant/billing/gateways/dibs.rb
@@ -395,7 +396,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
395
396
  requirements:
396
397
  - - ">="
397
398
  - !ruby/object:Gem::Version
398
- version: '2'
399
+ version: '2.1'
399
400
  required_rubygems_version: !ruby/object:Gem::Requirement
400
401
  requirements:
401
402
  - - ">="