whereHas('timeLines', function ($q) use ($user_id, $date) {
$q->where('user_id', $user_id)
->whereDate('starts_at', $date);
})
->with(['timeLines' => fn ($q) => $q->where('user_id', $user_id)])
->orderByDesc('id')
->get();
}
public function tasksForUserInRange(int $business_id, int $user_id, Carbon $start, Carbon $end): Collection
{
return MtUserTask::forBusiness($business_id)
->whereHas('timeLines', function ($q) use ($user_id, $start, $end) {
$q->where('user_id', $user_id)
->whereDate('starts_at', '>=', $start->toDateString())
->whereDate('starts_at', '<=', $end->toDateString());
})
->with(['timeLines' => fn ($q) => $q->where('user_id', $user_id)])
->orderByDesc('id')
->get();
}
public function calendarTasks(int $business_id, int $user_id, Carbon $start, Carbon $end): Collection
{
return MtUserTask::forBusiness($business_id)
->where('user_id', $user_id)
->where(function ($q) use ($start, $end) {
$q->whereBetween('created_at', [$start, $end])
->orWhereBetween('due_date', [$start->toDateString(), $end->toDateString()]);
})
->orderBy('title')
->get();
}
public function taskWorkMinutes(MtUserTask $task, int $user_id, ?string $date = null): int
{
$lines = $task->relationLoaded('timeLines')
? $task->timeLines->where('user_id', $user_id)
: $task->timeLines()->where('user_id', $user_id)->get();
if ($date) {
$lines = $lines->filter(fn ($line) => $line->starts_at && $line->starts_at->toDateString() === $date);
}
return (int) $lines->sum(fn ($line) => $line->durationMinutes() ?? 0);
}
public function sumTasksWorkMinutes(Collection $tasks, int $user_id, ?string $date = null): int
{
return (int) $tasks->sum(fn ($task) => $this->taskWorkMinutes($task, $user_id, $date));
}
public function userDayWorkMinutes(int $business_id, int $user_id, string $date): int
{
$lines = MtUserTimeLine::forBusiness($business_id)
->where('user_id', $user_id)
->whereDate('starts_at', $date)
->get();
return (int) $lines->sum(fn ($line) => $line->durationMinutes() ?? 0);
}
public function formatDuration(int $minutes): string
{
if ($minutes <= 0) {
return '۰:۰۰';
}
$formatted = sprintf('%d:%02d', intdiv($minutes, 60), $minutes % 60);
return function_exists('persian_number') ? persian_number($formatted) : $formatted;
}
public function formatDurationHtml(int $minutes): string
{
$label = $this->formatDuration($minutes);
if ($minutes <= 0) {
return ''.$label.'';
}
return ''.$label.'';
}
public function latestTimelineForTask(int $business_id, int $user_id, int $task_id, ?string $date = null): ?MtUserTimeLine
{
$query = MtUserTimeLine::forBusiness($business_id)
->where('user_id', $user_id)
->where('user_task_id', $task_id);
if ($date) {
$query->whereDate('starts_at', $date);
}
return $query->latest('starts_at')->first();
}
public function dayTabDates(): array
{
$future = collect();
for ($i = 0; $i < 7; $i++) {
$future->push(now()->addDays($i)->format('Y-m-d'));
}
$past = collect();
for ($i = 1; $i <= 6; $i++) {
$past->push(now()->subDays($i)->format('Y-m-d'));
}
return [
'future' => $future,
'past' => $past->reverse()->values(),
];
}
public function groupedTasksByTimelineDate(Collection $tasks, int $user_id): Collection
{
$grouped = collect();
foreach ($tasks as $task) {
$dates = $task->timeLines
->where('user_id', $user_id)
->pluck('starts_at')
->filter()
->map(fn ($dt) => $dt->toDateString())
->unique();
foreach ($dates as $date) {
if (! $grouped->has($date)) {
$grouped->put($date, collect());
}
if (! $grouped->get($date)->contains('id', $task->id)) {
$grouped->get($date)->push($task);
}
}
}
return $grouped->sortKeysDesc();
}
}