3scale/porta

View on GitHub
app/models/payment_detail.rb

Summary

Maintainability
A
0 mins
Test Coverage
# frozen_string_literal: true

class PaymentDetail < ApplicationRecord
  ATTRIBUTES = [:buyer_reference, :payment_service_reference, :credit_card_partial_number, :credit_card_expires_on].freeze

  attribute :credit_card_expires_on, :date

  class_attribute :notify_changes
  self.notify_changes = true

  belongs_to :account

  audited allow_mass_assignment: true

  attr_protected :account_id, :audit_ids

  validates :credit_card_partial_number, length: { :maximum => 4,
                                                   :allow_blank => true,
                                                   :message => "must be the final 4 digits only" }
  validates :buyer_reference, :payment_service_reference, :credit_card_partial_number, :credit_card_auth_code,
            :credit_card_authorize_net_payment_profile_token, :payment_method_id, length: {maximum: 255}

  alias_attribute :credit_card_auth_code, :buyer_reference
  alias_attribute :credit_card_authorize_net_payment_profile_token, :payment_service_reference

  after_commit :notify_credit_card_changes, if: :notify_changes?

  class CreditCardChangeNotifier
    attr_reader :account, :changes

    def initialize(account, changes)
      @account = account
      @changes = changes
    end

    def call
      credit_card_changes = changes.slice(*PaymentDetail::ATTRIBUTES)

      return if credit_card_changes.blank?

      ThreeScale::Analytics.track_account(account, 'Credit Card Changed', credit_card_changes_for_analytics(credit_card_changes))
      ThreeScale::Analytics.group(account)
    end

    protected

    def credit_card_changes_for_analytics(credit_card_changes)
      old_buyer_reference, new_buyer_reference = credit_card_changes[:buyer_reference]
      old_partial_number, new_partial_number = credit_card_changes[:credit_card_partial_number] || credit_card_changes[:payment_service_reference]
      old_expires_on, new_expires_on = credit_card_changes[:credit_card_expires_on]

      {
        valid_previously: (old_buyer_reference && old_partial_number).present?,
        valid_now: (new_buyer_reference && new_partial_number).present?,
        expires_on: new_expires_on,
        expired_on: old_expires_on
      }
    end
  end

  def changed_for_autosave?
    super && (persisted? || any_values?)
  end

  def any_values?
    ATTRIBUTES.any? { |attr| public_send(attr).present? }
  end

  def notify_changes?
    notify_changes
  end

  def do_not_notify
    self.notify_changes = false
  end

  private

  def notify_credit_card_changes
    CreditCardChangeNotifier.new(account, saved_changes).call
  end
end