Ver Fonte

feat: add service package no retorno do dashboard

Gustavo Mantovani há 6 dias atrás
pai
commit
eae5ff697a

+ 2 - 2
app/Data/Pagarme/Order/OrderRequestData.php

@@ -16,8 +16,8 @@ use Illuminate\Support\Collection;
 final readonly class OrderRequestData extends PagarmeData
 {
     /**
-     * @param  ItemData[]  $items
-     * @param  PaymentData[]  $payments
+     * @param ItemData[]    $items
+     * @param PaymentData[] $payments
      */
     public function __construct(
         public string  $code,

+ 3 - 3
app/Data/Pagarme/Order/OrderResponseData.php

@@ -11,9 +11,9 @@ use App\Data\Pagarme\PagarmeResponseData;
 use App\Enums\PaymentStatusEnum;
 
 /**
- * @param  ItemData[]  $items
- * @param  ChargeData[]  $charges
- * @param  CheckoutData[]  $checkouts
+ * @param ItemData[]     $items
+ * @param ChargeData[]   $charges
+ * @param CheckoutData[] $checkouts
  */
 final readonly class OrderResponseData extends PagarmeResponseData
 {

+ 31 - 0
app/Http/Controllers/ServicePackageController.php

@@ -73,6 +73,37 @@ class ServicePackageController extends Controller
 
     //
 
+    public function providerServicePackages(): JsonResponse
+    {
+        $items = $this->service->getByProviderUserId(Auth::id());
+
+        return $this->successResponse(payload: ServicePackageResource::collection($items));
+    }
+
+    public function acceptByProvider(int $id): JsonResponse
+    {
+        try {
+            $item = $this->service->acceptByProvider($id, Auth::id());
+
+            return $this->successResponse(payload: new ServicePackageResource($item), message: __('messages.updated'));
+        } catch (\Exception $e) {
+            return $this->errorResponse($e->getMessage(), 422);
+        }
+    }
+
+    public function refuseByProvider(int $id): JsonResponse
+    {
+        try {
+            $item = $this->service->refuseByProvider($id, Auth::id());
+
+            return $this->successResponse(payload: new ServicePackageResource($item), message: __('messages.updated'));
+        } catch (\Exception $e) {
+            return $this->errorResponse($e->getMessage(), 422);
+        }
+    }
+
+    //
+
     private function hasSchedulePayload(array $data): bool
     {
         return ! empty(data_get($data, 'schedules'))

+ 29 - 0
app/Services/DashboardService.php

@@ -693,6 +693,15 @@ class DashboardService
                         )
                 END AS time_since_request
             "),
+
+            DB::raw("
+                (
+                    SELECT service_package_items.service_package_id
+                    FROM service_package_items
+                    WHERE service_package_items.schedule_id = schedules.id
+                    LIMIT 1
+                ) AS service_package_id
+            "),
         )
         ->orderBy('schedules.date', 'asc')
         ->get();
@@ -743,6 +752,15 @@ class DashboardService
                     AND reviews.deleted_at IS NULL
                 ) AS provider_reviewed
             "),
+
+            DB::raw("
+                (
+                    SELECT service_package_items.service_package_id
+                    FROM service_package_items
+                    WHERE service_package_items.schedule_id = schedules.id
+                    LIMIT 1
+                ) AS service_package_id
+            "),
         )
         ->orderBy('schedules.start_time', 'asc')
         ->get();
@@ -767,6 +785,15 @@ class DashboardService
                 'schedules.schedule_type',
                 'schedules.status',
                 'custom_schedules.offers_meal',
+
+                DB::raw("
+                    (
+                        SELECT service_package_items.service_package_id
+                        FROM service_package_items
+                        WHERE service_package_items.schedule_id = schedules.id
+                        LIMIT 1
+                    ) AS service_package_id
+                "),
             )
             ->orderBy('schedules.date', 'asc')
             ->get();
@@ -948,6 +975,8 @@ class DashboardService
         return $rate > 1 ? $rate / 100 : $rate;
     }
 
+    //
+
     private function addressForDistance(int $clientId, ?Address $primaryAddress): ?Address
     {
         if ($primaryAddress?->latitude !== null && $primaryAddress?->longitude !== null) {

+ 9 - 0
app/Services/ProviderCalendarService.php

@@ -65,6 +65,15 @@ class ProviderCalendarService
                     LIMIT 1
                 ) AS provider_stars
             "),
+
+            DB::raw("
+                (
+                    SELECT service_package_items.service_package_id
+                    FROM service_package_items
+                    WHERE service_package_items.schedule_id = schedules.id
+                    LIMIT 1
+                ) AS service_package_id
+            "),
         ];
 
         $signPhoto = fn ($item) => tap($item, fn ($i) => $i->customer_photo = $i->customer_photo

+ 11 - 1
app/Services/ScheduleService.php

@@ -130,13 +130,23 @@ class ScheduleService
 
     //
 
-    public function updateStatus($id, string $status)
+    public function updateStatus($id, string $status, bool $fromPackage = false)
     {
         try {
             DB::beginTransaction();
 
             $schedule = Schedule::with(['provider.user', 'client.user', 'address'])->findOrFail($id);
 
+            if (! $fromPackage && in_array($status, ['accepted', 'rejected']) && Auth::user()->type === UserTypeEnum::PROVIDER) {
+                $belongsToServicePackage = DB::table('service_package_items')
+                    ->where('schedule_id', $schedule->id)
+                    ->exists();
+
+                if ($belongsToServicePackage) {
+                    throw new \DomainException(__('messages.schedule_belongs_to_package_use_package_endpoint'));
+                }
+            }
+
             $allowedTransitions = [
                 'pending'   => ['accepted', 'rejected', 'cancelled'],
                 'accepted'  => ['paid', 'cancelled'],

+ 67 - 1
app/Services/ServicePackageService.php

@@ -90,6 +90,73 @@ class ServicePackageService
             ->get();
     }
 
+    public function getByProviderUserId(int $userId): Collection
+    {
+        return ServicePackage::query()
+            ->with(['items.schedule.client.user', 'items.schedule.provider.user', 'items.schedule.address'])
+            ->whereHas('provider', fn ($query) => $query->where('user_id', $userId))
+            ->orderBy('created_at', 'desc')
+            ->get();
+    }
+
+    //
+
+    public function acceptByProvider(int $id, int $userId): ServicePackage
+    {
+        $package = ServicePackage::query()
+            ->with(['items.schedule'])
+            ->whereHas('provider', fn ($query) => $query->where('user_id', $userId))
+            ->findOrFail($id);
+
+        if ($package->status->value !== 'open') {
+            throw ValidationException::withMessages([
+                'status' => __('messages.service_package_must_be_open_for_changes'),
+            ]);
+        }
+
+        $scheduleService = app(ScheduleService::class);
+
+        DB::transaction(function () use ($package, $scheduleService) {
+            foreach ($package->items as $item) {
+                if ($item->schedule && $item->schedule->status === 'pending') {
+                    $scheduleService->updateStatus($item->schedule->id, 'accepted', fromPackage: true);
+                }
+            }
+        });
+
+        return $package->fresh(['items.schedule.client.user', 'items.schedule.provider.user', 'items.schedule.address']);
+    }
+
+    public function refuseByProvider(int $id, int $userId): ServicePackage
+    {
+        $package = ServicePackage::query()
+            ->with(['items.schedule'])
+            ->whereHas('provider', fn ($query) => $query->where('user_id', $userId))
+            ->findOrFail($id);
+
+        if ($package->status->value !== 'open') {
+            throw ValidationException::withMessages([
+                'status' => __('messages.service_package_must_be_open_for_changes'),
+            ]);
+        }
+
+        $scheduleService = app(ScheduleService::class);
+
+        DB::transaction(function () use ($package, $scheduleService) {
+            foreach ($package->items as $item) {
+                if ($item->schedule && $item->schedule->status === 'pending') {
+                    $scheduleService->updateStatus($item->schedule->id, 'rejected', fromPackage: true);
+                }
+            }
+
+            $package->update(['status' => 'cancelled']);
+        });
+
+        return $package->fresh(['items.schedule.client.user', 'items.schedule.provider.user', 'items.schedule.address']);
+    }
+
+    //
+
     public function createForUser(array $data, int $userId): ServicePackage
     {
         $client = Client::query()
@@ -192,5 +259,4 @@ class ServicePackageService
 
         return (int) $providerIds->first();
     }
-
 }

+ 1 - 0
lang/pt/messages.php

@@ -71,4 +71,5 @@ return [
     'service_package_schedule_already_assigned'     => 'O agendamento já pertence a outro pacote.',
     'service_package_schedule_has_active_payment'   => 'O agendamento já possui um pagamento e não pode ser adicionado ao pacote.',
     'gender_only_for_providers'                     => 'O gênero só pode ser alterado para usuários prestadores.',
+    'schedule_belongs_to_package_use_package_endpoint' => 'Este agendamento pertence a um pacote de serviços. Use o endpoint de pacotes para aceitá-lo ou recusá-lo.',
 ];

+ 9 - 5
routes/authRoutes/service_package.php

@@ -6,8 +6,12 @@ use Illuminate\Support\Facades\Route;
 Route::get('/service-packages',  [ServicePackageController::class, 'index'])->middleware('permission:service-package,view');
 Route::post('/service-packages', [ServicePackageController::class, 'store'])->middleware('permission:service-package,add');
 
-Route::get('/service-packages/me',                  [ServicePackageController::class, 'myServicePackages']);
-Route::post('/service-packages/me',                 [ServicePackageController::class, 'storeMine']);
-Route::get('/service-packages/{id}',                [ServicePackageController::class, 'show'])->middleware('permission:service-package,view');
-Route::put('/service-packages/{id}',                [ServicePackageController::class, 'update'])->middleware('permission:service-package,edit');
-Route::delete('/service-packages/{id}',             [ServicePackageController::class, 'destroy'])->middleware('permission:service-package,delete');
+Route::get('/service-packages/me',      [ServicePackageController::class, 'myServicePackages']);
+Route::post('/service-packages/me',     [ServicePackageController::class, 'storeMine']);
+Route::get('/service-packages/provider', [ServicePackageController::class, 'providerServicePackages']);
+Route::get('/service-packages/{id}',    [ServicePackageController::class, 'show'])->middleware('permission:service-package,view');
+Route::put('/service-packages/{id}',    [ServicePackageController::class, 'update'])->middleware('permission:service-package,edit');
+Route::delete('/service-packages/{id}', [ServicePackageController::class, 'destroy'])->middleware('permission:service-package,delete');
+
+Route::patch('/service-packages/{id}/accept', [ServicePackageController::class, 'acceptByProvider']);
+Route::patch('/service-packages/{id}/refuse', [ServicePackageController::class, 'refuseByProvider']);