Firstly, you can use the ->whereBetween() query builder method to just collect the attendances in a given date range, like in your case.
Secondly, why don't you just set a time_notified column (or something like that) in your member table and save there the exact timestamp you're sending an email to a user, so that you will always know when the last email has been sent. Or am I misunderstanding?
Need help to think over a 3 model related query
This is a school Laravel app, using 3 models Member for school members, Attendance for registering school attendance and EmailLog to see emails sent to members.
The main objective is to send "miss you" emails to inactive members on 4 ranges: one week inactive members, two week, one month and two month.
Let's only review the first case, one week inactive members. To select those members I created a local scope on the Member model:
public function scopeOneWeekInactiveRange($query) {
$query->whereDoesntHave('attendance', function ($query) {
$query->where('scan_date', '>', now()->subDays(7));
})
->whereHas('attendance', function ($query) {
$query->where('scan_date', '>', now()->subDays(14));
});
}
This will select all members that have previous activity but doesn't have activity on the last week, I think we are on the way...
Once we have the selection, I will fire through php artisan member:send-inactive-oneweek a notification. Once the notification email is delivered or opened, it will create a new row on email_logs table with the member and the email type sent, in this particular case email_type_id is 16.
My command looks like this:
public function handle(){
$members_to_notify = \App\Member::OneWeekInactiveRange()->get();
Notification::send($members_to_notify, new InactiveOneWNoti());
}
If I run this command on a daily basis, my school members that are on that range will get the notification all days. That is not what we wanted.
So I've created another local scope on our Member model. The main purpose for this scope is to select only members that doesn't have an email_type_id equal to 16 on the last week.
If it does, this means that an email was already fired to this member.
public function scopeOneWeekInactiveRangeEmail($query) {
$query->whereDoesntHave('emailLog', function ($query) {
$query->where('created_at', '>', now()->subDays(7))
->where('email_type_id', 16);
});
}
So now, I have modified the artisan command php artisan member:send-inactive-oneweek to:
public function handle(){
$members_to_notify = \App\Member::OneWeekInactiveRange()
->OneWeekInactiveRangeEmail()
->get();
Notification::send($members_to_notify, new InactiveOneWNoti());
}
Here is the MAIN ISSUE:
My mind says to me that this query is good to go, but I need a way to test it, I have make many drawings with possibilities but I can't find a way to really test this, I don't want an email sent two times on the same week. I wanted to only send this email again if the member has the one week inactive condition again in the future.
Any ideas?
Please or to participate in this conversation.