Bläddra i källkod

feat: :sparkles: cruds cliente -> prestadores bloqueados + crud prestador -> clientes bloqueados

cruds cliente -> prestadores bloqueados + crud prestador -> clientes bloqueados
Gustavo Zanatta 4 dagar sedan
förälder
incheckning
35c28695ed

+ 54 - 0
app/Http/Controllers/ClientProviderBlockController.php

@@ -0,0 +1,54 @@
+<?php
+
+namespace App\Http\Controllers;
+
+use App\Http\Requests\ClientProviderBlockRequest;
+use App\Http\Resources\ClientProviderBlockResource;
+use App\Services\ClientProviderBlockService;
+use Illuminate\Http\JsonResponse;
+
+class ClientProviderBlockController extends Controller
+{
+    public function __construct(
+        private ClientProviderBlockService $service
+    ) {}
+
+    public function index(int $clientId): JsonResponse
+    {
+        $blocks = $this->service->getByClientId($clientId);
+
+        return $this->successResponse(
+            payload: ClientProviderBlockResource::collection($blocks),
+        );
+    }
+
+    public function store(ClientProviderBlockRequest $request): JsonResponse
+    {
+        $block = $this->service->create($request->validated());
+
+        return $this->successResponse(
+            payload: new ClientProviderBlockResource($block),
+            message: __("messages.created"),
+            code: 201,
+        );
+    }
+
+    public function destroy(int $id): JsonResponse
+    {
+        $this->service->delete($id);
+
+        return $this->successResponse(
+            message: __("messages.deleted"),
+            code: 204,
+        );
+    }
+
+    public function getBlockedProviders(int $clientId): JsonResponse
+    {
+        $providerIds = $this->service->getBlockedProviderIds($clientId);
+
+        return $this->successResponse(
+            payload: $providerIds,
+        );
+    }
+}

+ 54 - 0
app/Http/Controllers/ProviderClientBlockController.php

@@ -0,0 +1,54 @@
+<?php
+
+namespace App\Http\Controllers;
+
+use App\Http\Requests\ProviderClientBlockRequest;
+use App\Http\Resources\ProviderClientBlockResource;
+use App\Services\ProviderClientBlockService;
+use Illuminate\Http\JsonResponse;
+
+class ProviderClientBlockController extends Controller
+{
+    public function __construct(
+        private ProviderClientBlockService $service
+    ) {}
+
+    public function index(int $providerId): JsonResponse
+    {
+        $blocks = $this->service->getByProviderId($providerId);
+
+        return $this->successResponse(
+            payload: ProviderClientBlockResource::collection($blocks),
+        );
+    }
+
+    public function store(ProviderClientBlockRequest $request): JsonResponse
+    {
+        $block = $this->service->create($request->validated());
+
+        return $this->successResponse(
+            payload: new ProviderClientBlockResource($block),
+            message: __("messages.created"),
+            code: 201,
+        );
+    }
+
+    public function destroy(int $id): JsonResponse
+    {
+        $this->service->delete($id);
+
+        return $this->successResponse(
+            message: __("messages.deleted"),
+            code: 204,
+        );
+    }
+
+    public function getBlockedClients(int $providerId): JsonResponse
+    {
+        $clientIds = $this->service->getBlockedClientIds($providerId);
+
+        return $this->successResponse(
+            payload: $clientIds,
+        );
+    }
+}

+ 59 - 0
app/Http/Requests/ClientProviderBlockRequest.php

@@ -0,0 +1,59 @@
+<?php
+
+namespace App\Http\Requests;
+
+use Illuminate\Foundation\Http\FormRequest;
+use Illuminate\Validation\Rule;
+
+class ClientProviderBlockRequest extends FormRequest
+{
+    public function authorize(): bool
+    {
+        return true;
+    }
+
+    public function rules(): array
+    {
+        $clientId = $this->input('client_id');
+        $blockId = $this->route('id');
+
+        $rules = [
+            'client_id' => ['sometimes', 'integer', 'exists:clients,id'],
+            'provider_id' => [
+                'sometimes',
+                'integer',
+                'exists:providers,id',
+                Rule::unique('client_provider_blocks', 'provider_id')
+                    ->where('client_id', $clientId)
+                    ->whereNull('deleted_at')
+                    ->ignore($blockId),
+            ],
+        ];
+
+        if ($this->isMethod('POST')) {
+            $rules['client_id'] = ['required', 'integer', 'exists:clients,id'];
+            $rules['provider_id'] = [
+                'required',
+                'integer',
+                'exists:providers,id',
+                Rule::unique('client_provider_blocks', 'provider_id')
+                    ->where('client_id', $clientId)
+                    ->whereNull('deleted_at')
+                    ->ignore($blockId),
+            ];
+        }
+
+        return $rules;
+    }
+
+    public function messages(): array
+    {
+        return [
+            'client_id.required' => __('validation.required', ['attribute' => __('validation.attributes.client')]),
+            'client_id.exists' => __('validation.exists', ['attribute' => __('validation.attributes.client')]),
+            'provider_id.required' => __('validation.required', ['attribute' => __('validation.attributes.provider')]),
+            'provider_id.exists' => __('validation.exists', ['attribute' => __('validation.attributes.provider')]),
+            'provider_id.unique' => __('validation.client_provider_block.already_blocked'),
+        ];
+    }
+}

+ 59 - 0
app/Http/Requests/ProviderClientBlockRequest.php

@@ -0,0 +1,59 @@
+<?php
+
+namespace App\Http\Requests;
+
+use Illuminate\Foundation\Http\FormRequest;
+use Illuminate\Validation\Rule;
+
+class ProviderClientBlockRequest extends FormRequest
+{
+    public function authorize(): bool
+    {
+        return true;
+    }
+
+    public function rules(): array
+    {
+        $providerId = $this->input('provider_id');
+        $blockId = $this->route('id');
+
+        $rules = [
+            'provider_id' => ['sometimes', 'integer', 'exists:providers,id'],
+            'client_id' => [
+                'sometimes',
+                'integer',
+                'exists:clients,id',
+                Rule::unique('provider_client_blocks', 'client_id')
+                    ->where('provider_id', $providerId)
+                    ->whereNull('deleted_at')
+                    ->ignore($blockId),
+            ],
+        ];
+
+        if ($this->isMethod('POST')) {
+            $rules['provider_id'] = ['required', 'integer', 'exists:providers,id'];
+            $rules['client_id'] = [
+                'required',
+                'integer',
+                'exists:clients,id',
+                Rule::unique('provider_client_blocks', 'client_id')
+                    ->where('provider_id', $providerId)
+                    ->whereNull('deleted_at')
+                    ->ignore($blockId),
+            ];
+        }
+
+        return $rules;
+    }
+
+    public function messages(): array
+    {
+        return [
+            'provider_id.required' => __('validation.required', ['attribute' => __('validation.attributes.provider')]),
+            'provider_id.exists' => __('validation.exists', ['attribute' => __('validation.attributes.provider')]),
+            'client_id.required' => __('validation.required', ['attribute' => __('validation.attributes.client')]),
+            'client_id.exists' => __('validation.exists', ['attribute' => __('validation.attributes.client')]),
+            'client_id.unique' => __('validation.provider_client_block.already_blocked'),
+        ];
+    }
+}

+ 23 - 0
app/Http/Resources/ClientProviderBlockResource.php

@@ -0,0 +1,23 @@
+<?php
+
+namespace App\Http\Resources;
+
+use Illuminate\Http\Request;
+use Illuminate\Http\Resources\Json\JsonResource;
+
+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'),
+        ];
+    }
+}

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

@@ -0,0 +1,23 @@
+<?php
+
+namespace App\Http\Resources;
+
+use Illuminate\Http\Request;
+use Illuminate\Http\Resources\Json\JsonResource;
+
+class ProviderClientBlockResource extends JsonResource
+{
+    public function toArray(Request $request): array
+    {
+        return [
+            'id' => $this->id,
+            'provider_id' => $this->provider_id,
+            'client_id' => $this->client_id,
+            'client_name' => $this->client->user->name ?? null,
+            'client_email' => $this->client->user->email ?? null,
+            'client_phone' => $this->client->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'),
+        ];
+    }
+}

+ 20 - 0
app/Models/Client.php

@@ -6,6 +6,7 @@ use Illuminate\Database\Eloquent\Factories\HasFactory;
 use Illuminate\Database\Eloquent\Model;
 use Illuminate\Database\Eloquent\SoftDeletes;
 use Illuminate\Database\Eloquent\Relations\BelongsTo;
+use Illuminate\Database\Eloquent\Relations\HasMany;
 
 class Client extends Model
 {
@@ -22,8 +23,27 @@ class Client extends Model
         'deleted_at' => 'datetime',
     ];
 
+    /**
+     * @return BelongsTo
+     */
     public function user(): BelongsTo
     {
         return $this->belongsTo(User::class);
     }
+
+    /**
+     * @return HasMany
+     */
+    public function blockedByProviders(): HasMany
+    {
+        return $this->hasMany(ProviderClientBlock::class);
+    }
+
+    /**
+     * @return HasMany
+     */
+    public function blockedProviders(): HasMany
+    {
+        return $this->hasMany(ClientProviderBlock::class);
+    }
 }

+ 34 - 0
app/Models/ClientProviderBlock.php

@@ -0,0 +1,34 @@
+<?php
+
+namespace App\Models;
+
+use Illuminate\Database\Eloquent\Factories\HasFactory;
+use Illuminate\Database\Eloquent\Model;
+use Illuminate\Database\Eloquent\SoftDeletes;
+use Illuminate\Database\Eloquent\Relations\BelongsTo;
+
+class ClientProviderBlock extends Model
+{
+    use HasFactory, SoftDeletes;
+
+    protected $fillable = [
+        'client_id',
+        'provider_id',
+    ];
+
+    protected $casts = [
+        'created_at' => 'datetime',
+        'updated_at' => 'datetime',
+        'deleted_at' => 'datetime',
+    ];
+
+    public function client(): BelongsTo
+    {
+        return $this->belongsTo(Client::class);
+    }
+
+    public function provider(): BelongsTo
+    {
+        return $this->belongsTo(Provider::class);
+    }
+}

+ 16 - 0
app/Models/Provider.php

@@ -80,4 +80,20 @@ class Provider extends Model
     {
         return $this->belongsTo(Media::class, "profile_media_id");
     }
+
+    /**
+     * @return \Illuminate\Database\Eloquent\Relations\HasMany
+     */
+    public function blockedClients()
+    {
+        return $this->hasMany(ProviderClientBlock::class);
+    }
+
+    /**
+     * @return \Illuminate\Database\Eloquent\Relations\HasMany
+     */
+    public function blockedByClients()
+    {
+        return $this->hasMany(ClientProviderBlock::class);
+    }
 }

+ 34 - 0
app/Models/ProviderClientBlock.php

@@ -0,0 +1,34 @@
+<?php
+
+namespace App\Models;
+
+use Illuminate\Database\Eloquent\Factories\HasFactory;
+use Illuminate\Database\Eloquent\Model;
+use Illuminate\Database\Eloquent\SoftDeletes;
+use Illuminate\Database\Eloquent\Relations\BelongsTo;
+
+class ProviderClientBlock extends Model
+{
+    use HasFactory, SoftDeletes;
+
+    protected $fillable = [
+        'provider_id',
+        'client_id',
+    ];
+
+    protected $casts = [
+        'created_at' => 'datetime',
+        'updated_at' => 'datetime',
+        'deleted_at' => 'datetime',
+    ];
+
+    public function provider(): BelongsTo
+    {
+        return $this->belongsTo(Provider::class);
+    }
+
+    public function client(): BelongsTo
+    {
+        return $this->belongsTo(Client::class);
+    }
+}

+ 51 - 0
app/Services/ClientProviderBlockService.php

@@ -0,0 +1,51 @@
+<?php
+
+namespace App\Services;
+
+use App\Models\ClientProviderBlock;
+use Exception;
+
+class ClientProviderBlockService
+{
+    public function getByClientId(int $clientId)
+    {
+        return ClientProviderBlock::with(['provider.user'])
+            ->where('client_id', $clientId)
+            ->orderBy('created_at', 'desc')
+            ->get();
+    }
+
+    public function create(array $data): ClientProviderBlock
+    {
+        $existing = ClientProviderBlock::where('client_id', $data['client_id'])
+            ->where('provider_id', $data['provider_id'])
+            ->first();
+
+        if ($existing) {
+            if ($existing->trashed()) {
+                $existing->restore();
+                $existing->load(['provider.user']);
+                return $existing;
+            } else {
+                throw new Exception(__('validation.client_provider_block.already_blocked'));
+            }
+        }
+
+        $block = ClientProviderBlock::create($data);
+        $block->load(['provider.user']);
+        return $block;
+    }
+
+    public function delete(int $id): bool
+    {
+        $block = ClientProviderBlock::findOrFail($id);
+        return $block->delete();
+    }
+
+    public function getBlockedProviderIds(int $clientId): array
+    {
+        return ClientProviderBlock::where('client_id', $clientId)
+            ->pluck('provider_id')
+            ->toArray();
+    }
+}

+ 54 - 0
app/Services/ProviderClientBlockService.php

@@ -0,0 +1,54 @@
+<?php
+
+namespace App\Services;
+
+use App\Models\ProviderClientBlock;
+use Exception;
+
+class ProviderClientBlockService
+{
+    public function getByProviderId(int $providerId)
+    {
+        return ProviderClientBlock::with(['client.user'])
+            ->where('provider_id', $providerId)
+            ->orderBy('created_at', 'desc')
+            ->get();
+    }
+
+    public function create(array $data): ProviderClientBlock
+    {
+        // Validar duplicidade (ignorando soft-deleted)
+        $existing = ProviderClientBlock::where('provider_id', $data['provider_id'])
+            ->where('client_id', $data['client_id'])
+            ->first();
+
+        if ($existing) {
+            if ($existing->trashed()) {
+                // Se foi deletado (desbloqueado), restaura
+                $existing->restore();
+                $existing->load(['client.user']);
+                return $existing;
+            } else {
+                // Se já existe ativo, lança erro
+                throw new Exception(__('validation.provider_client_block.already_blocked'));
+            }
+        }
+
+        $block = ProviderClientBlock::create($data);
+        $block->load(['client.user']);
+        return $block;
+    }
+
+    public function delete(int $id): bool
+    {
+        $block = ProviderClientBlock::findOrFail($id);
+        return $block->delete();
+    }
+
+    public function getBlockedClientIds(int $providerId): array
+    {
+        return ProviderClientBlock::where('provider_id', $providerId)
+            ->pluck('client_id')
+            ->toArray();
+    }
+}

+ 33 - 0
database/migrations/2026_03_10_134549_create_provider_client_blocks_table.php

@@ -0,0 +1,33 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+return new class extends Migration
+{
+    /**
+     * Run the migrations.
+     */
+    public function up(): void
+    {
+        Schema::create('provider_client_blocks', function (Blueprint $table) {
+            $table->id();
+            $table->foreignId('provider_id')->constrained('providers')->onDelete('cascade');
+            $table->foreignId('client_id')->constrained('clients')->onDelete('cascade');
+            $table->timestamps();
+            $table->softDeletes();
+
+            $table->index('provider_id');
+            $table->index('client_id');
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     */
+    public function down(): void
+    {
+        Schema::dropIfExists('provider_client_blocks');
+    }
+};

+ 34 - 0
database/migrations/2026_03_10_144611_create_client_provider_blocks_table.php

@@ -0,0 +1,34 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+return new class extends Migration
+{
+    /**
+     * Run the migrations.
+     */
+    public function up(): void
+    {
+        Schema::create('client_provider_blocks', function (Blueprint $table) {
+            $table->id();
+            $table->foreignId('client_id')->constrained('clients')->onDelete('cascade');
+            $table->foreignId('provider_id')->constrained('providers')->onDelete('cascade');
+            $table->timestamps();
+            $table->softDeletes();
+
+            $table->index('client_id');
+            $table->index('provider_id');
+            $table->index('deleted_at');
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     */
+    public function down(): void
+    {
+        Schema::dropIfExists('client_provider_blocks');
+    }
+};

+ 12 - 0
database/seeders/PermissionSeeder.php

@@ -76,6 +76,18 @@ class PermissionSeeder extends Seeder
                         "bits" => 271,
                         "children" => [],
                     ],
+                    [
+                        "scope" => "config.provider_client_block",
+                        "description" => "Clientes Bloqueados do Prestador",
+                        "bits" => 271,
+                        "children" => [],
+                    ],
+                    [
+                        "scope" => "config.client_provider_block",
+                        "description" => "Prestadores Bloqueados do Cliente",
+                        "bits" => 271,
+                        "children" => [],
+                    ],
                     [
                         "scope" => "config.client_payment_method",
                         "description" => "Configurações de Métodos de Pagamento do Cliente",

+ 2 - 0
database/seeders/UserTypePermissionSeeder.php

@@ -35,6 +35,8 @@ class UserTypePermissionSeeder extends Seeder
                         ['scope' => 'config.city', 'bits' => 1],
                         ['scope' => 'config.client', 'bits' => 271],
                         ['scope' => 'config.client_favorite_provider', 'bits' => 271],
+                        ['scope' => 'config.provider_client_block', 'bits' => 271],
+                        ['scope' => 'config.client_provider_block', 'bits' => 271],
                         ['scope' => 'config.client_payment_method', 'bits' => 271],
                         ['scope' => 'config.schedule', 'bits' => 271],
                         ['scope' => 'config.custom_schedule', 'bits' => 271],

+ 6 - 0
lang/en/validation.php

@@ -213,6 +213,12 @@ return [
             'code_already_verified' => 'The code has already been verified for this schedule.',
             'invalid_code' => 'The provided code is invalid.',
         ],
+        'provider_client_block' => [
+            'already_blocked' => 'This client is already blocked by this provider.',
+        ],
+        'client_provider_block' => [
+            'already_blocked' => 'This provider is already blocked by this client.',
+        ],
     ],
 
     /*

+ 6 - 0
lang/es/validation.php

@@ -213,6 +213,12 @@ return [
             'code_already_verified' => 'El código ya fue verificado para este agendamiento.',
             'invalid_code' => 'El código informado es inválido.',
         ],
+        'provider_client_block' => [
+            'already_blocked' => 'Este cliente ya está bloqueado por este proveedor.',
+        ],
+        'client_provider_block' => [
+            'already_blocked' => 'Este proveedor ya está bloqueado por este cliente.',
+        ],
     ],
 
     /*

+ 6 - 0
lang/pt/validation.php

@@ -214,6 +214,12 @@ return [
             'code_already_verified' => 'O código já foi verificado para este agendamento.',
             'invalid_code' => 'O código informado é inválido.',
         ],
+        'provider_client_block' => [
+            'already_blocked' => 'Este cliente já está bloqueado por este prestador.',
+        ],
+        'client_provider_block' => [
+            'already_blocked' => 'Este prestador já está bloqueado por este cliente.',
+        ],
     ],
 
     /*

+ 9 - 0
routes/authRoutes/client_provider_block.php

@@ -0,0 +1,9 @@
+<?php
+
+use App\Http\Controllers\ClientProviderBlockController;
+use Illuminate\Support\Facades\Route;
+
+Route::get('/client-provider-blocks/{clientId}', [ClientProviderBlockController::class, 'index'])->middleware('permission:config.client_provider_block,view');
+Route::get('/client-provider-blocks/{clientId}/ids', [ClientProviderBlockController::class, 'getBlockedProviders'])->middleware('permission:config.client_provider_block,view');
+Route::post('/client-provider-blocks', [ClientProviderBlockController::class, 'store'])->middleware('permission:config.client_provider_block,add');
+Route::delete('/client-provider-blocks/{id}', [ClientProviderBlockController::class, 'destroy'])->middleware('permission:config.client_provider_block,delete');

+ 9 - 0
routes/authRoutes/provider_client_block.php

@@ -0,0 +1,9 @@
+<?php
+
+use App\Http\Controllers\ProviderClientBlockController;
+use Illuminate\Support\Facades\Route;
+
+Route::get('/provider-client-blocks/{providerId}', [ProviderClientBlockController::class, 'index'])->middleware('permission:config.provider_client_block,view');
+Route::get('/provider-client-blocks/{providerId}/ids', [ProviderClientBlockController::class, 'getBlockedClients'])->middleware('permission:config.provider_client_block,view');
+Route::post('/provider-client-blocks', [ProviderClientBlockController::class, 'store'])->middleware('permission:config.provider_client_block,add');
+Route::delete('/provider-client-blocks/{id}', [ProviderClientBlockController::class, 'destroy'])->middleware('permission:config.provider_client_block,delete');