#6 merge gus

Merged
zntt merged 5 commits from Softpar/feature/diariaapp-gus-agendamentos-apps into Softpar/development 1 day ago

+ 11 - 0
app/Http/Controllers/DashboardController.php

@@ -26,6 +26,17 @@ class DashboardController extends Controller
     }
   }
 
+  public function scheduleClienteDetails(int $id): JsonResponse
+  {
+    try {
+      $dados = $this->service->getScheduleClienteDetails($id);
+      return $this->successResponse(payload: $dados);
+    } catch (\Exception $e) {
+      Log::error("Erro ao obter detalhes do schedule do cliente: " . $e->getMessage());
+      return $this->errorResponse(message: __("messages.error_fetching_data"), code: 500);
+    }
+  }
+
   public function dadosDashboardPrestador(): JsonResponse
   {
     try {

+ 3 - 2
app/Http/Requests/ReviewRequest.php

@@ -24,8 +24,9 @@ class ReviewRequest extends FormRequest
             'comment'     => ['nullable', 'string'],
             'improvements_ids' => ['nullable', 'array'],
             'improvements_ids.*' => ['integer', 'exists:improvement_types,id'],
-            'block_provider' => ['sometimes', 'boolean'],
-            'block_client'   => ['sometimes', 'boolean'],
+            'block_provider'    => ['sometimes', 'boolean'],
+            'block_client'      => ['sometimes', 'boolean'],
+            'favorite_provider' => ['sometimes', 'boolean'],
         ];
 
         if ($this->isMethod('POST')) {

+ 10 - 8
app/Http/Resources/ClientProviderBlockResource.php

@@ -10,14 +10,16 @@ class ClientProviderBlockResource extends JsonResource
     public function toArray(Request $request): array
     {
         return [
-            'id' => $this->id,
-            'client_id' => $this->client_id,
-            'provider_id' => $this->provider_id,
-            'provider_name' => $this->provider->user->name ?? null,
-            'provider_email' => $this->provider->user->email ?? null,
-            'provider_phone' => $this->provider->user->phone ?? null,
-            'created_at' => $this->created_at?->format('Y-m-d H:i'),
-            'updated_at' => $this->updated_at?->format('Y-m-d H:i'),
+            'id'               => $this->id,
+            'client_id'        => $this->client_id,
+            'provider_id'      => $this->provider_id,
+            'provider_name'    => $this->provider_name ?? $this->provider?->user?->name,
+            'provider_email'   => $this->provider_email ?? $this->provider?->user?->email,
+            'provider_phone'   => $this->provider_phone ?? $this->provider?->user?->phone,
+            'provider_district'=> $this->provider_district ?? null,
+            'provider_rating'  => $this->provider_rating ?? null,
+            'created_at'       => $this->created_at?->format('Y-m-d H:i'),
+            'updated_at'       => $this->updated_at?->format('Y-m-d H:i'),
         ];
     }
 }

+ 1 - 0
app/Http/Resources/DashboardClienteResource.php

@@ -22,6 +22,7 @@ class DashboardClienteResource extends JsonResource
       'lastDoneSchedules' => $this['lastDoneSchedules'],
       'favoriteProviders' => $this['favoriteProviders'],
       'providersClose' => $this['providersClose'],
+      'todaySchedules' => $this['todaySchedules'],
     ];
   }
 }

+ 1 - 0
app/Http/Resources/ProviderClientBlockResource.php

@@ -16,6 +16,7 @@ class ProviderClientBlockResource extends JsonResource
             'client_name' => $this->client->user->name ?? null,
             'client_email' => $this->client->user->email ?? null,
             'client_phone' => $this->client->user->phone ?? null,
+            'client_rating' => $this->client->average_rating ?? null,
             'created_at' => $this->created_at?->format('Y-m-d H:i'),
             'updated_at' => $this->updated_at?->format('Y-m-d H:i'),
         ];

+ 21 - 3
app/Services/ClientProviderBlockService.php

@@ -9,9 +9,27 @@ class ClientProviderBlockService
 {
     public function getByClientId(int $clientId)
     {
-        return ClientProviderBlock::with(['provider.user'])
-            ->where('client_id', $clientId)
-            ->orderBy('created_at', 'desc')
+        return ClientProviderBlock::where('client_provider_blocks.client_id', $clientId)
+            ->leftJoin('providers', 'providers.id', '=', 'client_provider_blocks.provider_id')
+            ->leftJoin('users as provider_user', 'provider_user.id', '=', 'providers.user_id')
+            ->leftJoin('addresses as provider_address', function ($join) {
+                $join->on('provider_address.source_id', '=', 'providers.id')
+                    ->where('provider_address.source', 'provider')
+                    ->whereNull('provider_address.deleted_at');
+            })
+            ->select(
+                'client_provider_blocks.id',
+                'client_provider_blocks.client_id',
+                'client_provider_blocks.provider_id',
+                'client_provider_blocks.created_at',
+                'client_provider_blocks.updated_at',
+                'provider_user.name as provider_name',
+                'provider_user.email as provider_email',
+                'provider_user.phone as provider_phone',
+                'providers.average_rating as provider_rating',
+                'provider_address.district as provider_district',
+            )
+            ->orderBy('client_provider_blocks.created_at', 'desc')
             ->get();
     }
 

+ 91 - 3
app/Services/DashboardService.php

@@ -6,8 +6,10 @@ use App\Models\Address;
 use App\Models\Client;
 use App\Models\ClientFavoriteProvider;
 use App\Models\Provider;
+use App\Models\ProviderSpeciality;
 use App\Models\Review;
 use App\Models\Schedule;
+use App\Models\Speciality;
 use App\Rules\ScheduleBusinessRules;
 use Illuminate\Support\Facades\Auth;
 use Illuminate\Support\Facades\DB;
@@ -43,7 +45,7 @@ class DashboardService
         ->count(),
     ];
 
-    $nextSchedules = Schedule::with('address:district,address,number,source_id,source,id,address_type')
+    $nextSchedules = Schedule::with('address:district,address,complement,number,source_id,source,id,address_type')
       ->where('schedules.client_id', $cliente->id)
       ->whereIn('schedules.status', ['accepted', 'paid'])
       ->leftJoin('providers', 'providers.id', '=', 'schedules.provider_id')
@@ -180,6 +182,39 @@ class DashboardService
       ->orderBy('schedules.date', 'asc')
       ->get();
 
+    $todaySchedules = Schedule::with('address:district,address,number,source_id,source,id,address_type')
+      ->where('schedules.client_id', $cliente->id)
+      ->whereIn('schedules.status', ['accepted', 'paid', 'started', 'finished'])
+      ->whereDate('schedules.date', now()->toDateString())
+      ->leftJoin('providers', 'providers.id', '=', 'schedules.provider_id')
+      ->leftJoin('users as provider_user', 'provider_user.id', '=', 'providers.user_id')
+      ->leftJoin('media', 'media.id', '=', 'providers.profile_media_id')
+      ->select(
+        'schedules.id',
+        'schedules.provider_id',
+        'provider_user.name as provider_name',
+        'schedules.date',
+        'schedules.start_time',
+        'schedules.end_time',
+        'schedules.total_amount',
+        'schedules.period_type',
+        'schedules.schedule_type',
+        'schedules.address_id',
+        'schedules.status',
+        'schedules.code_verified',
+        'schedules.code',
+        'media.url as provider_photo',
+        DB::raw("EXISTS(
+          SELECT 1 FROM reviews
+          WHERE reviews.schedule_id = schedules.id
+            AND reviews.origin = 'client'
+            AND reviews.origin_id = {$cliente->id}
+            AND reviews.deleted_at IS NULL
+        ) as client_reviewed"),
+      )
+      ->orderBy('schedules.start_time', 'asc')
+      ->get();
+
     return [
       'headerBar'        => $headerBar,
       'summaryInfos'     => $summaryInfos,
@@ -188,6 +223,51 @@ class DashboardService
       'lastDoneSchedules' => $lastDoneSchedules,
       'favoriteProviders' => $favoriteProviders,
       'providersClose'   => $providersClose,
+      'todaySchedules'   => $todaySchedules,
+    ];
+  }
+
+  public function getScheduleClienteDetails(int $scheduleId): array
+  {
+    $user = Auth::user();
+    $cliente = Client::where('user_id', $user->id)->firstOrFail();
+
+    $schedule = Schedule::where('schedules.id', $scheduleId)
+      ->where('schedules.client_id', $cliente->id)
+      ->leftJoin('providers', 'providers.id', '=', 'schedules.provider_id')
+      ->leftJoin('users as provider_user', 'provider_user.id', '=', 'providers.user_id')
+      ->leftJoin('custom_schedules', 'custom_schedules.schedule_id', '=', 'schedules.id')
+      ->leftJoin('media', 'media.id', '=', 'providers.profile_media_id')
+      ->select(
+        'schedules.provider_id',
+        'provider_user.name as provider_name',
+        'providers.birth_date as provider_birth_date',
+        'media.url as provider_photo',
+        'custom_schedules.offers_meal',
+      )
+      ->firstOrFail();
+
+    $allSpecialities = Speciality::where('active', true)
+      ->select('id', 'description')
+      ->orderBy('description')
+      ->get();
+
+    $providerSpecialityIds = ProviderSpeciality::where('provider_id', $schedule->provider_id)
+      ->pluck('speciality_id')
+      ->all();
+
+    $specialities = $allSpecialities->map(fn($sp) => [
+      'id'             => $sp->id,
+      'description'    => $sp->description,
+      'has_speciality' => in_array($sp->id, $providerSpecialityIds),
+    ])->values();
+
+    return [
+      'provider_name'       => $schedule->provider_name,
+      'provider_birth_date' => $schedule->provider_birth_date,
+      'provider_photo'      => $schedule->provider_photo,
+      'offers_meal'         => $schedule->offers_meal,
+      'specialities'        => $specialities,
     ];
   }
 
@@ -251,13 +331,14 @@ class DashboardService
 
     $todayServices = Schedule::with('address:district,address,number,source_id,source,id')
       ->where('schedules.provider_id', $provider->id)
-      ->whereIn('schedules.status', ['accepted', 'paid', 'started'])
+      ->whereIn('schedules.status', ['accepted', 'paid', 'started', 'finished'])
       ->whereDate('schedules.date', now()->toDateString())
       ->leftJoin('clients', 'clients.id', '=', 'schedules.client_id')
       ->leftJoin('users as client_user', 'client_user.id', '=', 'clients.user_id')
       ->leftJoin('custom_schedules', 'custom_schedules.schedule_id', '=', 'schedules.id')
       ->select(
         'schedules.id',
+        'schedules.client_id',
         'client_user.name as client_name',
         'schedules.date',
         'schedules.start_time',
@@ -268,8 +349,15 @@ class DashboardService
         'schedules.schedule_type',
         'schedules.status',
         'schedules.code_verified',
-        'schedules.status',
+        'schedules.code',
         'custom_schedules.offers_meal',
+        DB::raw("EXISTS(
+          SELECT 1 FROM reviews
+          WHERE reviews.schedule_id = schedules.id
+            AND reviews.origin = 'provider'
+            AND reviews.origin_id = {$provider->id}
+            AND reviews.deleted_at IS NULL
+        ) as provider_reviewed"),
       )
       ->orderBy('schedules.start_time', 'asc')
       ->get();

+ 1 - 1
app/Services/ImprovementTypeService.php

@@ -16,7 +16,7 @@ class ImprovementTypeService
                     $query->whereIn('improvement_type', ['client', 'provider', 'both']);
                 })
                     ->when($origin !== 'both', function ($query) use ($origin) {
-                        $query->where('improvement_type', $origin);
+                        $query->whereIn('improvement_type', [$origin, 'both']);
                     });
             })
             ->get();

+ 43 - 14
app/Services/ReviewService.php

@@ -3,6 +3,7 @@
 namespace App\Services;
 
 use App\Models\Client;
+use App\Models\ClientFavoriteProvider;
 use App\Models\ClientProviderBlock;
 use App\Models\Provider;
 use App\Models\ProviderClientBlock;
@@ -52,12 +53,12 @@ class ReviewService
           case 'client':
             $schedule = Schedule::find($data['schedule_id']);
             $provider = Provider::find($schedule->provider_id);
-            $provider->updateAverageRating();
+            $provider->updateAverageRating((float) $data['stars']);
             break;
           case 'provider':
             $schedule = Schedule::find($data['schedule_id']);
             $client = Client::find($schedule->client_id);
-            $client->updateAverageRating();
+            $client->updateAverageRating((float) $data['stars']);
             break;
         }
       }
@@ -66,23 +67,51 @@ class ReviewService
         $review->improvements()->sync($data['improvements_ids']);
       }
   
-      if($data['block_provider'] == true) {
+      if (!empty($data['block_provider'])) {
         $schedule = Schedule::find($data['schedule_id']);
+        $alreadyBlocked = ClientProviderBlock::where('client_id', $schedule->client_id)
+          ->where('provider_id', $schedule->provider_id)
+          ->whereNull('deleted_at')
+          ->exists();
 
-        $client_provider_block = new ClientProviderBlock();
-        $client_provider_block->client_id = $schedule->client_id;
-        $client_provider_block->provider_id = $schedule->provider_id;
-        $client_provider_block->save();
+        if (!$alreadyBlocked) {
+          ClientProviderBlock::create([
+            'client_id'   => $schedule->client_id,
+            'provider_id' => $schedule->provider_id,
+          ]);
+        }
       }
-  
-      if($data['block_client'] == true) {
+
+      if (!empty($data['block_client'])) {
         $schedule = Schedule::find($data['schedule_id']);
-        $provider_client_block = new ProviderClientBlock();
-        $provider_client_block->provider_id = $schedule->provider_id;
-        $provider_client_block->client_id = $schedule->client_id;
-        $provider_client_block->save();
+        $alreadyBlocked = ProviderClientBlock::where('provider_id', $schedule->provider_id)
+          ->where('client_id', $schedule->client_id)
+          ->whereNull('deleted_at')
+          ->exists();
+
+        if (!$alreadyBlocked) {
+          ProviderClientBlock::create([
+            'provider_id' => $schedule->provider_id,
+            'client_id'   => $schedule->client_id,
+          ]);
+        }
       }
-  
+
+      if (!empty($data['favorite_provider'])) {
+        $schedule = Schedule::find($data['schedule_id']);
+        $alreadyFavorited = ClientFavoriteProvider::where('client_id', $schedule->client_id)
+          ->where('provider_id', $schedule->provider_id)
+          ->whereNull('deleted_at')
+          ->exists();
+
+        if (!$alreadyFavorited) {
+          ClientFavoriteProvider::create([
+            'client_id'   => $schedule->client_id,
+            'provider_id' => $schedule->provider_id,
+          ]);
+        }
+      }
+
       DB::commit();
       return $review;
     } catch (Exception $e) {

+ 1 - 1
app/Services/ScheduleService.php

@@ -301,7 +301,7 @@ class ScheduleService
       DB::beginTransaction();
       $schedule = Schedule::findOrFail($id);
 
-      $allowedStatuses = ['accepted', 'paid'];
+      $allowedStatuses = ['accepted', 'paid', 'pending'];
       if (!in_array($schedule->status, $allowedStatuses)) {
         throw new \Exception("Cancelamento não permitido para o status atual: {$schedule->status}");
       }

+ 1 - 0
database/seeders/DatabaseSeeder.php

@@ -16,6 +16,7 @@ class DatabaseSeeder extends Seeder
             PermissionSeeder::class,
             UserTypePermissionSeeder::class,
             BrazilCitiesSeeder::class,
+            ImprovementTypeSeeder::class,
         ]);
     }
 }

+ 42 - 0
database/seeders/ImprovementTypeSeeder.php

@@ -0,0 +1,42 @@
+<?php
+
+namespace Database\Seeders;
+
+use App\Models\ImprovementType;
+use Illuminate\Database\Seeder;
+
+class ImprovementTypeSeeder extends Seeder
+{
+    public function run(): void
+    {
+        $types = [
+            // Exibidos quando o cliente avalia o prestador
+            ['description' => 'Agilidade',                 'improvement_type' => 'client'],
+            ['description' => 'Qualidade',                 'improvement_type' => 'client'],
+            ['description' => 'Dedicação',                 'improvement_type' => 'client'],
+            ['description' => 'Pontualidade',              'improvement_type' => 'client'],
+            ['description' => 'Cuidado com itens pessoais','improvement_type' => 'client'],
+
+            // Exibidos quando o prestador avalia o cliente
+            ['description' => 'Ambiente',                  'improvement_type' => 'provider'],
+            ['description' => 'Respeito',                  'improvement_type' => 'provider'],
+            ['description' => 'Materiais de limpeza',      'improvement_type' => 'provider'],
+            ['description' => 'Comunicação',               'improvement_type' => 'provider'],
+            ['description' => 'Comportamento adequado',    'improvement_type' => 'provider'],
+
+            // Exibidos nos dois contextos
+            ['description' => 'Organização',               'improvement_type' => 'both'],
+            ['description' => 'Simpatia',                  'improvement_type' => 'both'],
+        ];
+
+        foreach ($types as $type) {
+            ImprovementType::firstOrCreate(
+                [
+                    'description'      => $type['description'],
+                    'improvement_type' => $type['improvement_type'],
+                ],
+                ['is_active' => true]
+            );
+        }
+    }
+}

+ 14 - 6
database/seeders/UserTypePermissionSeeder.php

@@ -72,6 +72,9 @@ class UserTypePermissionSeeder extends Seeder
             ['scope' => 'config.service_type', 'bits' => 1],
             ['scope' => 'config.schedule', 'bits' => 271],
             ['scope' => 'config.custom_schedule', 'bits' => 271],
+            ['scope' => 'config.improvement_type', 'bits' => 1],
+            ['scope' => 'config.review', 'bits' => 271],
+            ['scope' => 'config.provider_client_block', 'bits' => 9],
           ];
           $this->seedUserTypePermissions($providerPermissions, UserTypeEnum::PROVIDER->value);
           break;
@@ -87,7 +90,9 @@ class UserTypePermissionSeeder extends Seeder
             ['scope' => 'config.client_payment_method', 'bits' => 271],
             ['scope' => 'config.provider_working_day', 'bits' => 271],
             ['scope' => 'config.provider_blocked_day', 'bits' => 271],
+            ['scope' => 'config.improvement_type', 'bits' => 1],
             ['scope' => 'config.review', 'bits' => 271],
+            ['scope' => 'config.client_provider_block', 'bits' => 9],
             ['scope' => 'config.schedule', 'bits' => 271],
             ['scope' => 'config.custom_schedule', 'bits' => 271],
             ['scope' => 'config.speciality', 'bits' => 271],
@@ -104,12 +109,15 @@ class UserTypePermissionSeeder extends Seeder
     foreach ($permissions as $permissionData) {
       $permission = Permission::where('scope', $permissionData['scope'])->first();
       if ($permission) {
-        $userTypePermission = UserTypePermission::firstOrNew([
-          'user_type' => $userType,
-          'permission_id' => $permission->id,
-          'bits' => $permissionData['bits'],
-        ]);
-        $userTypePermission->save();
+        UserTypePermission::updateOrCreate(
+          [
+            'user_type' => $userType,
+            'permission_id' => $permission->id,
+          ],
+          [
+            'bits' => $permissionData['bits'],
+          ]
+        );
       }
     }
   }

+ 1 - 0
routes/authRoutes/dashboard.php

@@ -4,4 +4,5 @@ use App\Http\Controllers\DashboardController;
 use Illuminate\Support\Facades\Route;
 
 Route::get('/dados-dashboard-cliente', [DashboardController::class, 'dadosDashboardCliente'])->middleware('permission:dashboard,view');
+Route::get('/dados-dashboard-cliente/schedule/{id}/detalhes', [DashboardController::class, 'scheduleClienteDetails'])->middleware('permission:dashboard,view');
 Route::get('/dados-dashboard-prestador', [DashboardController::class, 'dadosDashboardPrestador'])->middleware('permission:dashboard,view');