Class: Client

Inherits:
ActiveRecord::Base
  • Object
show all
Includes:
IsActiveModelHelper
Defined in:
app/models/client.rb

Direct Known Subclasses

ClientAccounting

Instance Method Summary collapse

Methods included from IsActiveModelHelper

append_features, #initialize

Instance Method Details

#authorized_for?(options) ⇒ Boolean

Returns:

  • (Boolean)


68
69
70
71
72
73
74
75
76
77
# File 'app/models/client.rb', line 68

def authorized_for?(options)
  case options[:action]
    when :destroy
      [Invoice, Payment, Activity].each{ |k| return false if k.count(:all, :conditions => ['client_id = ?', id] ) > 0 }

      true
    else
      true
  end
end

#balance(force_reload = false) ⇒ Object

THis is the client’s outstanding balance. This value is calculated based off the total invoices amount - total payments amount. And is Not determined based on invoice/payment assignments



31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'app/models/client.rb', line 31

def balance( force_reload = false )
  Money.new(
    (attribute_present? :balance_in_cents and !force_reload) ?
      read_attribute(:balance_in_cents).to_i :
      Client.find(
      :first, 
      :select => [
        'id',
        'company_name',
        '(
         IF(charges.charges_sum_in_cents IS NULL, 0,charges.charges_sum_in_cents) - 
         IF(deposits.payment_sum_in_cents IS NULL, 0, deposits.payment_sum_in_cents)
        ) AS sum_difference_in_cents'
      ].join(', '),
      :joins => [
        "LEFT JOIN(
          SELECT invoices.client_id, SUM(#{Invoice::ACTIVITY_TOTAL_SQL}) AS charges_sum_in_cents 
            FROM invoices 
            LEFT JOIN activities ON activities.invoice_id = invoices.id 
            GROUP BY invoices.client_id
        ) AS charges ON charges.client_id = clients.id",
        
        'LEFT JOIN (
          SELECT payments.client_id, SUM(payments.amount_in_cents) AS payment_sum_in_cents
            FROM payments 
            GROUP BY payments.client_id
        ) AS deposits ON deposits.client_id = clients.id '
      ].join(' '),
      :conditions => [ 'clients.id = ?', id]
      ).sum_difference_in_cents.to_i
  ) unless id.nil?
end

#ensure_not_referenced_on_destroyObject



64
65
66
# File 'app/models/client.rb', line 64

def ensure_not_referenced_on_destroy
  errors.add_to_base "Can't destroy a referenced employee" and return false unless authorized_for? {:destroy}
end

#mailing_addressObject



79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'app/models/client.rb', line 79

def mailing_address
  ret = []
  
  %w( name address1 address2 ).each do |f|
    val = send(f.to_sym) and ( ret << val if val.length )
  end

  ret << '%s%s %s' % [
    (city.nil? or city.length == 0) ? '' : "#{city}, ", 
    state, 
    zip
  ]

  ret
end

#nameObject



19
20
21
# File 'app/models/client.rb', line 19

def name
  self.company_name
end

#recommend_invoice_assignments_for(amount) ⇒ Object

Returns an array of unsaved InvoicePayment objects, with unset payment_ids, and ‘recommended’ amounts. If the provided amount exactly equals an outstanding invoice’s amount, we return a InvoicePayment for the oldest such matching invoice. Otherwise, we start applying the amount to invoices in ascending order by issued_date.



98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# File 'app/models/client.rb', line 98

def recommend_invoice_assignments_for(amount)
  amount = amount.to_money

  invs = unpaid_invoices(
    :all,
    # Using this order forces the closest-amount match to be above anything else, followed by date sorting
    :order => '(amount_outstanding_in_cents = %d) DESC, issued_on ASC, created_at ASC' % amount.cents
  )

  unassigned_outstanding = invs.inject(Money.new(0)){|total, inv| total + inv.amount_outstanding}
  
  invs.collect{ |inv|
    if amount > 0 and unassigned_outstanding > 0
      assignment = (amount >= inv.amount_outstanding) ? 
          inv.amount_outstanding : 
          amount
      
      unassigned_outstanding -= assignment
      amount  -= assignment
      
      InvoicePayment.new :invoice => inv, :amount => assignment if assignment > 0
    end
  }.compact
end

#recommend_payment_assignments_for(amount, verbose_inclusion = false) ⇒ Object

Returns an array of unsaved InvoicePayment objects, with unset invoice_ids, and ‘recommended’ amounts. If the provided amount exactly equals an payment’s unalloated amount, we return a InvoicePayment for the oldest such matching payment. Otherwise, we start applying the amount to payments in ascending order by issued_date.



126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
# File 'app/models/client.rb', line 126

def recommend_payment_assignments_for(amount, verbose_inclusion = false)
  amount = amount.to_money
  
  pymnts = unassigned_payments(
    :all,
    # Using this order forces the closest-amount match to be above anything else, followed by date sorting
    :order => '(amount_unallocated_in_cents = %d) DESC, paid_on ASC, created_at ASC' % amount.cents
  )

  current_client_balance = pymnts.inject(Money.new(0)){|total, pmnt| total - pmnt.amount_unallocated}

  pymnts.collect{ |unallocated_pmnt|
    if amount > 0 or current_client_balance < 0
      assignment = (unallocated_pmnt.amount_unallocated > amount) ?
        amount :
        unallocated_pmnt.amount_unallocated
      
      current_client_balance += assignment
      amount -= assignment
      
      InvoicePayment.new :payment => unallocated_pmnt, :amount => assignment if assignment > 0
    end
  }.compact
end

#unassigned_payments(how_many = :all, options = {}) ⇒ Object

Returns all the client’s payments for which the invoice allocation is less than the payment amount. Perhaps this should be a has_many, But since we’re using the find_with_totals that would get complicated…



170
171
172
173
174
175
176
177
178
179
180
181
# File 'app/models/client.rb', line 170

def unassigned_payments( how_many = :all, options = {} )
  Payment.find_with_totals( 
    how_many, 
    {:conditions => [
      [
      'client_id = ?',
      '(payments.amount_in_cents - IF(payments_total.amount_allocated_in_cents IS NULL, 0, payments_total.amount_allocated_in_cents) ) > ?'
      ].join(' AND '),
      id, 0
    ]}.merge(options.reject{|k,v| k == :conditions}) 
  )
end

#uninvoiced_activities_balance(force_reload = false) ⇒ Object



23
24
25
26
27
# File 'app/models/client.rb', line 23

def uninvoiced_activities_balance( force_reload = false )
  (attribute_present? :uninvoiced_activities_balance_in_cents and !force_reload) ?
    Money.new(read_attribute(:uninvoiced_activities_balance_in_cents).to_i) :
    (Activity.sum( Invoice::ACTIVITY_TOTAL_SQL, :conditions => ['client_id = ? AND is_published = ? AND invoice_id IS NULL',id, true] ) or 0)
end

#unpaid_invoices(how_many = :all, options = {}) ⇒ Object

Returns all the client’s invoices for which the allocated payments is less than the invoice amount. Perhaps this should be a has_many, But since we’re using the find_with_totals that would get complicated…



153
154
155
156
157
158
159
160
161
162
163
164
165
166
# File 'app/models/client.rb', line 153

def unpaid_invoices( how_many = :all, options = {} )
  Invoice.find_with_totals(
    how_many, 
    {:conditions => [
      [
      'client_id = ?',
      'is_published = ?',
      'IF(activities_total.total_in_cents IS NULL, 0,activities_total.total_in_cents) - '+
      'IF(invoices_total.total_in_cents IS NULL, 0,invoices_total.total_in_cents) > ?'
      ].join(' AND '),
      id, true, 0
    ]}.merge(options.reject{|k,v| k == :conditions})
  )
end