Просмотр исходного кода

✨ feat(partner-agreement-service): adicionar módulo de serviços dos parceiros

Fase: dev | Origin: melhoria-interna
Gustavo Zanatta 1 неделя назад
Родитель
Сommit
72e4d3a005

+ 70 - 0
app/Http/Controllers/PartnerAgreementServiceController.php

@@ -0,0 +1,70 @@
+<?php
+
+namespace App\Http\Controllers;
+
+use App\Http\Requests\PartnerAgreementServiceRequest;
+use App\Http\Requests\UploadMediaRequest;
+use App\Http\Resources\MediaResource;
+use App\Http\Resources\PartnerAgreementServiceResource;
+use App\Services\MediaService;
+use App\Services\PartnerAgreementServiceService;
+use Illuminate\Http\JsonResponse;
+
+class PartnerAgreementServiceController extends Controller
+{
+    public function __construct(
+        protected PartnerAgreementServiceService $service,
+        protected MediaService $mediaService,
+    ) {}
+
+    public function indexByPartner(int $partnerAgreementId): JsonResponse
+    {
+        $items = $this->service->getAllByPartner($partnerAgreementId);
+        return $this->successResponse(payload: PartnerAgreementServiceResource::collection($items));
+    }
+
+    public function store(PartnerAgreementServiceRequest $request): JsonResponse
+    {
+        $item = $this->service->create($request->validated());
+        return $this->successResponse(
+            payload: new PartnerAgreementServiceResource($item),
+            message: __('messages.created'),
+            code: 201,
+        );
+    }
+
+    public function show(int $id): JsonResponse
+    {
+        $item = $this->service->findById($id);
+        return $this->successResponse(payload: new PartnerAgreementServiceResource($item));
+    }
+
+    public function update(PartnerAgreementServiceRequest $request, int $id): JsonResponse
+    {
+        $item = $this->service->update($id, $request->validated());
+        return $this->successResponse(
+            payload: new PartnerAgreementServiceResource($item),
+            message: __('messages.updated'),
+        );
+    }
+
+    public function destroy(int $id): JsonResponse
+    {
+        $this->service->delete($id);
+        return $this->successResponse(message: __('messages.deleted'), code: 204);
+    }
+
+    public function uploadMedia(UploadMediaRequest $request, int $id): JsonResponse
+    {
+        $file      = $request->file('file');
+        $mediaType = str_starts_with($file->getMimeType(), 'image/') ? 'imagem' : 'documento';
+        $media     = $this->mediaService->upload($file, 'partner_agreement_service', $id, $mediaType);
+        return $this->successResponse(payload: new MediaResource($media), code: 201);
+    }
+
+    public function deleteMedia(int $id, int $mediaId): JsonResponse
+    {
+        $this->mediaService->delete($mediaId);
+        return $this->successResponse(message: __('messages.deleted'), code: 204);
+    }
+}

+ 33 - 0
app/Http/Requests/PartnerAgreementServiceRequest.php

@@ -0,0 +1,33 @@
+<?php
+
+namespace App\Http\Requests;
+
+use App\Enums\PartnerAgreementServiceStatusEnum;
+use Illuminate\Foundation\Http\FormRequest;
+use Illuminate\Validation\Rule;
+
+class PartnerAgreementServiceRequest extends FormRequest
+{
+    public function rules(): array
+    {
+        $rules = [
+            'partner_agreement_id' => 'sometimes|integer|exists:partner_agreements,id',
+            'service_number'       => 'sometimes|nullable|string|max:50',
+            'name'                 => 'sometimes|string|max:255',
+            'description'          => 'sometimes|nullable|string',
+            'category_id'          => 'sometimes|nullable|integer|exists:categories,id',
+            'price'                => 'sometimes|nullable|numeric|min:0',
+            'associate_price'      => 'sometimes|nullable|numeric|min:0',
+            'supplier_price'       => 'sometimes|nullable|numeric|min:0',
+            'requires_scheduling'  => 'sometimes|boolean',
+            'status'               => ['sometimes', Rule::enum(PartnerAgreementServiceStatusEnum::class)],
+        ];
+
+        if ($this->isMethod('post')) {
+            $rules['partner_agreement_id'] = 'required|integer|exists:partner_agreements,id';
+            $rules['name']                 = 'required|string|max:255';
+        }
+
+        return $rules;
+    }
+}

+ 33 - 0
app/Http/Resources/PartnerAgreementServiceResource.php

@@ -0,0 +1,33 @@
+<?php
+
+namespace App\Http\Resources;
+
+use Carbon\Carbon;
+use Illuminate\Http\Request;
+use Illuminate\Http\Resources\Json\JsonResource;
+use App\Http\Resources\MediaResource;
+
+class PartnerAgreementServiceResource extends JsonResource
+{
+    public function toArray(Request $request): array
+    {
+        return [
+            'id'                   => $this->id,
+            'partner_agreement_id' => $this->partner_agreement_id,
+            'partner_agreement'    => $this->whenLoaded('partnerAgreement', fn() => new PartnerAgreementResource($this->partnerAgreement)),
+            'service_number'       => $this->service_number,
+            'name'                 => $this->name,
+            'description'          => $this->description,
+            'category_id'          => $this->category_id,
+            'category'             => $this->whenLoaded('category', fn() => new CategoryResource($this->category)),
+            'price'                => $this->price,
+            'associate_price'      => $this->associate_price,
+            'supplier_price'       => $this->supplier_price,
+            'requires_scheduling'  => $this->requires_scheduling,
+            'status'               => $this->status,
+            'media'                => $this->whenLoaded('media', fn() => MediaResource::collection($this->media)),
+            'created_at'           => Carbon::parse($this->created_at)->format('Y-m-d H:i:s'),
+            'updated_at'           => Carbon::parse($this->updated_at)->format('Y-m-d H:i:s'),
+        ];
+    }
+}

+ 48 - 0
app/Models/PartnerAgreementService.php

@@ -0,0 +1,48 @@
+<?php
+
+namespace App\Models;
+
+use App\Enums\PartnerAgreementServiceStatusEnum;
+use Illuminate\Database\Eloquent\Model;
+use Illuminate\Database\Eloquent\Relations\BelongsTo;
+use Illuminate\Database\Eloquent\Relations\HasMany;
+use Illuminate\Database\Eloquent\SoftDeletes;
+use App\Models\Media;
+
+class PartnerAgreementService extends Model
+{
+    use SoftDeletes;
+
+    protected $guarded = ['id'];
+
+    protected function casts(): array
+    {
+        return [
+            'price'                => 'float',
+            'associate_price'      => 'float',
+            'supplier_price'       => 'float',
+            'requires_scheduling'  => 'boolean',
+            'status'               => PartnerAgreementServiceStatusEnum::class,
+        ];
+    }
+
+    public function partnerAgreement(): BelongsTo
+    {
+        return $this->belongsTo(PartnerAgreement::class);
+    }
+
+    public function category(): BelongsTo
+    {
+        return $this->belongsTo(Category::class);
+    }
+
+    public function appointments(): HasMany
+    {
+        return $this->hasMany(Appointment::class);
+    }
+
+    public function media(): HasMany
+    {
+        return $this->hasMany(Media::class, 'source_id')->where('source', 'partner_agreement_service');
+    }
+}

+ 50 - 0
app/Services/PartnerAgreementServiceService.php

@@ -0,0 +1,50 @@
+<?php
+
+namespace App\Services;
+
+use App\Models\PartnerAgreementService;
+use Illuminate\Database\Eloquent\Collection;
+
+class PartnerAgreementServiceService
+{
+    public function getAllByPartner(int $partnerAgreementId): Collection
+    {
+        return PartnerAgreementService::with(['category', 'media'])
+            ->where('partner_agreement_id', $partnerAgreementId)
+            ->orderBy('name')
+            ->get();
+    }
+
+    public function findById(int $id): ?PartnerAgreementService
+    {
+        return PartnerAgreementService::with(['partnerAgreement', 'category', 'media'])->find($id);
+    }
+
+    public function create(array $data): PartnerAgreementService
+    {
+        return PartnerAgreementService::create($data);
+    }
+
+    public function update(int $id, array $data): ?PartnerAgreementService
+    {
+        $model = PartnerAgreementService::find($id);
+
+        if (!$model) {
+            return null;
+        }
+
+        $model->update($data);
+        return $model->fresh(['category', 'media']);
+    }
+
+    public function delete(int $id): bool
+    {
+        $model = PartnerAgreementService::find($id);
+
+        if (!$model) {
+            return false;
+        }
+
+        return $model->delete();
+    }
+}

+ 36 - 0
database/migrations/2025_01_01_000007_create_partner_agreement_services_table.php

@@ -0,0 +1,36 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+return new class extends Migration
+{
+    public function up(): void
+    {
+        Schema::create('partner_agreement_services', function (Blueprint $table) {
+            $table->id();
+            $table->foreignId('partner_agreement_id')->constrained('partner_agreements')->cascadeOnDelete();
+            $table->string('service_number')->nullable();
+            $table->string('name');
+            $table->text('description')->nullable();
+            $table->foreignId('category_id')->nullable()->constrained('categories')->nullOnDelete();
+            $table->decimal('price', 10, 2)->nullable();
+            $table->decimal('associate_price', 10, 2)->nullable();
+            $table->decimal('supplier_price', 10, 2)->nullable();
+            $table->boolean('requires_scheduling')->default(false);
+            $table->string('status')->default('active');
+            $table->timestamps();
+            $table->softDeletes();
+
+            $table->index('partner_agreement_id');
+            $table->index('category_id');
+            $table->index('status');
+        });
+    }
+
+    public function down(): void
+    {
+        Schema::dropIfExists('partner_agreement_services');
+    }
+};

+ 19 - 0
routes/authRoutes/partner_agreement_service.php

@@ -0,0 +1,19 @@
+<?php
+
+use App\Http\Controllers\PartnerAgreementServiceController;
+use Illuminate\Support\Facades\Route;
+
+Route::controller(PartnerAgreementServiceController::class)->prefix('partner-agreement-service')->group(function () {
+    Route::get('/partner/{partnerAgreementId}', 'indexByPartner')->middleware('permission:parceiro.servico,view');
+
+    Route::post('/', 'store')->middleware('permission:parceiro.servico,add');
+
+    Route::get('/{id}', 'show')->middleware('permission:parceiro.servico,view');
+
+    Route::put('/{id}', 'update')->middleware('permission:parceiro.servico,edit');
+
+    Route::delete('/{id}', 'destroy')->middleware('permission:parceiro.servico,delete');
+
+    Route::post('/{id}/media', 'uploadMedia')->middleware('permission:parceiro.servico,edit');
+    Route::delete('/{id}/media/{mediaId}', 'deleteMedia')->middleware('permission:parceiro.servico,edit');
+});