| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240 |
- <?php
- namespace App\Rules;
- use App\Models\Provider;
- use App\Models\ProviderBlockedDay;
- use App\Models\ProviderWorkingDay;
- use App\Models\Schedule;
- use App\Models\ScheduleProposal;
- use Carbon\Carbon;
- use Illuminate\Support\Facades\Log;
- class ScheduleBusinessRules
- {
- // Status que devem ser ignorados na validação de limite por semana
- private const EXCLUDED_STATUSES = ['cancelled', 'rejected'];
- /**
- * Valida se o prestador pode ter mais um agendamento com o cliente na semana
- * Limite: 2 agendamentos por semana (domingo a sábado)
- * @param int $clientId
- * @param int $providerId
- * @param string $date (Y-m-d)
- * @param int|null $excludeScheduleId
- * @return bool
- * @throws \Exception
- */
- public static function validateWeeklyScheduleLimit($clientId, $providerId, $date, $excludeScheduleId = null)
- {
- $date = Carbon::parse($date);
-
- $weekStart = $date->copy()->startOfWeek(Carbon::SUNDAY);
- $weekEnd = $date->copy()->endOfWeek(Carbon::SATURDAY);
- $weeklySchedulesCount = Schedule::where('client_id', $clientId)
- ->where('provider_id', $providerId)
- ->whereNotIn('status', self::EXCLUDED_STATUSES)
- ->whereBetween('date', [$weekStart->format('Y-m-d'), $weekEnd->format('Y-m-d')])
- ->when($excludeScheduleId, function ($query) use ($excludeScheduleId) {
- $query->where('id', '!=', $excludeScheduleId);
- })
- ->count();
- if ($weeklySchedulesCount >= 2) {
- throw new \Exception(__('validation.custom.schedule.weekly_limit_exceeded'));
- }
- return true;
- }
-
- /**
- * Valida se o prestador tem horário de trabalho cadastrado para o dia da semana e período
- * @param int $provider_id
- * @param int $day_of_week (0 - domingo, 6 - sábado)
- * @param string $period ('morning' ou 'afternoon')
- * @return bool
- * @throws \Exception
- */
- public static function validateWorkingDay($provider_id, $day_of_week, $period)
- {
- $workingDay = ProviderWorkingDay::where('provider_id', $provider_id)
- ->where('day', $day_of_week)
- ->where('period', $period)
- ->first();
- if(!$workingDay) {
- throw new \Exception(__('validation.custom.schedule.provider_not_working'));
- }
- return true;
- }
- /**
- * Valida se o prestador tem bloqueio cadastrado para o dia e horário
- * @param int $provider_id
- * @param string $date_ymd (Y-m-d)
- * @param string $start_time (H:i:s)
- * @param string $end_time (H:i:s)
- * @return bool
- * @throws \Exception
- */
- public static function validateBlockedDay($provider_id, $date_ymd, $start_time, $end_time)
- {
- $blockedDay = ProviderBlockedDay::where('provider_id', $provider_id)
- ->where('date', $date_ymd)
- ->where(function ($query) use ($start_time, $end_time) {
- $query->where('period', 'full')
- ->orWhere(function ($q) use ($start_time, $end_time) {
- $q->where('period', 'partial')
- ->where(function ($q2) use ($start_time, $end_time) {
- $q2->whereBetween('init_hour', [$start_time, $end_time])
- ->orWhereBetween('end_hour', [$start_time, $end_time])
- ->orWhere(function ($q3) use ($start_time, $end_time) {
- $q3->where('init_hour', '<=', $start_time)
- ->where('end_hour', '>=', $end_time);
- });
- });
- });
- })
- ->first();
- if ($blockedDay) {
- throw new \Exception(__('validation.custom.schedule.provider_blocked'));
- }
- return true;
- }
- public static function validatePricePeriod($provider_id, $min_price, $max_price, $period_type)
- {
- if ($min_price < 0 || $max_price < 0) {
- throw new \Exception(__('validation.custom.schedule.invalid_price'));
- }
- if ($min_price > $max_price) {
- throw new \Exception(__('validation.custom.schedule.invalid_price_range'));
- }
- $provider = Provider::find($provider_id);
- $provider_price_period = 0;
- switch ($period_type):
- case '2': //2 horas
- $provider_price_period = $provider->daily_price_2h;
- break;
- case '4': //4 horas
- $provider_price_period = $provider->daily_price_4h;
- break;
- case '6': //6 horas
- $provider_price_period = $provider->daily_price_6h;
- break;
- case '8': //8 horas
- $provider_price_period = $provider->daily_price_8h;
- break;
- default:
- throw new \Exception(__('validation.custom.schedule.invalid_period_type'));
- endswitch;
- if ($provider_price_period < $min_price || $provider_price_period > $max_price) {
- throw new \Exception(__('validation.custom.schedule.price_not_in_range'));
- }
- return true;
- }
- /**
- * Valida se o prestador tem outro agendamento no mesmo dia e horário
- * @param int $provider_id
- * @param string $date_ymd (Y-m-d)
- * @param string $start_time (H:i:s)
- * @param string $end_time (H:i:s)
- * @param int|null $exclude_schedule_id (id do agendamento a ser excluído da validação, usado para edição de agendamento)
- * @return bool
- * @throws \Exception
- */
- public static function validateConflictingSchedule($provider_id, $date_ymd, $start_time, $end_time, $exclude_schedule_id = null)
- {
- $conflictingSchedule = Schedule::where('provider_id', $provider_id)
- ->where('date', $date_ymd)
- ->whereIn('status', ['pending', 'accepted', 'paid', 'started'])
- ->where(function ($query) use ($start_time, $end_time) {
- $query->whereBetween('start_time', [$start_time, $end_time])
- ->orWhereBetween('end_time', [$start_time, $end_time])
- ->orWhere(function ($q) use ($start_time, $end_time) {
- $q->where('start_time', '<=', $start_time)
- ->where('end_time', '>=', $end_time);
- });
- })
- ->when($exclude_schedule_id, function ($query) use ($exclude_schedule_id) {
- $query->where('id', '!=', $exclude_schedule_id);
- })
- ->first();
- if ($conflictingSchedule) {
- throw new \Exception(__('validation.custom.schedule.provider_conflicting_schedule'));
- }
- return true;
- }
- /**
- * Valida se o prestador tem outro agendamento com o mesmo cliente no mesmo dia e horário
- * @param int $provider_id
- * @param string $date_ymd (Y-m-d)
- * @param string $start_time (H:i:s)
- * @param string $end_time (H:i:s)
- * @param int|null $exclude_schedule_id (id do agendamento a ser excluído da validação, usado para edição de agendamento)
- * @return bool
- * @throws \Exception
- */
- public static function validateConflictingSameProposal($provider_id, $schedule_id)
- {
- $conflictingSameProposal = ScheduleProposal::where('schedule_proposals.provider_id', $provider_id)
- ->where('schedule_proposals.schedule_id', $schedule_id)
- ->leftJoin('schedules', 'schedule_proposals.schedule_id', '=', 'schedules.id')
- ->whereNotIn('schedules.status', self::EXCLUDED_STATUSES)
- ->first();
- if ($conflictingSameProposal) {
- throw new \Exception(__('validation.custom.schedule.provider_conflicting_same_proposal'));
- }
- return true;
- }
- /**
- * Valida se o prestador tem outro agendamento com o mesmo cliente no mesmo dia e horário, ignorando o horário
- * @param int $provider_id
- * @param string $date_ymd (Y-m-d)
- * @param string $start_time (H:i:s)
- * @param string $end_time (H:i:s)
- * @param int|null $exclude_schedule_id (id do agendamento a ser excluído da validação, usado para edição de agendamento)
- * @return bool
- * @throws \Exception
- */
- public static function validateConflictingProposalSameDate($provider_id, $date_ymd, $start_time, $end_time, $exclude_schedule_id = null)
- {
- $conflictingProposalSameDate = ScheduleProposal::where('schedule_proposals.provider_id', $provider_id)
- ->leftJoin('schedules', 'schedule_proposals.schedule_id', '=', 'schedules.id')
- ->where('schedules.date', $date_ymd)
- ->where(function ($query) use ($start_time, $end_time) {
- $query->whereBetween('schedules.start_time', [$start_time, $end_time])
- ->orWhereBetween('schedules.end_time', [$start_time, $end_time])
- ->orWhere(function ($q) use ($start_time, $end_time) {
- $q->where('schedules.start_time', '<=', $start_time)
- ->where('schedules.end_time', '>=', $end_time);
- });
- })
- ->whereNotIn('status', self::EXCLUDED_STATUSES)
- ->when($exclude_schedule_id, function ($query) use ($exclude_schedule_id) {
- $query->where('schedules.id', '!=', $exclude_schedule_id);
- })
- ->first();
- if ($conflictingProposalSameDate) {
- throw new \Exception(__('validation.custom.schedule.provider_conflicting_proposal_same_date'));
- }
- return true;
- }
- }
|