我已经构建了一个 Rails 应用程序,它记录员工时间(上类/下类)并计算总小时数,允许导出到 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,等等。我真的不确定如何解决这个问题以及什么可能有效。到目前为止,我所写的内容在当前的支付期内有效,但随着时间的推移,范围会发生变化。
任何帮助将不胜感激。
最佳答案
我想你想要的是创建一个范围,它可以接收一个 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'))
更新:
根据您的评论,您似乎正在从架构的角度寻找更多信息。在不了解您的数据库架构的情况下很难为您提供帮助,因此我将从高层次开始。
假设您有一个
Employee
模型和一个带有 Shift
和 clock_in
字段的 clock_out
模型。您可能还需要一个名为 PayPeriod
的模型,其中包含 start_date
和 end_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
,今天的 yday
是 138
,如果你使用 integer division(ruby 的默认值)除以 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
添加一个范围: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
这基本上只是将任何时钟时间归结为一个代表 14 天周期的整数。然后你可以打电话
Shift.all.group_by { |shift| shift.pay_period }
如果您需要将每个
pay_period
包含在一个日历年内,您可以执行以下操作:def pay_period
[clock_in.year, clock_in.to_date.yday / 14]
end
关于ruby-on-rails - Rails 确定工资核算期,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/37264645/