Skip to content

Instantly share code, notes, and snippets.

@ksob
Created May 30, 2014 14:21
Show Gist options
  • Save ksob/af9031dd6525b3e96258 to your computer and use it in GitHub Desktop.
Save ksob/af9031dd6525b3e96258 to your computer and use it in GitHub Desktop.
sageone_pl/sopl_accounts/app/models/sopl_accounts/fixed_asset.rb --- after refactoring - duplication removed - flog/flay
module SoplAccounts
class FixedAsset < ActiveRecord::Base
self.table_name = :fixed_assets
belongs_to :business
has_one :sales_invoice, class_name: 'FujiInvoicing::SalesInvoice'
has_many :fixed_assets_amortizations, class_name: 'SoplAccounts::FixedAssetsAmortization', dependent: :delete_all
after_initialize :set_placed_in_service_date_defaults,
:set_acquisition_date_defaults,
:set_amortization_date_defaults,
:set_amortization_method_defaults,
:set_accumulated_depreciation_defaults,
:set_starting_value_defaults,
:set_amortization_rate_defaults
before_save :build_amortization_plan
scope :filter_by_name, ->(term) { where('UPPER(name) LIKE ?', "%#{term}%") }
scope :filter_by_service_date,
->(term) { where('MONTH(placed_in_service_date) = ?', "#{term}") }
scope :sort_by_liquidation_or_sale_date, ->(order) { order("coalesce(liquidation_date, sale_date) #{order}") }
validates :name, presence: true
validates :placed_in_service_date, presence: true
validates :acquisition_date, presence: true
validates :amortization_date, presence: true
validates :classification, presence: true
validates :amortization_rate, presence: true
validates :starting_value, presence: true
validates :amortization_rate, :numericality =>
{ :greater_than => 0.00, :less_than_or_equal_to => 100.00 }
validates :starting_value, :numericality =>
{ :greater_than => 0.00, :less_than => 10000000000000.00 }
validates :accumulated_depreciation, :numericality =>
{ :less_than => 10000000000000.00 }
validate :ensure_placed_in_service_date_grater_or_equal_acquisition_date
validate :ensure_amortization_date_grater_or_equal_placed_in_service_date
validate :ensure_starting_value_grater_or_equal_accumulated_depreciation
validates :liquidation_date, presence: true, if: ->(r) { r.liquidation_date.present? }
validates :liquidation_reason, presence: true, if: ->(r) { r.liquidation_date.present? }
attr_accessible :accumulated_depreciation, :acquisition_date, :amortization_date,
:amortization_method, :amortization_rate, :classification,
:description, :invoice_number, :name,
:placed_in_service_date, :starting_value,
:liquidation_date, :liquidation_reason
grid_data_is :name, :placed_in_service_date, :acquisition_date,
:starting_value, :accumulated_depreciation,
:liquidation_or_sale_date
def formatted
name
end
def liquidation_or_sale_date
liquidation_date.presence || sale_date.presence
end
def depreciations_this_month
0 # TODO
end
def depreciations_cumulatively_this_year
0 # TODO
end
def left_to_depreciate
fixed_assets_amortizations.sum(:amount) - fixed_assets_amortizations.where(accounted: true).sum(:amount)
end
def updated_starting_value
0 # TODO
end
def liquidated?
liquidation_date?
end
def sold?
sales_invoice.present?
end
def editable?
!liquidated? && !sold?
end
def recalculate_amortization_plan(attrs)
FixedAsset.transaction do
base = (starting_value - accumulated_depreciation)
total = 0
fixed_assets_amortizations.where(accounted: false).each do |record|
new_val = attrs[record.id.to_s]
record.amount = new_val
total += record.amount
if record.amount_changed? && total > base
raise "incorrect"
end
end
total = 0
yearly_total = 0
fixed_assets_amortizations.where(accounted: true).each do |record|
total += record.amount
end
year = amortization_date.year
month = amortization_date.month
yearly_amount = (starting_value * amortization_rate / 100.0).round(2)
monthly_amount = (yearly_amount / 12.0).round(2)
# we can't use monthly amount here because calculations don't match algorithm
first_year_amount = ((yearly_amount / 12.0) * (12 - month + 1)).round(2)
fixed_assets_amortizations.where(accounted: false).each do |record|
new_val = attrs[record.id.to_s]
total += new_val.to_f
if total > base
record.destroy
else
record.amount = new_val
record.modified = true if record.amount_changed?
record.save
end
end
last_record = fixed_assets_amortizations.where(accounted: false).order('id DESC').first
last_record.destroy # remove record without full amount
last_record = fixed_assets_amortizations.where(accounted: false).order('id DESC').first
total = 0
fixed_assets_amortizations.each do |record|
total += record.amount
end
year = last_record.year
month = last_record.month + 1
if month > 12
month = 1
year += 1
end
fixed_assets_amortizations.where(year: year).each do |record|
yearly_total += record.amount
end
eval common_amortization_code "create!"
true
end
rescue
false
end
def reset_amortization_plan
FixedAsset.transaction do
fixed_assets_amortizations.where(accounted: false).delete_all
total = 0
yearly_total = 0
fixed_assets_amortizations.each do |record|
total += record.amount
end
last_record = fixed_assets_amortizations.order('id DESC').first
year = amortization_date.year
month = amortization_date.month
base = (starting_value - accumulated_depreciation)
yearly_amount = (starting_value * amortization_rate / 100.0).round(2)
monthly_amount = (yearly_amount / 12.0).round(2)
# we can't use monthly amount here because calculations don't match algorithm
first_year_amount = ((yearly_amount / 12.0) * (12 - month + 1)).round(2)
if last_record
year = last_record.year
month = last_record.month + 1
if month > 12
month = 1
year += 1
end
end
fixed_assets_amortizations.where(year: year).each do |record|
yearly_total += record.amount
end
eval common_amortization_code "create!"
end
end
private
def common_amortization_code(create_or_build)
<<-eos
while base > total
yearly_total += monthly_amount
amount = monthly_amount
if month == 12
if year == amortization_date.year
amount += first_year_amount - yearly_total
else
amount += yearly_amount - yearly_total
end
end
total += amount
amount += (base - total) if total > base
fixed_assets_amortizations.#{create_or_build} year: year,
month: month,
amount: amount
month += 1
if month > 12
month = 1
year += 1
yearly_total = 0
end
end
eos
end
def set_placed_in_service_date_defaults
self.placed_in_service_date ||= Date.today if new_record?
end
def set_acquisition_date_defaults
self.acquisition_date ||= Date.today if new_record?
end
def set_amortization_date_defaults
if new_record?
date = Date.today.end_of_month + 1
self.amortization_date ||= date
end
end
def set_amortization_method_defaults
self.amortization_method ||= "liniowa" if new_record?
self.acquisition_date ||= Date.today if new_record?
end
def set_accumulated_depreciation_defaults
self.accumulated_depreciation ||= 0.00 if new_record?
end
def set_starting_value_defaults
self.starting_value ||= 0.00 if new_record?
end
def set_amortization_rate_defaults
self.amortization_rate ||= 0 if new_record?
end
def ensure_placed_in_service_date_grater_or_equal_acquisition_date
return if !placed_in_service_date || !acquisition_date
if placed_in_service_date < acquisition_date
errors.add :placed_in_service_date, :earlier_than_aquisition
end
end
def ensure_amortization_date_grater_or_equal_placed_in_service_date
return if !placed_in_service_date || !amortization_date
if amortization_date < placed_in_service_date
errors.add :amortization_date, :earlier_than_placed_in_service
end
end
def ensure_starting_value_grater_or_equal_accumulated_depreciation
return if !starting_value || !accumulated_depreciation
if starting_value < accumulated_depreciation
errors.add :accumulated_depreciation, :bigger_than_starting_value
end
end
def build_amortization_plan
return unless amortization_rate_changed?
fixed_assets_amortizations.delete_all
base = (starting_value - accumulated_depreciation)
year = amortization_date.year
month = amortization_date.month
yearly_amount = (starting_value * amortization_rate / 100.0).round(2)
monthly_amount = (yearly_amount / 12.0).round(2)
# we can't use monthly amount here because calculations don't match algorithm
first_year_amount = ((yearly_amount / 12.0) * (12 - month + 1)).round(2)
total = 0
yearly_total = 0
eval common_amortization_code "build"
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment