Class: Killbill::Cybersource::PaymentPlugin

Inherits:
Plugin::ActiveMerchant::PaymentPlugin
  • Object
show all
Defined in:
lib/cybersource/api.rb

Constant Summary collapse

FIVE_MINUTES_AGO =
(1 * 300)
ONE_HOUR_AGO =
(1 * 3600)
SIXTY_DAYS_AGO =
(60 * 86400)

Instance Method Summary collapse

Constructor Details

#initializePaymentPlugin

Returns a new instance of PaymentPlugin.



9
10
11
12
13
14
15
16
17
18
19
# File 'lib/cybersource/api.rb', line 9

def initialize
  gateway_builder = Proc.new do |config|
    ::ActiveMerchant::Billing::CyberSourceGateway.new :login => config[:login], :password => config[:password]
  end

  super(gateway_builder,
        :cybersource,
        ::Killbill::Cybersource::CybersourcePaymentMethod,
        ::Killbill::Cybersource::CybersourceTransaction,
        ::Killbill::Cybersource::CybersourceResponse)
end

Instance Method Details

#add_merchant_descriptor(transaction_type, properties, options) ⇒ Object



379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
# File 'lib/cybersource/api.rb', line 379

def add_merchant_descriptor(transaction_type, properties, options)
  merchant_descriptor = find_value_from_properties(properties, 'merchant_descriptor')
  return unless merchant_descriptor.present?

  merchant_descriptor_hash = JSON.parse(merchant_descriptor) rescue nil
  return unless merchant_descriptor_hash.present? && merchant_descriptor_hash.is_a?(Hash)

  merchant_descriptor_hash = merchant_descriptor_hash.with_indifferent_access

  merchant_descriptor_hash[:transaction_type] = transaction_type
  if merchant_descriptor_hash[:card_type].nil?
    merchant_descriptor_hash[:card_type] = ::Killbill::Plugin::ActiveMerchant::Utils.normalized(properties_to_hash(properties), :cc_type)
  end
  options[:merchant_descriptor] = merchant_descriptor_hash
end

#add_payment_method(kb_account_id, kb_payment_method_id, payment_method_props, set_default, properties, context) ⇒ Object



216
217
218
219
220
221
222
# File 'lib/cybersource/api.rb', line 216

def add_payment_method(, kb_payment_method_id, payment_method_props, set_default, properties, context)
  # Pass extra parameters for the gateway here
  options = {}

  properties = merge_properties(properties, options)
  super(, kb_payment_method_id, payment_method_props, set_default, properties, context)
end

#add_reconciliation_id(properties, options) ⇒ Object



395
396
397
398
# File 'lib/cybersource/api.rb', line 395

def add_reconciliation_id(properties, options)
  reconciliation_id = find_value_from_properties(properties, 'reconciliation_id')
  options[:reconciliation_id] = reconciliation_id if reconciliation_id.present?
end

#add_required_options(kb_account_id, properties, options, context) ⇒ Object



364
365
366
367
368
369
370
371
372
373
374
375
376
377
# File 'lib/cybersource/api.rb', line 364

def add_required_options(, properties, options, context)
  if options[:email].nil?
    email = find_value_from_properties(properties, 'email')
    if email.nil?
      # Note: we need to clone the context otherwise it will be transformed back to a Java one here
       = @kb_apis..(, @kb_apis.create_context(context.tenant_id))
      email = .email
    end
    options[:email] = email
  end

  ::Killbill::Plugin::ActiveMerchant::Utils.normalize_property(properties, 'ignore_avs')
  ::Killbill::Plugin::ActiveMerchant::Utils.normalize_property(properties, 'ignore_cvv')
end

#authorize_payment(kb_account_id, kb_payment_id, kb_payment_transaction_id, kb_payment_method_id, amount, currency, properties, context) ⇒ Object



29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/cybersource/api.rb', line 29

def authorize_payment(, kb_payment_id, kb_payment_transaction_id, kb_payment_method_id, amount, currency, properties, context)
  # Pass extra parameters for the gateway here
  options = {}

  add_required_options(, properties, options, context)
  add_merchant_descriptor(:AUTHORIZE, properties, options)
  add_reconciliation_id(properties, options)

  properties = merge_properties(properties, options)
  auth_response = super(, kb_payment_id, kb_payment_transaction_id, kb_payment_method_id, amount, currency, properties, context)

  # Error 234 is "A problem exists with your CyberSource merchant configuration", most likely the processor used doesn't support $0 auth for this card type
  if auth_response.gateway_error_code == '234' && to_cents(amount, currency) == 0
    h_props = properties_to_hash(properties)
    if ::Killbill::Plugin::ActiveMerchant::Utils.normalized(h_props, :force_validation)
      force_validation_amount = (::Killbill::Plugin::ActiveMerchant::Utils.normalized(h_props, :force_validation_amount) || 1).to_f
      auth_response = force_validation(auth_response, , kb_payment_id, kb_payment_transaction_id, kb_payment_method_id, force_validation_amount, currency, properties, context)
    end
  end

  auth_response
end

#before_gateway(gateway, kb_transaction, last_transaction, payment_source, amount_in_cents, currency, options, context) ⇒ Object

Make calls idempotent



320
321
322
323
324
325
326
327
328
329
330
331
# File 'lib/cybersource/api.rb', line 320

def before_gateway(gateway, kb_transaction, last_transaction, payment_source, amount_in_cents, currency, options, context)
  super

  merchant_reference_code = options[:order_id]
  report = get_report_for_kb_transaction(merchant_reference_code, kb_transaction, options, context)
  return nil if report.nil? || report.empty?

  logger.info "Skipping gateway call for existing kb_transaction_id='#{kb_transaction.id}', merchant_reference_code='#{merchant_reference_code}'"
  options[:skip_gw] = true
rescue => e
  logger.warn "Error checking for duplicate payment for merchant_reference_code='#{merchant_reference_code}': #{e.message}\n#{e.backtrace.join("\n")}"
end

#before_gateways(kb_transaction, last_transaction, payment_source, amount_in_cents, currency, options, context = nil) ⇒ Object



306
307
308
309
310
311
312
313
314
315
316
317
# File 'lib/cybersource/api.rb', line 306

def before_gateways(kb_transaction, last_transaction, payment_source, amount_in_cents, currency, options, context = nil)
  # Provide necessary information for merchant descriptor
  if options[:merchant_descriptor].present? &&
     options[:merchant_descriptor][:card_type].nil? &&
     payment_source.present? &&
     payment_source.respond_to?(:brand)

    options[:merchant_descriptor][:card_type] = payment_source.brand
  end

  super
end

#build_form_descriptor(kb_account_id, descriptor_fields, properties, context) ⇒ Object



264
265
266
267
268
269
270
271
272
273
274
275
276
# File 'lib/cybersource/api.rb', line 264

def build_form_descriptor(, descriptor_fields, properties, context)
  # Pass extra parameters for the gateway here
  options = {}
  properties = merge_properties(properties, options)

  # Add your custom static hidden tags here
  options = {
      #:token => config[:cybersource][:token]
  }
  descriptor_fields = merge_properties(descriptor_fields, options)

  super(, descriptor_fields, properties, context)
end

#capture_payment(kb_account_id, kb_payment_id, kb_payment_transaction_id, kb_payment_method_id, amount, currency, properties, context) ⇒ Object



52
53
54
55
56
57
58
59
60
61
62
# File 'lib/cybersource/api.rb', line 52

def capture_payment(, kb_payment_id, kb_payment_transaction_id, kb_payment_method_id, amount, currency, properties, context)
  # Pass extra parameters for the gateway here
  options = {}

  add_required_options(, properties, options, context)
  add_merchant_descriptor(:CAPTURE, properties, options)
  add_reconciliation_id(properties, options)

  properties = merge_properties(properties, options)
  super(, kb_payment_id, kb_payment_transaction_id, kb_payment_method_id, amount, currency, properties, context)
end

#credit_payment(kb_account_id, kb_payment_id, kb_payment_transaction_id, kb_payment_method_id, amount, currency, properties, context) ⇒ Object



84
85
86
87
88
89
90
91
92
93
# File 'lib/cybersource/api.rb', line 84

def credit_payment(, kb_payment_id, kb_payment_transaction_id, kb_payment_method_id, amount, currency, properties, context)
  # Pass extra parameters for the gateway here
  options = {}

  add_required_options(, properties, options, context)
  add_reconciliation_id(properties, options)

  properties = merge_properties(properties, options)
  super(, kb_payment_id, kb_payment_transaction_id, kb_payment_method_id, amount, currency, properties, context)
end

#delete_payment_method(kb_account_id, kb_payment_method_id, properties, context) ⇒ Object



224
225
226
227
228
229
230
# File 'lib/cybersource/api.rb', line 224

def delete_payment_method(, kb_payment_method_id, properties, context)
  # Pass extra parameters for the gateway here
  options = {}

  properties = merge_properties(properties, options)
  super(, kb_payment_method_id, properties, context)
end

#force_validation(auth_response, kb_account_id, kb_payment_id, kb_payment_transaction_id, kb_payment_method_id, amount, currency, properties, context) ⇒ Object

TODO: should this eventually be hardened and extracted into the base framework?



413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
# File 'lib/cybersource/api.rb', line 413

def force_validation(auth_response, , kb_payment_id, kb_payment_transaction_id, kb_payment_method_id, amount, currency, properties, context)
  # Trigger a non-$0 auth
  new_auth_response = nil
  begin
    # If duplicate checks are enabled, we need to bypass them (since a transaction for that merchant reference code was already attempted)
    properties << build_property(:bypass_duplicate_check, true)
    new_auth_response = authorize_payment(, kb_payment_id, kb_payment_transaction_id, kb_payment_method_id, amount, currency, properties, context)
  rescue => e
    # Note: state might be broken here (potentially two responses with the same kb_payment_transaction_id)
    @logger.warn("Unexpected exception while forcing validation for kb_payment_id='#{kb_payment_id}', kb_payment_transaction_id='#{kb_payment_transaction_id}': #{e.message}\n#{e.backtrace.join("\n")}")
    return auth_response
  end

  # Void it right away on success (make sure we didn't skip the gateway call too)
  if new_auth_response.status == :PROCESSED && !new_auth_response.first_payment_reference_id.blank?
    # The transaction id here is bogus, since it doesn't exist in Kill Bill
    void_properties = merge_properties(properties, { :external_key_as_order_id => false })
    begin
      void_payment(, kb_payment_id, SecureRandom.uuid, kb_payment_method_id, void_properties, context)
    rescue => e
      @logger.warn("Unexpected exception while voiding forced validation for kb_payment_id='#{kb_payment_id}', kb_payment_transaction_id='#{kb_payment_transaction_id}': #{e.message}\n#{e.backtrace.join("\n")}")
    end
  end

  # Finally, clean up the state of the original (failed) auth
  cybersource_response_id = find_value_from_properties(auth_response.properties, 'cybersourceResponseId')
  if cybersource_response_id.nil?
    @logger.warn "Unable to find cybersourceResponseId matching failed authorization for kb_payment_id='#{kb_payment_id}', kb_payment_transaction_id='#{kb_payment_transaction_id}'"
  else
    response = CybersourceResponse.find_by(:id => cybersource_response_id)
    if response.nil?
      @logger.warn "Unable to find response matching failed authorization for kb_payment_id='#{kb_payment_id}', kb_payment_transaction_id='#{kb_payment_transaction_id}'"
    else
      # Change the kb_payment_transaction_id to avoid confusing Kill Bill (there is no transaction row to update since the call wasn't successful)
      response.update(:kb_payment_transaction_id => SecureRandom.uuid)
    end
  end

  new_auth_response
end

#get_payment_info(kb_account_id, kb_payment_id, properties, context) ⇒ Object



112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
# File 'lib/cybersource/api.rb', line 112

def get_payment_info(, kb_payment_id, properties, context)
  # Pass extra parameters for the gateway here
  options = {}

  properties = merge_properties(properties, options)
  transaction_info_plugins = super(, kb_payment_id, properties, context)

  # Should never happen...
  return [] if transaction_info_plugins.nil?

  # Note: this won't handle the case where we don't have any record in the DB. While this should very rarely happen
  # (see Killbill::Plugin::ActiveMerchant::Gateway), we could use the CyberSource Payment Batch Detail Report to fix it.

  options = properties_to_hash(properties)

  initial_transaction = nil
  transaction_info_plugins.each do |transaction_info_plugin|
    initial_transaction = transaction_info_plugin if transaction_info_plugin.transaction_type == :AUTHORIZE || transaction_info_plugin.transaction_type == :PURCHASE || transaction_info_plugin.transaction_type == :CREDIT
  end

  # Should never happen (maybe transaction_type wasn't saved?)...
  initial_transaction = transaction_info_plugins.last if initial_transaction.nil?

  authorization = find_value_from_properties(initial_transaction.properties, 'authorization')
  order_id = Killbill::Plugin::ActiveMerchant::Utils.normalized(options, :order_id)
  # authorization is very likely nil, as we didn't get an answer from the gateway in the first place
  order_id ||= authorization.split(';')[0] unless authorization.nil?

  existing_request_ids = transaction_info_plugins.map{|trx_info| trx_info.first_payment_reference_id}.compact

  stale = false
  transaction_info_plugins.each do |transaction_info_plugin|
    # We only need to fix the UNDEFINED ones
    next unless transaction_info_plugin.status == :UNDEFINED

    cybersource_response_id = find_value_from_properties(transaction_info_plugin.properties, 'cybersourceResponseId')
    if cybersource_response_id.nil?
      logger.warn("Unable to fix UNDEFINED kb_transaction_id='#{transaction_info_plugin.kb_transaction_payment_id}' (cybersource_response_id not specified)")
      next
    end

    report_date = transaction_info_plugin.created_date
    delay_since_transaction = now - report_date
    delay_since_transaction = 0 if delay_since_transaction < 0

    # Give some time for CyberSource to update their records
    janitor_delay_threshold = (Killbill::Plugin::ActiveMerchant::Utils.normalized(options, :janitor_delay_threshold) || FIVE_MINUTES_AGO).to_i
    should_refresh_status = delay_since_transaction >= janitor_delay_threshold
    next unless should_refresh_status

    # Retrieve the report from CyberSource
    if order_id.nil?
      # order_id undetermined - try the defaults (see PaymentPlugin#dispatch_to_gateways)
      report = get_report(initial_transaction.kb_transaction_payment_id, report_date, options, context)
      if report.nil? || report.empty?
        kb_transaction = get_kb_transaction(kb_payment_id, initial_transaction.kb_transaction_payment_id, context.tenant_id)
        report = get_report(kb_transaction.external_key, report_date, options, context)
      end
    else
      report = get_report(order_id, report_date, options, context)
    end

    # Report API not configured, connection problem or skip_gw=true
    next if report.nil?

    threshold = (Killbill::Plugin::ActiveMerchant::Utils.normalized(options, :cancel_threshold) || ONE_HOUR_AGO).to_i
    should_cancel_payment = delay_since_transaction >= threshold
    if (report.empty? || report_not_match(report, transaction_info_plugin.first_payment_reference_id, existing_request_ids)) && !should_cancel_payment
      # We'll retry later
      logger.info("Unable to fix UNDEFINED kb_transaction_id='#{transaction_info_plugin.kb_transaction_payment_id}' (not found in CyberSource)")
      next
    else
      # Update our rows
      response = CybersourceResponse.find_by(:id => cybersource_response_id)
      if response.nil?
        logger.warn("Unable to fix UNDEFINED kb_transaction_id='#{transaction_info_plugin.kb_transaction_payment_id}' (CyberSource response='#{cybersource_response_id}' not found)")
        next
      end

      if should_cancel_payment
        # At this point, it's safe to assume the payment never happened
        logger.info("Canceling UNDEFINED kb_transaction_id='#{transaction_info_plugin.kb_transaction_payment_id}'")
        response.cancel
      else
        logger.info("Fixing UNDEFINED kb_transaction_id='#{transaction_info_plugin.kb_transaction_payment_id}', success='#{report.response.success?}'")
        response.update_and_create_transaction(report.response)
      end

      stale = true
    end
  end

  # If we updated the state, re-fetch the latest data
  stale ? super(, kb_payment_id, properties, context) : transaction_info_plugins
end

#get_payment_method_detail(kb_account_id, kb_payment_method_id, properties, context) ⇒ Object



232
233
234
235
236
237
238
# File 'lib/cybersource/api.rb', line 232

def get_payment_method_detail(, kb_payment_method_id, properties, context)
  # Pass extra parameters for the gateway here
  options = {}

  properties = merge_properties(properties, options)
  super(, kb_payment_method_id, properties, context)
end

#get_payment_methods(kb_account_id, refresh_from_gateway, properties, context) ⇒ Object



244
245
246
247
248
249
250
# File 'lib/cybersource/api.rb', line 244

def get_payment_methods(, refresh_from_gateway, properties, context)
  # Pass extra parameters for the gateway here
  options = {}

  properties = merge_properties(properties, options)
  super(, refresh_from_gateway, properties, context)
end

#get_report(merchant_reference_code, date, options, context) ⇒ Object

Janitor path



342
343
344
345
346
# File 'lib/cybersource/api.rb', line 342

def get_report(merchant_reference_code, date, options, context)
  report_api = get_report_api(options, context)
  return nil if report_api.nil?
  get_single_transaction_report(report_api, merchant_reference_code, date)
end

#get_report_api(options, context) ⇒ Object



400
401
402
403
404
405
406
407
408
409
410
# File 'lib/cybersource/api.rb', line 400

def get_report_api(options, context)
  return nil if options[:skip_gw] || options[:bypass_duplicate_check]
  cybersource_config = config(context.tenant_id)[:cybersource]
  return nil unless cybersource_config.is_a?(Array)
  on_demand_config = cybersource_config.find { |c| c[:account_id].to_s == 'on_demand' }
  return nil if on_demand_config.nil?
  CyberSourceOnDemand.new(on_demand_config, logger)
rescue => e
  @logger.warn("Unexpected exception while looking-up reporting API for kb_tenant_id='#{context.tenant_id}': #{e.message}\n#{e.backtrace.join("\n")}")
  nil
end

#get_report_for_kb_transaction(merchant_reference_code, kb_transaction, options, context) ⇒ Object

Duplicate check



334
335
336
337
338
339
# File 'lib/cybersource/api.rb', line 334

def get_report_for_kb_transaction(merchant_reference_code, kb_transaction, options, context)
  report_api = get_report_api(options, context)
  return nil if report_api.nil? || !report_api.check_for_duplicates?
  # kb_transaction is a Utils::LazyEvaluator, delay evaluation as much as possible
  get_single_transaction_report(report_api, merchant_reference_code, kb_transaction.created_date)
end

#get_single_transaction_report(report_api, merchant_reference_code, date, fuzzy_date = true) ⇒ Object



348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
# File 'lib/cybersource/api.rb', line 348

def get_single_transaction_report(report_api, merchant_reference_code, date, fuzzy_date=true)
  if fuzzy_date
    report = get_single_transaction_report(report_api, merchant_reference_code, date, false)
    report = get_single_transaction_report(report_api, merchant_reference_code, date - 1.day, false) if report.nil? || report.empty?
    report = get_single_transaction_report(report_api, merchant_reference_code, date + 1.day, false) if report.nil? || report.empty?
    return report
  end

  begin
    report_api.single_transaction_report(merchant_reference_code, date.strftime('%Y%m%d'))
  rescue => e
    logger.warn "Error retrieving report for merchant_reference_code='#{merchant_reference_code}', target_date='#{date}': #{e.message}\n#{e.backtrace.join("\n")}"
    nil
  end
end

#nowObject



454
455
456
457
# File 'lib/cybersource/api.rb', line 454

def now
  # We might want a 'util' function to make the conversion Joda DateTime to a Ruby Time object
  Time.parse(@clock.get_clock.get_utc_now.to_s)
end

#on_event(event) ⇒ Object



21
22
23
24
25
26
27
# File 'lib/cybersource/api.rb', line 21

def on_event(event)
  # Require to deal with per tenant configuration invalidation
  super(event)
  #
  # Custom event logic could be added below...
  #
end

#process_notification(notification, properties, context) ⇒ Object



278
279
280
281
282
283
284
285
286
287
288
289
290
# File 'lib/cybersource/api.rb', line 278

def process_notification(notification, properties, context)
  # Pass extra parameters for the gateway here
  options = {}
  properties = merge_properties(properties, options)

  super(notification, properties, context) do |gw_notification, service|
    # Retrieve the payment
    # gw_notification.kb_payment_id =
    #
    # Set the response body
    # gw_notification.entity =
  end
end

#purchase_payment(kb_account_id, kb_payment_id, kb_payment_transaction_id, kb_payment_method_id, amount, currency, properties, context) ⇒ Object



64
65
66
67
68
69
70
71
72
# File 'lib/cybersource/api.rb', line 64

def purchase_payment(, kb_payment_id, kb_payment_transaction_id, kb_payment_method_id, amount, currency, properties, context)
  # Pass extra parameters for the gateway here
  options = {}

  add_required_options(, properties, options, context)

  properties = merge_properties(properties, options)
  super(, kb_payment_id, kb_payment_transaction_id, kb_payment_method_id, amount, currency, properties, context)
end

#refund_payment(kb_account_id, kb_payment_id, kb_payment_transaction_id, kb_payment_method_id, amount, currency, properties, context) ⇒ Object



95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/cybersource/api.rb', line 95

def refund_payment(, kb_payment_id, kb_payment_transaction_id, kb_payment_method_id, amount, currency, properties, context)
  credit_opts = properties_to_hash(properties)
  if should_credit?(kb_payment_id, context, credit_opts)
    # Note: from the plugin perspective, this transaction is a CREDIT but Kill Bill doesn't care about PaymentTransactionInfoPlugin#TransactionType
    return credit_payment(, kb_payment_id, kb_payment_transaction_id, kb_payment_method_id, amount, currency, hash_to_properties(credit_opts), context)
  end

  # Pass extra parameters for the gateway here
  options = {}

  add_required_options(, properties, options, context)
  add_merchant_descriptor(:REFUND, properties, options)

  properties = merge_properties(properties, options)
  super(, kb_payment_id, kb_payment_transaction_id, kb_payment_method_id, amount, currency, properties, context)
end

#report_not_match(report, request_id, existing_request_ids) ⇒ Object



459
460
461
462
# File 'lib/cybersource/api.rb', line 459

def report_not_match(report, request_id, existing_request_ids)
  # Check if the response's request id is the request_id of a previous request. If so, then this report does not match.
  report.request_id.nil? || (request_id != report.request_id && existing_request_ids.include?(report.request_id))
end

#reset_payment_methods(kb_account_id, payment_methods, properties, context) ⇒ Object



260
261
262
# File 'lib/cybersource/api.rb', line 260

def reset_payment_methods(, payment_methods, properties, context)
  super
end

#search_payment_methods(search_key, offset, limit, properties, context) ⇒ Object



252
253
254
255
256
257
258
# File 'lib/cybersource/api.rb', line 252

def search_payment_methods(search_key, offset, limit, properties, context)
  # Pass extra parameters for the gateway here
  options = {}

  properties = merge_properties(properties, options)
  super(search_key, offset, limit, properties, context)
end

#search_payments(search_key, offset, limit, properties, context) ⇒ Object



208
209
210
211
212
213
214
# File 'lib/cybersource/api.rb', line 208

def search_payments(search_key, offset, limit, properties, context)
  # Pass extra parameters for the gateway here
  options = {}

  properties = merge_properties(properties, options)
  super(search_key, offset, limit, properties, context)
end

#set_default_payment_method(kb_account_id, kb_payment_method_id, properties, context) ⇒ Object



240
241
242
# File 'lib/cybersource/api.rb', line 240

def set_default_payment_method(, kb_payment_method_id, properties, context)
  # TODO
end

#should_credit?(kb_payment_id, context, options = {}) ⇒ Boolean

Returns:

  • (Boolean)


292
293
294
295
296
297
298
299
300
301
302
303
304
# File 'lib/cybersource/api.rb', line 292

def should_credit?(kb_payment_id, context, options = {})
  # Transform refunds on old payments into credits automatically unless the disable_auto_credit property is passed
  return false if Killbill::Plugin::ActiveMerchant::Utils.normalized(options, :disable_auto_credit)

  transaction = @transaction_model.find_candidate_transaction_for_refund(kb_payment_id, context.tenant_id)
  return false if transaction.nil?

  threshold = (Killbill::Plugin::ActiveMerchant::Utils.normalized(options, :auto_credit_threshold) || SIXTY_DAYS_AGO).to_i

  options[:payment_processor_account_id] ||= transaction.

  (now - transaction.created_at) >= threshold
end

#void_payment(kb_account_id, kb_payment_id, kb_payment_transaction_id, kb_payment_method_id, properties, context) ⇒ Object



74
75
76
77
78
79
80
81
82
# File 'lib/cybersource/api.rb', line 74

def void_payment(, kb_payment_id, kb_payment_transaction_id, kb_payment_method_id, properties, context)
  # Pass extra parameters for the gateway here
  options = {}

  add_required_options(, properties, options, context)

  properties = merge_properties(properties, options)
  super(, kb_payment_id, kb_payment_transaction_id, kb_payment_method_id, properties, context)
end