orderBy('date', 'desc') ->orderBy('start_time', 'desc') ->get(); } public function getById($id) { return Schedule::with(['client.user', 'provider.user', 'address'])->findOrFail($id); } public function create(array $data) { $data['code'] = str_pad(random_int(0, 9999), 4, '0', STR_PAD_LEFT); $provider = Provider::findOrFail($data['provider_id']); $data['total_amount'] = $this->calculateAmount($provider, $data['period_type']); $this->validateProviderAvailability($data); return Schedule::create($data); } public function createMultiple(array $baseData, array $schedules) { foreach ($schedules as $schedule) { $validationData = array_merge($baseData, $schedule); try { $this->validateProviderAvailability($validationData); } catch (\Exception $e) { throw new \Exception("Prestador não disponível para a data " . Carbon::parse($schedule['date'])->format('d/m/Y') . ": " . $e->getMessage()); } } $createdSchedules = []; foreach ($schedules as $schedule) { $scheduleData = array_merge($baseData, $schedule, [ 'code' => str_pad(random_int(0, 9999), 4, '0', STR_PAD_LEFT), ]); $createdSchedules[] = Schedule::create($scheduleData); } return $createdSchedules; } public function update($id, array $data) { $schedule = Schedule::findOrFail($id); if (isset($data['provider_id']) || isset($data['period_type'])) { $providerId = $data['provider_id'] ?? $schedule->provider_id; $periodType = $data['period_type'] ?? $schedule->period_type; $provider = Provider::findOrFail($providerId); $data['total_amount'] = $this->calculateAmount($provider, $periodType); } if (isset($data['date']) || isset($data['start_time']) || isset($data['provider_id'])) { $validationData = array_merge($schedule->toArray(), $data); $this->validateProviderAvailability($validationData, $id); } $schedule->update($data); return $schedule->fresh(['client.user', 'provider.user', 'address']); } public function delete($id) { $schedule = Schedule::findOrFail($id); $schedule->delete(); return $schedule; } private function calculateAmount(Provider $provider, string $periodType): float { $hourlyRates = [ '2' => $provider->daily_price_2h ?? 0, '4' => $provider->daily_price_4h ?? 0, '6' => $provider->daily_price_6h ?? 0, '8' => $provider->daily_price_8h ?? 0, ]; return $hourlyRates[$periodType] ?? 0; } private function validateProviderAvailability(array $data, $excludeScheduleId = null) { $provider = Provider::findOrFail($data['provider_id']); $date = Carbon::parse($data['date']); $startTime = $data['start_time']; $endTime = $data['end_time']; $dayOfWeek = $date->dayOfWeek; $startHour = (int) substr($startTime, 0, 2); $period = $startHour < 12 ? 'morning' : 'afternoon'; $workingDay = ProviderWorkingDay::where('provider_id', $data['provider_id']) ->where('day', $dayOfWeek) ->where('period', $period) ->first(); if (!$workingDay) { throw new \Exception("Prestador não trabalha neste dia/período."); } $blockedDay = ProviderBlockedDay::where('provider_id', $data['provider_id']) ->where('date', $date->format('Y-m-d')) ->where(function ($query) use ($startTime, $endTime) { $query->where('period', 'full') ->orWhere(function ($q) use ($startTime, $endTime) { $q->where('period', 'partial') ->where(function ($q2) use ($startTime, $endTime) { $q2->whereBetween('init_hour', [$startTime, $endTime]) ->orWhereBetween('end_hour', [$startTime, $endTime]) ->orWhere(function ($q3) use ($startTime, $endTime) { $q3->where('init_hour', '<=', $startTime) ->where('end_hour', '>=', $endTime); }); }); }); }) ->first(); if ($blockedDay) { throw new \Exception("Prestador possui bloqueio neste dia/horário."); } $conflictingSchedule = Schedule::where('provider_id', $data['provider_id']) ->where('date', $date->format('Y-m-d')) ->whereIn('status', ['pending', 'accepted', 'paid', 'started']) ->where(function ($query) use ($startTime, $endTime) { $query->whereBetween('start_time', [$startTime, $endTime]) ->orWhereBetween('end_time', [$startTime, $endTime]) ->orWhere(function ($q) use ($startTime, $endTime) { $q->where('start_time', '<=', $startTime) ->where('end_time', '>=', $endTime); }); }) ->when($excludeScheduleId, function ($query) use ($excludeScheduleId) { $query->where('id', '!=', $excludeScheduleId); }) ->first(); if ($conflictingSchedule) { throw new \Exception("Prestador já possui agendamento neste horário."); } return true; } }