Rails确定工资核算期限

时间:2016-05-16 23:12:48

标签: ruby-on-rails ruby ruby-on-rails-3 activerecord scope

我已经构建了一个Rails应用程序,记录员工时间(clockin / clockout)并计算总小时数,允许导出为CSV / PDF,根据日期搜索时间卡等。

我真正想做的是通过某种方法实现工资核算期。

工资核算期从星期日开始,到14天后的星期六结束。写这样一个范围的最佳方法是什么?也可以将工资周期的周数分成两个?

我写了这些范围,但它们有缺陷:

scope :payroll_week_1, -> {
  start = Time.zone.now.beginning_of_week - 1.day
  ending = Time.zone.now.end_of_week - 1.day
  where(clock_in: start..ending)
}
scope :payroll_week_2, -> {
  start = Time.zone.now.end_of_week.beginning_of_day
  ending = Time.zone.now.end_of_week.end_of_day + 6.days
  where(clock_in: start..ending)
}

如果您目前处于工资核算期,这些工作正常,但是一旦您通过本周结束,范围将不再有效,因为我的时间基于Time.zone.now

有没有办法真正做到这一点?即使我必须设置某种静态范围或值,即4月10日 - 23日是工资单期间1等等,我真的不确定如何处理这个问题以及可能有什么用处。到目前为止,我所撰写的内容在当前的支付期内有效,但随着时间的推移,范围也随之浮动。

非常感谢任何帮助。

1 个答案:

答案 0 :(得分:2)

我认为你想要的是创建一个范围,它可以接收start_day作为参数:

scope :payroll_week_starting, -> (start_day) {
  where(clock_in: start_day..(start_day + 1.week))
}

然后,将来您可以在支付期的第一天致电您的范围:

ModelName.payroll_week_starting(Date.parse('31/12/2015'))

UPDATE:

根据您的评论,您似乎从架构角度寻找更多信息。在不了解您的数据库架构的情况下帮助您很难,所以我只是从高层开始。

假设您拥有Employee模型和Shift模型,其中包含clock_inclock_out字段。您可能还需要一个名为PayPeriod的模型,其中包含字段start_dateend_date

每个Employee has_many :shifts和每个PayPeriod has_many :shifts

您可以在PayPeriod上添加几个类方法,这样您就可以在任何给定的日期时间内找到和/或创建PayPeriod

def self.for(time)
  find_by("start_date < ? AND end_date > ?", time, time)
end

def self.create_for(time)
  # yday is the number of days into the current year
  period_start_yday = 14 * (time.yday / 14)
  start_date = Date.new(time.year) + period_start_yday.days
  next_year = Date.new(time.year) + 1.year
  create(
    start_date: start_date,
    end_date: [start_date + 14.days, last_day_of_year].min,
  )
end

def self.find_or_create_for(time)
  for(time) || create_for(time)
end

create_for逻辑非常复杂,但一个例子可以帮助您理解:

我今天说May 17th, 2016,今天的yday138,如果您使用integer division(默认为红宝石)除以14(长度为你的工资期间,你得到9.再次乘以14,你得到126,这是最新的yday可以被14整除。如果你把这个天数加到今年年初,你将开始PayPeriod的开始。 PayPeriod的结尾是start_date之后的14天,但没有延续到下一年。

我将做的是向before_save添加Shift回调以查找或创建相应的PayPeriod

before_save :associate_pay_period

def associate_pay_period
  self.pay_period_id = PayPeriod.find_or_create_for(clock_in)
end

然后每个PayPeriod都有一堆Shift个,而Shift每个PayPeriod都属于PayPeriod

例如,如果您希望在特定PayPeriod期间获得特定员工的所有班次(可能将工作时间加总为Shift),请将范围添加到{{1 }}:

scope :for, -> (user) { where(user: user) }

并致电pay_period.shifts.for(user)

更新#2:

另一个(更简单)我认为(如果您不想创建实际的PayPeriod模型),只需向具有clock_in的模型添加方法(我将其称为Shift):

def pay_period
  clock_in.to_date.mjd / 14
end

这基本上只是将任何clock_in时间归结为表示14天周期的整数。然后你可以打电话

Shift.all.group_by { |shift| shift.pay_period }

如果您需要在一个日历年内包含每个pay_period,您可以执行以下操作:

def pay_period
  [clock_in.year, clock_in.to_date.yday / 14]
end