Alaric
Alaric

Reputation: 229

How to recalculate values when the new year comes, Ruby

I'm trying to write an app that calculates sick/vacation days and how much an employee has available in either category.

Next step is adding a method that every year on January first recalculates all the employee's available vacation/sick time (without scrubbing/overwriting the data from the previous year, as that information needs to be accessed).

I have an Employee model (which is posted below), which :has_many Furloughs (which have their own model which I won't post unless requested, but basically handles how the date ranges are calculated).

class Employee < ActiveRecord::Base
  has_many :furloughs, :dependent => :destroy

  def years_employed
    (DateTime.now - hire_date).round / 365
  end

  def vacation_days
    if years_employed < 1 && newbie
      ((12 - hire_date.month) * 0.8).ceil
    elsif years_employed <= 6
      10 
    elsif years_employed <= 16
      years_employed + 4
    else 
      20
    end
  end

  def newbie
    Time.now.year == hire_date.year
  end

  def sick_days
    5.0
  end

  def vacation_days_used 
      self.furloughs.collect(&:vacation_duration).inject(0) { | memo, n | memo + n } 
  end

  def sick_days_used
    self.furloughs.collect(&:sick_duration).inject(0) { | memo, n | memo + n }
  end

  def remaining_vacation_days
    vacation_days - vacation_days_used
  end

  def remaining_sick_days
    sick_days - sick_days_used
  end

end

On January 1st, vacation/sick_days and vacation/sick_days_used methods need to reset, and then I also need to add a rollover method like

 def rollover
    if some_method_determining_last_year(remaining_vacation_days) >= 2
      2
    else
      remaining_vacation_days
    end
  end

that needs to add to the newly calculated total as well. I'd appreciate any thoughts on what how I should approach this.

Upvotes: 1

Views: 187

Answers (2)

Hana
Hana

Reputation: 163

A database solution would probably be the simplest way to go, but since you're already on a track of trying to store as little information as possible, I might have a solution for you. You already have a method for the number of vacation/sick days (probably really should be hours) an employee has. From there you can have a method that calculates the total vacation and sick days an employee has ever earned. Then it's just a simple calculation between the number of days they have used and the number of hours the have earned. You will probably have to add a filter to those methods for expired hours, but you get the idea. I also assume that vacation_days_used are days used for the entirety of their employment (can't tell since I can't see the furlough model):

def total_vacation_days_earned
  # vacation_days has to be recalculate, probably should be a mapped function.
  # for each year, how many vacation days did you earn, but this is a rough method
  vacation_days * years_employed # can put cutoffs like, first 2 years employed, etc.
end

def total_sick_days_earned
  sick_days * years_employed
end

def vacation_days_used 
  self.furloughs.collect(&:vacation_duration).inject(0) { | memo, n | memo + n } 
end

def sick_days_used
 self.furloughs.collect(&:sick_duration).inject(0) { | memo, n | memo + n }
end

def remaining_vacation_days
  total_vacation_days_earned - vacation_days_used
end

def remaining_sick_days
  total_sick_days_earned - sick_days_used
end

Now you shouldn't need a rollover method since at the beginning of the year each employee has a running total of time they have ever accrued minus a running total of time they have ever used.

Most employers will give you a fraction of the holidays you have accrued each payroll period, not upfront at the beginning of the year. You will probably eventually need to segment it out by payroll period as well as years_employed by payroll (i.e., Employee has been here 24 payroll cycles, or 2 years). You will need a more robust years_employed method, I've written up a gist that can be used as a starting point for a method that calculates years served as incremented calendar (not always 365 days) year from the hire_date. You could modify this to increment every two weeks, fifteen days, whatever the payroll cycle is. You could also add a service or additional model to handle payroll methods.

Upvotes: 2

Steve Wilhelm
Steve Wilhelm

Reputation: 6260

I would recommend extending the Employee model/schema to include two additional columns: remaining_vacation_days and sick_days.

Upon creation of Employee, set these values appropriately and decrement remaining_vacation_days and increment sick_days after a Furlough save (see after_save).

Finally, on Jan 1st use your vacation_days and sick_days methods to reset these values for the new year.

Upvotes: 2

Related Questions