Skip to content

Instantly share code, notes, and snippets.

@stefanoverna
Created July 27, 2011 14:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save stefanoverna/1109504 to your computer and use it in GitHub Desktop.
Save stefanoverna/1109504 to your computer and use it in GitHub Desktop.
# -*- encoding : utf-8 -*-
class Invoice < ActiveRecord::Base
paginates_per 15
belongs_to :campaign
has_and_belongs_to_many :tasks
has_many :expense_notes
validates_presence_of :campaign
validates_presence_of :start_date
validates_presence_of :end_date
validates_presence_of :expiration_period
validate :validate_end_date
validate :invalid_invoice_period
validate :intersecting_invoices
validate :presence_of_non_invoiced_good_hours_in_some_task
before_validation :set_start_date_if_blank
after_create :invoice_tasks
after_create :invoice_expense_notes
def tasks_hours
tasks.inject(0) do |hours, task|
hours + task.total_good_hours_in_period(:do_not_invoice, start_date, end_date)
end
end
def tasks_amount
invoiced_hours * campaign.try(:hourly_price)
end
def expense_notes_amount
expense_notes.inject(0) do |amount, expense_note|
amount + expense_note.amount
end
end
def amount
tasks_amount + expense_notes_amount
end
private
######### BEFORE VALIDATION #########
def set_start_date_if_blank
if start_date.blank?
self.start_date = if campaign.invoices.blank?
campaign.activities.minimum(:estimated_start_date)
else
campaign.invoices.maximum(:end_date).advance(:days => 1)
end
end
end
######### VALIDAZIONI ###########
def presence_of_non_invoiced_good_hours_in_some_task
# perche possa creare una fattura
if campaign.present?
# almeno uno tra i task della campagna
campaign.activities.map(&:tasks).flatten.any? do |task|
# deve avere qualche ora da fatturare nel periodo della fattura stessa
task.total_good_hours_in_period(:do_not_invoice, start_date, end_date).nonzero?
end
end
end
def validate_end_date
# la data di inizio fattura dev'essere precedente a quella di fine
if start_date.present? && end_date.present? && end_date < start_date
errors.add :end_date, I18n.t("activerecord.errors.models.contract.attributes.end_date.lower_than_start_date")
end
end
def invalid_invoice_period
if end_date.present? && start_date.present? && campaign.present? && campaign.activities.present?
# la data di inizio fattura dev'essere superiore alla data di inizio campagna
if start_date < campaign.activities.minimum(:estimated_start_date)
errors.add :start_date, I18n.t("activerecord.errors.models.invoice.attributes.start_date.lower_than_campaign_start")
# la data di termine fattura dev'essere inferiore o uguale alla fine campagna
elsif end_date > campaign.activities.maximum(:estimated_end_date)
errors.add :end_date, I18n.t("activerecord.errors.models.invoice.attributes.end_date.greater_than_campaign_end")
end
end
end
def intersecting_invoices
# non posso avere due fatture con periodo di appartenenza intersecante
if start_date.present? && campaign.present? && campaign.invoices.present? && start_date <= (campaign.invoices - self).max(:end_date)
errors.add :end_date, I18n.t("activerecord.errors.models.invoice.attributes.end_date.lower_than_previous")
end
end
########## AFTER CREATE ###########
def invoice_tasks
campaign.activities.map(&:tasks).flatten.each do |task|
if task.total_good_hours_in_period(:do_not_invoice, start_date, end_date).nonzero?
task.invoices << self
end
end
end
def invoice_expense_notes
campaign.activities.map(&:expense_notes).each do |expense_note|
if expense_note.spending_date <= end_date && expense_note.spending_date >= start_date
self.expense_notes << expense_note
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment