Class: Payment

Inherits:
ActiveRecord::Base
  • Object
show all
Includes:
ExtensibleObjectHelper, MoneyModelHelper
Defined in:
app/models/payment.rb

Class Method Summary collapse

Instance Method Summary collapse

Methods included from MoneyModelHelper

append_features

Methods included from ExtensibleObjectHelper

append_features

Constructor Details

#initialize(*args) ⇒ Payment

Returns a new instance of Payment.



26
27
28
29
# File 'app/models/payment.rb', line 26

def initialize(*args)
  super(*args)
  self.paid_on = Time.now.beginning_of_day if paid_on.nil?
end

Class Method Details

.find_with_totals(how_many = :all, options = {}) ⇒ Object



105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# File 'app/models/payment.rb', line 105

def self.find_with_totals( how_many = :all, options = {} )
  cast_amount_allocated = 'IF(payments_total.amount_allocated_in_cents IS NULL, 0, payments_total.amount_allocated_in_cents)'
  
  joins = 'LEFT JOIN ('+
    'SELECT payment_id, SUM(amount_in_cents) AS amount_allocated_in_cents FROM invoice_payments GROUP BY payment_id'+
  ') AS payments_total ON payments_total.payment_id = payments.id'
  
  Payment.find( 
    how_many,
    {
      :select => [
        'payments.id',
        'payments.amount_in_cents',
        "#{cast_amount_allocated} AS amount_allocated_in_cents",
        "payments.amount_in_cents - #{cast_amount_allocated} AS amount_unallocated_in_cents"
      ].join(', '),
      :order => 'paid_on ASC',
      :joins => joins,
      :group => 'payments.id'
    }.merge(options)
  )
end

Instance Method Details

#amount_allocated(force_reload = false) ⇒ Object



37
38
39
40
41
42
43
# File 'app/models/payment.rb', line 37

def amount_allocated( force_reload = false )
  Money.new(  
    (attribute_present? :amount_allocated_in_cents  and !force_reload) ? 
      read_attribute(:amount_allocated_in_cents).to_i : 
      ( invoice_assignments(force_reload).collect(&:amount_in_cents).sum || 0 )
  )
end

#amount_unallocated(force_reload = false) ⇒ Object



31
32
33
34
35
# File 'app/models/payment.rb', line 31

def amount_unallocated( force_reload = false )
  (attribute_present? :amount_unallocated_in_cents  and !force_reload) ? 
    Money.new(read_attribute(:amount_unallocated_in_cents).to_i) : 
    (amount(force_reload) - amount_allocated(force_reload))
end

#is_allocated?(force_reload = false) ⇒ Boolean

Returns:

  • (Boolean)


45
46
47
48
49
# File 'app/models/payment.rb', line 45

def is_allocated?( force_reload = false )
  (attribute_present? :is_allocated  and !force_reload) ? 
    (read_attribute(:is_allocated).to_i == 1) :
    amount_unallocated(force_reload).zero?
end

#nameObject



101
102
103
# File 'app/models/payment.rb', line 101

def name  
  '%s Payment from %s'  % [ amount.format, client.company_name ]
end

#validate_invoice_payments_not_greater_than_amountObject



51
52
53
54
55
56
57
58
59
# File 'app/models/payment.rb', line 51

def validate_invoice_payments_not_greater_than_amount    
  my_amount = self.amount
  assignment_amount = self.invoice_assignments.inject(Money.new(0)){|sum,ip| ip.amount+sum }
  
  # We use the funky :> /:< to differentiate between the case of a credit invoice and a (normal?) invoice
  errors.add :invoice_assignments, "exceeds payment amount" if assignment_amount.send(
    (my_amount >= 0) ? :> : :<, my_amount
  )
end

#validate_invoice_payments_not_greater_than_invoice_amountObject



61
62
63
64
65
66
67
68
69
70
71
72
# File 'app/models/payment.rb', line 61

def validate_invoice_payments_not_greater_than_invoice_amount
  invoice_assignments.each do |asgn|
    errors.add(
      :invoice_assignments, 
      "has an invalid assignment whose amount (%s) is greater than invoice #%d's amount (%s)" % [
        asgn.amount.to_s,
        asgn.invoice.id,
        asgn.invoice.amount.to_s
      ]
    ) if asgn.amount > asgn.invoice.amount
  end
end

#validate_invoice_payments_not_negativeObject



85
86
87
88
89
90
91
92
93
94
# File 'app/models/payment.rb', line 85

def validate_invoice_payments_not_negative
  invoice_assignments.each do |asgn|
    errors.add(
      :invoice_assignments, 
      "has an invalid assignment with a negative value applied to invoice #%d" % [
        asgn.invoice.id
      ]
    ) if asgn.amount < 0
  end
end

#validate_invoice_payments_only_assigned_to_published_invoicesObject



74
75
76
77
78
79
80
81
82
83
# File 'app/models/payment.rb', line 74

def validate_invoice_payments_only_assigned_to_published_invoices
  invoice_assignments.each do |asgn|
    errors.add(
      :invoice_assignments, 
      "has an invalid assignment which is applied to an unpublished invoice #%d" % [
        asgn.invoice.id
      ]
    ) unless asgn.invoice.is_published
  end
end

#validate_on_updateObject

We don’t want any actual fields changing on update. But, we do want the assignments to be changeable…



97
98
99
# File 'app/models/payment.rb', line 97

def validate_on_update
  errors.add_to_base "Payments can't be updated after creation" if changed.length > 0
end