我已经构建了一个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等等,我真的不确定如何处理这个问题以及可能有什么用处。到目前为止,我所撰写的内容在当前的支付期内有效,但随着时间的推移,范围也随之浮动。
非常感谢任何帮助。
答案 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'))
根据您的评论,您似乎从架构角度寻找更多信息。在不了解您的数据库架构的情况下帮助您很难,所以我只是从高层开始。
假设您拥有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(默认为红宝石)除以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)
另一个(更简单)我认为(如果您不想创建实际的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