|
|
@@ -2,6 +2,8 @@
|
|
|
|
|
|
namespace App\Services;
|
|
|
|
|
|
+use App\Jobs\FinishScheduleJob;
|
|
|
+use App\Jobs\StartScheduleJob;
|
|
|
use App\Models\Schedule;
|
|
|
use App\Models\Provider;
|
|
|
use App\Models\ProviderBlockedDay;
|
|
|
@@ -27,41 +29,23 @@ class ScheduleService
|
|
|
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);
|
|
|
- $this->validateWeeklyScheduleLimit($data);
|
|
|
-
|
|
|
- return Schedule::create($data);
|
|
|
- }
|
|
|
-
|
|
|
- public function createMultiple(array $baseData, array $schedules)
|
|
|
+ public function createSingleOrMultiple(array $baseData, array $schedules)
|
|
|
{
|
|
|
+ $createdSchedules = [];
|
|
|
foreach ($schedules as $schedule) {
|
|
|
- $validationData = array_merge($baseData, $schedule);
|
|
|
try {
|
|
|
- $this->validateProviderAvailability($validationData);
|
|
|
- $this->validateWeeklyScheduleLimit($validationData);
|
|
|
+ $datasMerged = array_merge($baseData, $schedule);
|
|
|
+ $this->validateProviderAvailability($datasMerged, null);
|
|
|
+ $scheduleData = array_merge($datasMerged, [
|
|
|
+ 'code' => str_pad(random_int(0, 9999), 4, '0', STR_PAD_LEFT),
|
|
|
+ ]);
|
|
|
+ $createdSchedules[] = Schedule::create($scheduleData);
|
|
|
+
|
|
|
} catch (\Exception $e) {
|
|
|
- throw new \Exception("Prestador não disponível para a data " . Carbon::parse($schedule['date'])->format('d/m/Y') . ": " . $e->getMessage());
|
|
|
+ throw new \Exception(__("validation.provider_unavailable"));
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- $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;
|
|
|
}
|
|
|
|
|
|
@@ -106,81 +90,48 @@ class ScheduleService
|
|
|
|
|
|
private function validateProviderAvailability(array $data, $excludeScheduleId = null)
|
|
|
{
|
|
|
- $provider = Provider::findOrFail($data['provider_id']);
|
|
|
+ $provider_id = $data['provider_id'];
|
|
|
+ $client_id = $data['client_id'];
|
|
|
+
|
|
|
$date = Carbon::parse($data['date']);
|
|
|
+ $dayOfWeek = $date->dayOfWeek;
|
|
|
$startTime = $data['start_time'];
|
|
|
$endTime = $data['end_time'];
|
|
|
+ $period = $startTime < '13:00:00' ? 'morning' : 'afternoon';
|
|
|
+
|
|
|
+ // bloqueio 2 schedules por semana para o mesmo client e provider
|
|
|
+ ScheduleBusinessRules::validateWeeklyScheduleLimit(
|
|
|
+ $client_id,
|
|
|
+ $provider_id,
|
|
|
+ $data['date'],
|
|
|
+ $excludeScheduleId
|
|
|
+ );
|
|
|
|
|
|
- $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;
|
|
|
- }
|
|
|
-
|
|
|
- private function validateWeeklyScheduleLimit(array $data)
|
|
|
- {
|
|
|
- if (isset($data['schedule_type']) && $data['schedule_type'] !== 'default') {
|
|
|
- return true;
|
|
|
- }
|
|
|
-
|
|
|
- return ScheduleBusinessRules::validateWeeklyScheduleLimit(
|
|
|
- $data['client_id'],
|
|
|
- $data['provider_id'],
|
|
|
- $data['date']
|
|
|
+ // bloqueio provider trabalha no dia/periodo
|
|
|
+ ScheduleBusinessRules::validateWorkingDay(
|
|
|
+ $provider_id,
|
|
|
+ $dayOfWeek,
|
|
|
+ $period
|
|
|
+ );
|
|
|
+
|
|
|
+ // bloqueio provider tem blockedday para dia/hora
|
|
|
+ ScheduleBusinessRules::validateBlockedDay(
|
|
|
+ $provider_id,
|
|
|
+ $date->format('Y-m-d'),
|
|
|
+ $startTime,
|
|
|
+ $endTime
|
|
|
);
|
|
|
+
|
|
|
+ // bloqueio provider tem outro agendamento para dia/hora
|
|
|
+ ScheduleBusinessRules::validateConflictingSchedule(
|
|
|
+ $provider_id,
|
|
|
+ $date->format('Y-m-d'),
|
|
|
+ $startTime,
|
|
|
+ $endTime,
|
|
|
+ $excludeScheduleId
|
|
|
+ );
|
|
|
+
|
|
|
+ return true;
|
|
|
}
|
|
|
|
|
|
public function getSchedulesDefaultGroupedByClient()
|
|
|
@@ -231,29 +182,62 @@ class ScheduleService
|
|
|
|
|
|
public function updateStatus($id, string $status)
|
|
|
{
|
|
|
- $schedule = Schedule::findOrFail($id);
|
|
|
-
|
|
|
- $allowedTransitions = [
|
|
|
- 'pending' => ['accepted', 'rejected'],
|
|
|
- 'accepted' => ['paid', 'cancelled'],
|
|
|
- 'paid' => ['cancelled', 'started'],
|
|
|
- 'started' => ['finished'],
|
|
|
- 'rejected' => [],
|
|
|
- 'cancelled' => [],
|
|
|
- 'finished' => [],
|
|
|
- ];
|
|
|
-
|
|
|
- $currentStatus = $schedule->status;
|
|
|
-
|
|
|
- if (!isset($allowedTransitions[$currentStatus])) {
|
|
|
- throw new \Exception("Status atual inválido.");
|
|
|
- }
|
|
|
-
|
|
|
- if (!in_array($status, $allowedTransitions[$currentStatus])) {
|
|
|
- throw new \Exception("Transição de status não permitida: {$currentStatus} → {$status}");
|
|
|
+ try {
|
|
|
+ DB::beginTransaction();
|
|
|
+ $schedule = Schedule::findOrFail($id);
|
|
|
+
|
|
|
+ $allowedTransitions = [
|
|
|
+ 'pending' => ['accepted', 'rejected'],
|
|
|
+ 'accepted' => ['paid', 'cancelled'],
|
|
|
+ 'paid' => ['cancelled', 'started'],
|
|
|
+ 'started' => ['finished'],
|
|
|
+ 'rejected' => [],
|
|
|
+ 'cancelled' => [],
|
|
|
+ 'finished' => [],
|
|
|
+ ];
|
|
|
+
|
|
|
+ $currentStatus = $schedule->status;
|
|
|
+
|
|
|
+ if (!isset($allowedTransitions[$currentStatus])) {
|
|
|
+ throw new \Exception("Status atual inválido.");
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!in_array($status, $allowedTransitions[$currentStatus])) {
|
|
|
+ throw new \Exception("Transição de status não permitida: {$currentStatus} → {$status}");
|
|
|
+ }
|
|
|
+
|
|
|
+ $schedule->update(['status' => $status]);
|
|
|
+
|
|
|
+ switch ($status) {
|
|
|
+ case 'pending':
|
|
|
+ break;
|
|
|
+ case 'accepted':
|
|
|
+ break;
|
|
|
+ case 'rejected':
|
|
|
+ break;
|
|
|
+ case 'paid':
|
|
|
+ $date_cleaned = Carbon::parse($schedule->date)->format('Y-m-d');
|
|
|
+ $date_time_dispatch = Carbon::parse($date_cleaned . ' ' . $schedule->start_time);
|
|
|
+
|
|
|
+ StartScheduleJob::dispatch($schedule->id)->delay($date_time_dispatch);
|
|
|
+
|
|
|
+ // dispatch de teste em local
|
|
|
+ // StartScheduleJob::dispatch($schedule->id)->delay(now()->addSeconds(15));
|
|
|
+ break;
|
|
|
+ case 'cancelled':
|
|
|
+ break;
|
|
|
+ case 'started':
|
|
|
+ break;
|
|
|
+ case 'finished':
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ DB::commit();
|
|
|
+ return $schedule->fresh(['client.user', 'provider.user', 'address']);
|
|
|
+ } catch (\Exception $e) {
|
|
|
+ DB::rollBack();
|
|
|
+ Log::error("Erro ao atualizar status do agendamento: " . $e->getMessage());
|
|
|
+ throw new \Exception("Não foi possível atualizar o status do agendamento.");
|
|
|
}
|
|
|
-
|
|
|
- $schedule->update(['status' => $status]);
|
|
|
- return $schedule->fresh(['client.user', 'provider.user', 'address']);
|
|
|
}
|
|
|
}
|