Je pense que ce que vous voulez, c'est créer un champ d'application, qui peut recevoir un start_day
comme paramètre :
scope :payroll_week_starting, -> (start_day) {
where(clock_in: start_day..(start_day + 1.week))
}
Ainsi, à l'avenir, vous pourrez appeler votre champ d'application le premier jour de votre période de paie :
ModelName.payroll_week_starting(Date.parse('31/12/2015'))
UPDATE :
Selon votre commentaire, il semble que vous recherchiez un peu plus d'informations d'un point de vue architectural. Il est difficile de vous aider sans comprendre l'architecture de votre base de données, je vais donc partir d'un niveau élevé.
Supposons que vous ayez un Employee
et un modèle de Shift
avec le modèle clock_in
y clock_out
champs. Vous pouvez également vouloir un modèle appelé PayPeriod
avec les champs start_date
y end_date
.
Chaque Employee
has_many :shifts
et chaque PayPeriod
has_many :shifts
Vous pouvez ajouter quelques méthodes de classe sur PayPeriod
afin que vous puissiez trouver et/ou créer le PayPeriod
pour une date donnée.
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
Le create_for
La logique est assez compliquée, mais un exemple vous aidera à comprendre :
Disons que j'ai pointé aujourd'hui May 17th, 2016
, le yday
pour aujourd'hui est 138
Si vous utilisez division entière (par défaut pour ruby) pour diviser par 14 (la durée de vos périodes de paie), vous obtiendrez 9. En multipliant à nouveau ce chiffre par 14, vous obtiendrez 126, ce qui correspond à la période de paie la plus récente. yday
divisible par 14. Si vous ajoutez ce nombre de jours au début de cette année, vous obtiendrez le début de la PayPeriod
. La fin de la PayPeriod
est de 14 jours après le start_date
mais pas de report sur l'année suivante.
Ce que je ferais alors, c'est ajouter un before_save
à l'adresse Shift
pour trouver ou créer le PayPeriod
before_save :associate_pay_period
def associate_pay_period
self.pay_period_id = PayPeriod.find_or_create_for(clock_in)
end
Ensuite, chaque PayPeriod
aura un tas de Shift
et chaque Shift
appartiendra à un PayPeriod
.
Si, par exemple, vous souhaitez obtenir toutes les affectations d'un employé spécifique au cours d'une période de temps donnée, vous pouvez utiliser l'outil de gestion des affectations. PayPeriod
(pour éventuellement additionner les heures travaillées pour ce PayPeriod
) ajoute un champ d'application à Shift
:
scope :for, -> (user) { where(user: user) }
Et appeler pay_period.shifts.for(user)
MISE À JOUR N° 2 :
Une autre idée (beaucoup plus simple) m'est venue à l'esprit (si vous ne voulez pas créer une véritable PayPeriod
), il suffirait d'ajouter une méthode au modèle qui a la fonction clock_in
(Je vais l'appeler Shift
):
def pay_period
clock_in.to_date.mjd / 14
end
Ce qui revient à réduire tout temps clock_in à un entier représentant une période de 14 jours. Vous pouvez alors appeler
Shift.all.group_by { |shift| shift.pay_period }
Si vous avez besoin de chaque pay_period
à l'intérieur d'une même année civile, vous pouvez le faire :
def pay_period
[clock_in.year, clock_in.to_date.yday / 14]
end