浏览代码

feat: :sparkles: crud cliente formas pagamento

crud cliente formas pagamento
Gustavo Zanatta 1 月之前
父节点
当前提交
6a174f307b

+ 68 - 0
app/Http/Controllers/ClientPaymentMethodController.php

@@ -0,0 +1,68 @@
+<?php
+
+namespace App\Http\Controllers;
+
+use App\Http\Requests\ClientPaymentMethodRequest;
+use App\Http\Resources\ClientPaymentMethodResource;
+use App\Services\ClientPaymentMethodService;
+use Illuminate\Http\JsonResponse;
+
+class ClientPaymentMethodController extends Controller
+{
+    public function __construct(
+        private readonly ClientPaymentMethodService $service
+    ) {}
+
+    public function index(int $clientId): JsonResponse
+    {
+        $paymentMethods = $this->service->getByClientId($clientId);
+        
+        return $this->successResponse(
+            payload: ClientPaymentMethodResource::collection($paymentMethods)
+        );
+    }
+
+    public function show(int $id): JsonResponse
+    {
+        $paymentMethod = $this->service->findById($id);
+        
+        return $this->successResponse(
+            payload: new ClientPaymentMethodResource($paymentMethod)
+        );
+    }
+
+    public function store(ClientPaymentMethodRequest $request): JsonResponse
+    {
+        $paymentMethod = $this->service->create($request->validated());
+        
+        return $this->successResponse(
+            payload: new ClientPaymentMethodResource($paymentMethod),
+            message: __("messages.created"),
+            code: 201,
+        );
+    }
+
+    public function update(ClientPaymentMethodRequest $request, int $id): JsonResponse
+    {
+        $paymentMethod = $this->service->findById($id);
+        
+        $paymentMethod = $this->service->update($paymentMethod, $request->validated());
+        
+        return $this->successResponse(
+            payload: new ClientPaymentMethodResource($paymentMethod),
+            message: __("messages.updated"),
+        );
+    }
+
+    public function destroy(int $id): JsonResponse
+    {
+        $paymentMethod = $this->service->findById($id);
+        
+        $this->service->delete($paymentMethod);
+        
+        return $this->successResponse(
+            message: __("messages.deleted"),
+            code: 204,
+        );
+    }
+}

+ 0 - 2
app/Http/Controllers/ProviderBlockedDayController.php

@@ -26,7 +26,6 @@ class ProviderBlockedDayController extends Controller
     public function show(int $id): JsonResponse
     {
         $blockedDay = $this->service->findById($id);
-        abort_if(!$blockedDay, 404);
         return $this->successResponse(
             payload: new ProviderBlockedDayResource($blockedDay),
         );
@@ -56,7 +55,6 @@ class ProviderBlockedDayController extends Controller
     public function destroy(int $id): JsonResponse
     {
         $blockedDay = $this->service->findById($id);
-        abort_if(!$blockedDay, 404);
         
         $this->service->delete($blockedDay);
         return $this->successResponse(

+ 0 - 2
app/Http/Controllers/ProviderPaymentMethodController.php

@@ -26,7 +26,6 @@ class ProviderPaymentMethodController extends Controller
     public function show(int $id): ProviderPaymentMethodResource
     {
         $paymentMethod = $this->service->findById($id);
-        abort_if(!$paymentMethod, 404);
         return new ProviderPaymentMethodResource($paymentMethod);
     }
 
@@ -41,7 +40,6 @@ class ProviderPaymentMethodController extends Controller
     public function update(ProviderPaymentMethodRequest $request, int $id): JsonResponse
     {
         $paymentMethod = $this->service->findById($id);
-        abort_if(!$paymentMethod, 404);
         
         $paymentMethod = $this->service->update($paymentMethod, $request->validated());
         return $this->successResponse(

+ 18 - 3
app/Http/Requests/ClientFavoriteProviderRequest.php

@@ -17,10 +17,10 @@ class ClientFavoriteProviderRequest extends FormRequest
         $clientId = $this->input('client_id');
         $favoriteId = $this->route('id');
 
-        return [
-            'client_id' => ['required', 'integer', 'exists:clients,id'],
+        $rules = [
+            'client_id' => ['sometimes', 'integer', 'exists:clients,id'],
             'provider_id' => [
-                'required',
+                'sometimes',
                 'integer',
                 'exists:providers,id',
                 Rule::unique('client_favorite_providers', 'provider_id')
@@ -30,6 +30,21 @@ class ClientFavoriteProviderRequest extends FormRequest
             ],
             'notes' => ['nullable', 'string', 'max:1000'],
         ];
+
+        if ($this->isMethod('POST')) {
+            $rules['client_id'] = ['required', 'integer', 'exists:clients,id'];
+            $rules['provider_id'] = [
+                'required',
+                'integer',
+                'exists:providers,id',
+                Rule::unique('client_favorite_providers', 'provider_id')
+                    ->where('client_id', $clientId)
+                    ->whereNull('deleted_at')
+                    ->ignore($favoriteId),
+            ];
+        }
+
+        return $rules;
     }
 
     public function messages(): array

+ 73 - 0
app/Http/Requests/ClientPaymentMethodRequest.php

@@ -0,0 +1,73 @@
+<?php
+
+namespace App\Http\Requests;
+
+use Illuminate\Foundation\Http\FormRequest;
+
+class ClientPaymentMethodRequest extends FormRequest
+{
+    public function authorize(): bool
+    {
+        return true;
+    }
+
+    public function rules(): array
+    {
+        $rules = [
+            'client_id' => ['sometimes', 'integer', 'exists:clients,id'],
+            'card_number' => ['sometimes', 'string', 'min:13', 'max:19'],
+            'holder_name' => ['sometimes', 'string', 'max:255'],
+            'expiration' => ['sometimes', 'string', 'regex:/^(0[1-9]|1[0-2])\/\d{4}$/'],
+            'cvv' => ['sometimes', 'string', 'min:3', 'max:4'],
+            'card_name' => ['nullable', 'string', 'max:255'],
+            'brand' => ['nullable', 'string', 'max:50'],
+            'last_four_digits' => ['sometimes', 'string', 'size:4'],
+            'is_active' => ['nullable', 'boolean'],
+        ];
+
+        if ($this->isMethod('POST')) {
+            $rules['client_id'] = ['required', 'integer', 'exists:clients,id'];
+            $rules['card_number'] = ['required', 'string', 'min:13', 'max:19'];
+            $rules['holder_name'] = ['required', 'string', 'max:255'];
+            $rules['expiration'] = ['required', 'string', 'regex:/^(0[1-9]|1[0-2])\/\d{4}$/'];
+            $rules['cvv'] = ['required', 'string', 'min:3', 'max:4'];
+            $rules['last_four_digits'] = ['required', 'string', 'size:4'];
+        }
+
+        return $rules;
+    }
+
+    public function messages(): array
+    {
+        return [
+            'client_id.required' => 'O cliente é obrigatório.',
+            'client_id.exists' => 'Cliente não encontrado.',
+            'card_number.required' => 'O número do cartão é obrigatório.',
+            'card_number.min' => 'O número do cartão deve ter no mínimo 13 dígitos.',
+            'card_number.max' => 'O número do cartão deve ter no máximo 19 dígitos.',
+            'holder_name.required' => 'O nome do titular é obrigatório.',
+            'expiration.required' => 'A data de validade é obrigatória.',
+            'expiration.regex' => 'A data de validade deve estar no formato MM/YYYY.',
+            'cvv.required' => 'O CVV é obrigatório.',
+            'cvv.min' => 'O CVV deve ter no mínimo 3 dígitos.',
+            'cvv.max' => 'O CVV deve ter no máximo 4 dígitos.',
+            'last_four_digits.required' => 'Os últimos 4 dígitos são obrigatórios.',
+            'last_four_digits.size' => 'Devem ser exatamente 4 dígitos.',
+        ];
+    }
+
+    protected function prepareForValidation(): void
+    {
+        if ($this->has('card_number')) {
+            $this->merge([
+                'card_number' => str_replace(' ', '', $this->card_number),
+            ]);
+        }
+
+        if ($this->has('cvv')) {
+            $this->merge([
+                'cvv' => str_replace(' ', '', $this->cvv),
+            ]);
+        }
+    }
+}

+ 27 - 0
app/Http/Resources/ClientPaymentMethodResource.php

@@ -0,0 +1,27 @@
+<?php
+
+namespace App\Http\Resources;
+
+use Illuminate\Http\Request;
+use Illuminate\Http\Resources\Json\JsonResource;
+
+class ClientPaymentMethodResource extends JsonResource
+{
+    public function toArray(Request $request): array
+    {
+        return [
+            'id' => $this->id,
+            'client_id' => $this->client_id,
+            'holder_name' => $this->holder_name,
+            'expiration' => $this->expiration,
+            'card_name' => $this->card_name,
+            'brand' => $this->brand,
+            'last_four_digits' => $this->last_four_digits,
+            'cvv' => $this->cvv,
+            'card_number' => '**** **** **** ' . $this->last_four_digits,
+            'is_active' => $this->is_active,
+            'created_at' => $this->created_at?->format('Y-m-d H:i:s'),
+            'updated_at' => $this->updated_at?->format('Y-m-d H:i:s'),
+        ];
+    }
+}

+ 44 - 0
app/Models/ClientPaymentMethod.php

@@ -0,0 +1,44 @@
+<?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 ClientPaymentMethod extends Model
+{
+    use HasFactory, SoftDeletes;
+
+    protected $fillable = [
+        'client_id',
+        'card_number',
+        'holder_name',
+        'expiration',
+        'cvv',
+        'card_name',
+        'brand',
+        'last_four_digits',
+        'is_active',
+    ];
+
+    protected $casts = [
+        'card_number' => 'encrypted',
+        'cvv' => 'encrypted',
+        'is_active' => 'boolean',
+        'created_at' => 'datetime',
+        'updated_at' => 'datetime',
+        'deleted_at' => 'datetime',
+    ];
+
+    protected $hidden = [
+        // 'card_number',
+        'cvv',
+    ];
+
+    public function client(): BelongsTo
+    {
+        return $this->belongsTo(Client::class);
+    }
+}

+ 57 - 0
app/Services/ClientPaymentMethodService.php

@@ -0,0 +1,57 @@
+<?php
+
+namespace App\Services;
+
+use App\Models\ClientPaymentMethod;
+use Illuminate\Support\Collection;
+
+class ClientPaymentMethodService
+{
+    public function getByClientId(int $clientId): Collection
+    {
+        return ClientPaymentMethod::where('client_id', $clientId)
+            ->orderBy('is_active', 'desc')
+            ->orderBy('created_at', 'desc')
+            ->get();
+    }
+
+    public function findById(int $id): ?ClientPaymentMethod
+    {
+        return ClientPaymentMethod::find($id);
+    }
+
+    public function create(array $data): ClientPaymentMethod
+    {
+        if ($data['is_active'] ?? true) {
+            $this->deactivateOtherCards($data['client_id']);
+        }
+
+        return ClientPaymentMethod::create($data);
+    }
+
+    public function update(ClientPaymentMethod $paymentMethod, array $data): ClientPaymentMethod
+    {
+        if (isset($data['is_active']) && $data['is_active']) {
+            $this->deactivateOtherCards($paymentMethod->client_id, $paymentMethod->id);
+        }
+
+        $paymentMethod->update($data);
+        return $paymentMethod->fresh();
+    }
+
+    public function delete(ClientPaymentMethod $paymentMethod): bool
+    {
+        return $paymentMethod->delete();
+    }
+
+    private function deactivateOtherCards(int $clientId, ?int $exceptId = null): void
+    {
+        $query = ClientPaymentMethod::where('client_id', $clientId);
+        
+        if ($exceptId) {
+            $query->where('id', '!=', $exceptId);
+        }
+
+        $query->update(['is_active' => false]);
+    }
+}

+ 39 - 0
database/migrations/2026_02_10_184616_create_client_payment_methods_table.php

@@ -0,0 +1,39 @@
+<?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_payment_methods', function (Blueprint $table) {
+            $table->id();
+            $table->foreignId('client_id')->constrained('clients')->onDelete('cascade');
+            $table->text('card_number');
+            $table->string('holder_name');
+            $table->string('expiration', 7);
+            $table->text('cvv');
+            $table->string('card_name')->nullable();
+            $table->string('brand')->nullable();
+            $table->string('last_four_digits', 4);
+            $table->boolean('is_active')->default(true);
+            $table->timestamps();
+            $table->softDeletes();
+
+            $table->index('client_id');
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     */
+    public function down(): void
+    {
+        Schema::dropIfExists('client_payment_methods');
+    }
+};

+ 6 - 0
database/seeders/PermissionSeeder.php

@@ -76,6 +76,12 @@ class PermissionSeeder extends Seeder
                         "bits" => 271,
                         "children" => [],
                     ],
+                    [
+                        "scope" => "config.client_payment_method",
+                        "description" => "Configurações de Métodos de Pagamento do Cliente",
+                        "bits" => 271,
+                        "children" => [],
+                    ],
                     [
                         "scope" => "config.country",
                         "description" => "Configurações de Países",

+ 1 - 0
database/seeders/UserTypePermissionSeeder.php

@@ -35,6 +35,7 @@ class UserTypePermissionSeeder extends Seeder
                         ['scope' => 'config.city', 'bits' => 1],
                         ['scope' => 'config.client', 'bits' => 271],
                         ['scope' => 'config.client_favorite_provider', 'bits' => 271],
+                        ['scope' => 'config.client_payment_method', 'bits' => 271],
                         ['scope' => 'config.country', 'bits' => 1],
                         ['scope' => 'config.state', 'bits' => 1],
                         ['scope' => 'config.provider', 'bits' => 271],

+ 13 - 0
routes/authRoutes/client_payment_method.php

@@ -0,0 +1,13 @@
+<?php
+
+use App\Http\Controllers\ClientPaymentMethodController;
+use Illuminate\Support\Facades\Route;
+
+// Get list by client
+Route::get('/client/payment-methods/{clientId}', [ClientPaymentMethodController::class, 'index']);
+
+// CRUD individual
+Route::get('/client/payment-method/{id}', [ClientPaymentMethodController::class, 'show']);
+Route::post('/client/payment-method', [ClientPaymentMethodController::class, 'store']);
+Route::put('/client/payment-method/{id}', [ClientPaymentMethodController::class, 'update']);
+Route::delete('/client/payment-method/{id}', [ClientPaymentMethodController::class, 'destroy']);