class PedicelPay::TokenData

Constants

CURRENCIES
DateError
Error

Attributes

amount[RW]
cryptogram[RW]
currency[RW]
dm_id[RW]
eci[RW]
expiry[RW]
name[RW]
pan[RW]

Public Class Methods

new(pan: nil, expiry: nil, currency: nil, amount: nil, name: nil, dm_id: nil, cryptogram: nil, eci: nil) click to toggle source
# File lib/pedicel-pay/token_data.rb, line 31
def initialize(pan: nil, expiry: nil, currency: nil, amount: nil,
               name: nil, dm_id: nil, cryptogram: nil, eci: nil)
  @pan        = pan
  @expiry     = expiry
  @currency   = currency
  @amount     = amount
  @name       = name
  @dm_id      = dm_id
  @cryptogram = cryptogram
  @eci        = eci
end
sample_expiry(expired: nil, now: nil, soon: nil) click to toggle source
# File lib/pedicel-pay/token_data.rb, line 108
def self.sample_expiry(expired: nil, now: nil, soon: nil)
  # WARNING: Time calculations ahead!
  # Think very carefully about all the crazy corner cases.

  now  ||= Time.now
  soon ||= now + 5 * 60

  year  = sample_expiry_year(expired: expired, soon: soon)
  month = sample_expiry_month(expired: expired, year: year, now: now, soon: soon)

  require 'date'
  Date.civil(year, month, -1).strftime('%y%m%d')
end
sample_expiry_month(expired: nil, year:, now:, soon:) click to toggle source
# File lib/pedicel-pay/token_data.rb, line 135
def self.sample_expiry_month(expired: nil, year:, now:, soon:)
  # WARNING: Time calculations ahead!
  # Think very carefully about all the crazy corner cases.

  case expired
  when nil
    1..12
  when true
    year < now.year ? 1..12 : 1..(now.month - 1)
  when false
    raise DateError, 'cannot expire in a soon future year' if expired && year > soon.year

    year == soon.year ? 1..soon.month : 1..12
  end
    .to_a.sample
end
sample_expiry_year(expired: nil, soon:) click to toggle source
# File lib/pedicel-pay/token_data.rb, line 122
def self.sample_expiry_year(expired: nil, soon:)
  # WARNING: Time calculations ahead!
  # Think very carefully about all the crazy corner cases.

  case expired
  when nil   then -5..6
  when true  then -5..0
  when false then 0..6
  end
    .map { |i| soon.year + i }
    .to_a.sample
end

Public Instance Methods

card_expired?(now) click to toggle source
# File lib/pedicel-pay/token_data.rb, line 104
def card_expired?(now)
  Time.parse(expired) <= now
end
sample(expired: nil, pan_length: nil) click to toggle source
# File lib/pedicel-pay/token_data.rb, line 66
def sample(expired: nil, pan_length: nil)
  # PAN
  # Override @pan if pan_length doesn't match.
  if pan.nil? || (pan_length && pan.length != pan_length)
    pan_length ||= [12, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 19, 19, 19].sample

    self.pan = [ [2, 4, 5, 6].sample, *(2..pan_length).map { rand(0..9) } ].join
  end

  # Expiry
  # Override @expiry if it doesn't match `expired`.
  # WARNING: Time calculations ahead!
  # Think very carefully about all the crazy corner cases.
  now = Time.now
  if expiry.nil? || (expired ^ card_expired?(now)) # Cannot use "soon".
    self.expiry = self.class.sample_expiry(expired: expired, now: now, soon: now + 5 * 60)
  end

  # Currency
  self.currency ||= CURRENCIES.sample

  # Amount
  self.amount ||= rand(100..99_999)

  # Name

  # Device Manufacturer Identification
  self.dm_id ||= Helper.bytestring_to_hex(PedicelPay.config[:random].bytes(5))

  # Cryptogram
  self.cryptogram ||= Base64.strict_encode64(PedicelPay.config[:random].bytes(20))

  # ECI
  self.eci ||= %w[05 06 07].sample

  self
end
to_hash() click to toggle source
# File lib/pedicel-pay/token_data.rb, line 43
def to_hash
  data = { onlinePaymentCryptogram: cryptogram }
  data[:eciIndicator] = eci if eci

  result = {
    applicationPrimaryAccountNumber: pan,
    applicationExpirationDate: expiry,
    currencyCode: currency,
    transactionAmount: amount,
    deviceManufacturerIdentifier: dm_id,
    paymentDataType: '3DSecure',
    paymentData: data
  }

  result[:cardholderName] = name if name

  result
end
to_json() click to toggle source
# File lib/pedicel-pay/token_data.rb, line 62
def to_json
  to_hash.to_json
end