Class: CreditCardVault

Inherits:
ApplicationRecord show all
Includes:
Models::Auditable
Defined in:
app/models/credit_card_vault.rb

Overview

== Schema Information

Table name: credit_card_vaults
Database name: primary

id :integer not null, primary key
address_city :string
address_country :string
address_line1 :string
address_line1_check :string
address_line2 :string
address_state :string
address_zip_check :string
card_type :string(255)
consent_channel :string
consent_given_at :datetime
cvc_check :string
description :string
exp_month :integer
exp_year :integer
expiration_date :date
hidden :boolean
issuer_number :string
name :string
number :string(255) not null
stripe_detached_at :datetime
zip_code :string(10)
created_at :datetime
updated_at :datetime
creator_id :integer
customer_id :integer not null
updater_id :integer
vault_id :string

Indexes

customer_id_expiration_date (customer_id,expiration_date)
index_credit_card_vaults_on_vault_id (vault_id)

Foreign Keys

fk_rails_... (customer_id => parties.id)

Constant Summary collapse

%w[www crm_phone crm_manual].freeze

Constants included from Models::Auditable

Models::Auditable::ALWAYS_IGNORED

Instance Attribute Summary collapse

Belongs to collapse

Methods included from Models::Auditable

#creator, #updater

Has many collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Models::Auditable

#all_skipped_columns, #audit_reference_data, #should_not_save_version, #stamp_record

Methods inherited from ApplicationRecord

ransackable_associations, ransackable_attributes, ransackable_scopes, ransortable_attributes, #to_relation

Methods included from Models::EventPublishable

#publish_event

Instance Attribute Details

#address_line1Object (readonly)



55
# File 'app/models/credit_card_vault.rb', line 55

validates :customer_id, :vault_id, :number, :exp_year, :exp_month, :address_line1, :zip_code, :address_state, presence: true

#address_stateObject (readonly)



55
# File 'app/models/credit_card_vault.rb', line 55

validates :customer_id, :vault_id, :number, :exp_year, :exp_month, :address_line1, :zip_code, :address_state, presence: true

#card_tokenObject

Returns the value of attribute card_token.



63
64
65
# File 'app/models/credit_card_vault.rb', line 63

def card_token
  @card_token
end

#customer_idObject (readonly)



55
# File 'app/models/credit_card_vault.rb', line 55

validates :customer_id, :vault_id, :number, :exp_year, :exp_month, :address_line1, :zip_code, :address_state, presence: true

#exp_monthObject (readonly)



55
# File 'app/models/credit_card_vault.rb', line 55

validates :customer_id, :vault_id, :number, :exp_year, :exp_month, :address_line1, :zip_code, :address_state, presence: true

#exp_yearObject (readonly)



55
# File 'app/models/credit_card_vault.rb', line 55

validates :customer_id, :vault_id, :number, :exp_year, :exp_month, :address_line1, :zip_code, :address_state, presence: true

#numberObject (readonly)



55
# File 'app/models/credit_card_vault.rb', line 55

validates :customer_id, :vault_id, :number, :exp_year, :exp_month, :address_line1, :zip_code, :address_state, presence: true

#vault_idObject (readonly)



55
# File 'app/models/credit_card_vault.rb', line 55

validates :customer_id, :vault_id, :number, :exp_year, :exp_month, :address_line1, :zip_code, :address_state, presence: true

#zip_codeObject (readonly)



55
# File 'app/models/credit_card_vault.rb', line 55

validates :customer_id, :vault_id, :number, :exp_year, :exp_month, :address_line1, :zip_code, :address_state, presence: true

Class Method Details

.cleanup_invalid_valuesObject



95
96
97
98
99
100
101
# File 'app/models/credit_card_vault.rb', line 95

def self.cleanup_invalid_values
  # zip
  CreditCardVault.where.not(zip_code: nil).find_each do |ccv|
    new_zip = Normalizr.normalize(ccv.zip_code, :strip, :no_undefined, :blank, :zip_or_postal_code)
    ccv.update_column(:zip_code, new_zip) unless new_zip == ccv.zip_code
  end
end

.consentedActiveRecord::Relation<CreditCardVault>

A relation of CreditCardVaults that are consented. Active Record Scope

Returns:

See Also:



69
# File 'app/models/credit_card_vault.rb', line 69

scope :consented, -> { where.not(consent_given_at: nil) }

.detachedActiveRecord::Relation<CreditCardVault>

A relation of CreditCardVaults that are detached. Active Record Scope

Returns:

See Also:



68
# File 'app/models/credit_card_vault.rb', line 68

scope :detached, -> { where.not(stripe_detached_at: nil) }

.expiredActiveRecord::Relation<CreditCardVault>

A relation of CreditCardVaults that are expired. Active Record Scope

Returns:

See Also:



66
# File 'app/models/credit_card_vault.rb', line 66

scope :expired, -> { where('credit_card_vaults.expiration_date <= ?', Date.current) }

A relation of CreditCardVaults that are hidden without consent. Active Record Scope

Returns:

See Also:



70
# File 'app/models/credit_card_vault.rb', line 70

scope :hidden_without_consent, -> { where(hidden: true).where(consent_given_at: nil) }

.sync_stripe_status!(customer) ⇒ Object



72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'app/models/credit_card_vault.rb', line 72

def self.sync_stripe_status!(customer)
  return unless customer&.stripe_customer_id.present?

  currency = customer.catalog&.currency || 'USD'
  stripe_pms = Payment::Apis::Stripe.list_payment_methods(
    customer.stripe_customer_id, currency: currency
  )
  attached_pm_ids = stripe_pms.data.map(&:id).to_set

  customer.credit_card_vaults.where.not(vault_id: nil).find_each do |vault|
    pm_id = vault.vault_id
    next if pm_id.include?('|') # skip legacy cus_xxx|card_xxx IDs

    if attached_pm_ids.include?(pm_id)
      vault.update_columns(stripe_detached_at: nil) if vault.stripe_detached_at.present?
    else
      vault.update_columns(stripe_detached_at: Time.current) if vault.stripe_detached_at.nil?
    end
  end
rescue ::Stripe::StripeError => e
  Rails.logger.warn("[CreditCardVault] Stripe sync failed for customer #{customer.id}: #{e.message}")
end

.validActiveRecord::Relation<CreditCardVault>

A relation of CreditCardVaults that are valid. Active Record Scope

Returns:

See Also:



65
# File 'app/models/credit_card_vault.rb', line 65

scope :valid, -> { where('credit_card_vaults.expiration_date > ?', Date.current) }

.visibleActiveRecord::Relation<CreditCardVault>

A relation of CreditCardVaults that are visible. Active Record Scope

Returns:

See Also:



67
# File 'app/models/credit_card_vault.rb', line 67

scope :visible, -> { where('hidden is null or hidden = false').where(stripe_detached_at: nil) }

Instance Method Details

#address_to_stringObject



111
112
113
# File 'app/models/credit_card_vault.rb', line 111

def address_to_string
  [address_line1, address_line2, address_city, address_state, zip_code, address_country].compact.join(', ')
end


119
120
121
122
123
124
125
126
127
128
129
130
# File 'app/models/credit_card_vault.rb', line 119

def consent_channel_label
  return nil if consent_channel.blank?

  channel, person = consent_channel.split(':', 2)
  label = case channel
          when 'www' then 'Website'
          when 'crm_phone' then 'Phone'
          when 'crm_manual' then 'Manual entry'
          else channel.humanize
          end
  person.present? ? "#{label} by #{person}" : label
end

#consented?Boolean

Returns:

  • (Boolean)


115
116
117
# File 'app/models/credit_card_vault.rb', line 115

def consented?
  consent_given_at.present?
end

#customerCustomer

Returns:

See Also:



57
# File 'app/models/credit_card_vault.rb', line 57

belongs_to :customer, optional: true

#expired?Boolean

Returns:

  • (Boolean)


107
108
109
# File 'app/models/credit_card_vault.rb', line 107

def expired?
  expiration_date <= Date.current
end

#grant_consent!(channel) ⇒ Object



132
133
134
# File 'app/models/credit_card_vault.rb', line 132

def grant_consent!(channel)
  update!(consent_given_at: Time.current, consent_channel: channel, hidden: false)
end

#paymentsActiveRecord::Relation<Payment>

Returns:

  • (ActiveRecord::Relation<Payment>)

See Also:



58
# File 'app/models/credit_card_vault.rb', line 58

has_many :payments, foreign_key: 'vault_id', primary_key: 'vault_id'

#set_expirationObject (protected)



145
146
147
# File 'app/models/credit_card_vault.rb', line 145

def set_expiration
  self.expiration_date = Date.new(exp_year, exp_month, -1) if exp_year.present? and exp_month.present?
end

#store_card(email = nil) ⇒ Object



136
137
138
139
140
141
# File 'app/models/credit_card_vault.rb', line 136

def store_card(email = nil)
  return unless vault_id.nil?

  res = Payment::Gateways::CreditCard.new.store(self, email)
  res.success
end

#summaryObject



103
104
105
# File 'app/models/credit_card_vault.rb', line 103

def summary
  "Type: #{card_type} | #: #{number} | Name: #{name} | Exp: #{exp_month}/#{exp_year}"
end