<commit_before># == Schema Information
#
# Table name: payments
#
#  id                   :integer          not null, primary key
#  user_id              :integer
#  completed            :boolean          default(FALSE), not null
#  cancelled            :boolean          default(FALSE), not null
#  transaction_id       :string(255)
#  completed_date       :datetime
#  created_at           :datetime
#  updated_at           :datetime
#  payment_date         :string(255)
#  note                 :string(255)
#  invoice_id           :string(255)
#  offline_pending      :boolean          default(FALSE), not null
#  offline_pending_date :datetime
#
# Indexes
#
#  index_payments_user_id  (user_id)
#

class Payment < ApplicationRecord
  include CachedModel

  scope :completed, -> { where(completed: true) }
  scope :completed_or_offline, -> { where("completed = TRUE or offline_pending = TRUE") }
  scope :offline_pending, -> { where(offline_pending: true) }

  validates :user_id, presence: true
  validate :transaction_id_or_note
  validates_associated :payment_details

  has_paper_trail

  belongs_to :user
  has_many :payment_details, inverse_of: :payment, dependent: :destroy
  accepts_nested_attributes_for :payment_details, reject_if: proc { |attributes| attributes['registrant_id'].blank? }, allow_destroy: true

  before_validation :set_invoice_id
  validates :invoice_id, presence: true, uniqueness: true

  after_save :update_registrant_items
  after_save :touch_payment_details
  after_save :inform_of_coupons

  def completed_or_offline?
    completed? || offline_pending?
  end

  def details
    return "(Offline Payment Pending)" if offline_pending?

    if transaction_id.present?
      return transaction_id
    end

    if note.present?
      return note
    end

    nil
  end

  def complete(options = {})
    assign_attributes(options)
    self.completed_date = Time.current
    self.completed = true
    self.offline_pending = false
    save
  end

  # Mark this payment as "will be paid offline"
  def offline_pay
    self.offline_pending_date = Time.current
    self.offline_pending = true
    save
  end

  # return a set of payment_details which are unique With-respect-to {amount, expense_item }
  def unique_payment_details
    results = []
    payment_details.each do |pd|
      res = nil
      results.each do |r|
        if r.expense_item_id == pd.line_item_id && r.amount == pd.amount
          res = r
          break
        end
      end

      if res.nil?
        results << PaymentDetailSummary.new(expense_item_id: pd.line_item_id, count: 1, amount: pd.amount)
      else
        res.count += 1
      end
    end
    results
  end

  def paypal_post_url
    EventConfiguration.paypal_base_url + "/cgi-bin/webscr"
  end

  def total_amount
    Money.new(payment_details.reduce(0.to_money) { |memo, pd| memo + pd.cost })
  end

  def self.total_refunded_amount
    total = 0.to_money
    PaymentDetail.refunded.includes(:payment).each do |payment_detail|
      total += payment_detail.cost
    end
    total
  end

  def self.total_received
    total = 0.to_money
    Payment.includes(payment_details: [:refund_detail]).completed.each do |payment|
      total += payment.total_amount
    end
    total
  end

  def self.paid_details
    all = []
    Registrant.all.find_each do |reg|
      all += reg.paid_details
    end
    all
  end

  def self.build_from_details(options)
    payment = Payment.new(
      completed: true,
      note: options[:note],
      completed_date: Time.current
    )
    payment.payment_details.build(
      registrant: options[:registrant],
      line_item: options[:item],
      details: options[:details],
      amount: options[:amount],
      free: false
    )
    payment
  end

  private
<commit_msg>eager load more data to make sum better<commit_after># == Schema Information
#
# Table name: payments
#
#  id                   :integer          not null, primary key
#  user_id              :integer
#  completed            :boolean          default(FALSE), not null
#  cancelled            :boolean          default(FALSE), not null
#  transaction_id       :string(255)
#  completed_date       :datetime
#  created_at           :datetime
#  updated_at           :datetime
#  payment_date         :string(255)
#  note                 :string(255)
#  invoice_id           :string(255)
#  offline_pending      :boolean          default(FALSE), not null
#  offline_pending_date :datetime
#
# Indexes
#
#  index_payments_user_id  (user_id)
#

class Payment < ApplicationRecord
  include CachedModel

  scope :completed, -> { where(completed: true) }
  scope :completed_or_offline, -> { where("completed = TRUE or offline_pending = TRUE") }
  scope :offline_pending, -> { where(offline_pending: true) }

  validates :user_id, presence: true
  validate :transaction_id_or_note
  validates_associated :payment_details

  has_paper_trail

  belongs_to :user
  has_many :payment_details, inverse_of: :payment, dependent: :destroy
  accepts_nested_attributes_for :payment_details, reject_if: proc { |attributes| attributes['registrant_id'].blank? }, allow_destroy: true

  before_validation :set_invoice_id
  validates :invoice_id, presence: true, uniqueness: true

  after_save :update_registrant_items
  after_save :touch_payment_details
  after_save :inform_of_coupons

  def completed_or_offline?
    completed? || offline_pending?
  end

  def details
    return "(Offline Payment Pending)" if offline_pending?

    if transaction_id.present?
      return transaction_id
    end

    if note.present?
      return note
    end

    nil
  end

  def complete(options = {})
    assign_attributes(options)
    self.completed_date = Time.current
    self.completed = true
    self.offline_pending = false
    save
  end

  # Mark this payment as "will be paid offline"
  def offline_pay
    self.offline_pending_date = Time.current
    self.offline_pending = true
    save
  end

  # return a set of payment_details which are unique With-respect-to {amount, expense_item }
  def unique_payment_details
    results = []
    payment_details.each do |pd|
      res = nil
      results.each do |r|
        if r.expense_item_id == pd.line_item_id && r.amount == pd.amount
          res = r
          break
        end
      end

      if res.nil?
        results << PaymentDetailSummary.new(expense_item_id: pd.line_item_id, count: 1, amount: pd.amount)
      else
        res.count += 1
      end
    end
    results
  end

  def paypal_post_url
    EventConfiguration.paypal_base_url + "/cgi-bin/webscr"
  end

  def total_amount
    Money.new(payment_details.reduce(0.to_money) { |memo, pd| memo + pd.cost })
  end

  def self.total_refunded_amount
    total = 0.to_money
    PaymentDetail.refunded.includes(:payment, refund_detail: :refund).each do |payment_detail|
      total += payment_detail.cost
    end
    total
  end

  def self.total_received
    total = 0.to_money
    Payment.includes(payment_details: [refund_detail: :refund]).completed.each do |payment|
      total += payment.total_amount
    end
    total
  end

  def self.paid_details
    all = []
    Registrant.all.find_each do |reg|
      all += reg.paid_details
    end
    all
  end

  def self.build_from_details(options)
    payment = Payment.new(
      completed: true,
      note: options[:note],
      completed_date: Time.current
    )
    payment.payment_details.build(
      registrant: options[:registrant],
      line_item: options[:item],
      details: options[:details],
      amount: options[:amount],
      free: false
    )
    payment
  end

  private

{'fraction_non_alphanumeric': 0.08282934525374704, 'fraction_numerical': 0.004470155140678412, 'mean_word_length': 2.7714427367377295, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3059704', 'n_tokens_mistral': 2416, 'n_tokens_neox': 2319, 'n_words': 570}