Răsfoiți Sursa

feat: adiciona modulo de grupos

ebagabee 3 săptămâni în urmă
părinte
comite
7e7d6a7d41

+ 50 - 0
app/Http/Controllers/GroupController.php

@@ -0,0 +1,50 @@
+<?php
+
+namespace App\Http\Controllers;
+
+use App\Services\GroupService;
+use App\Http\Requests\GroupRequest;
+use App\Http\Resources\GroupResource;
+use Illuminate\Http\JsonResponse;
+
+class GroupController extends Controller
+{
+    public function __construct(protected GroupService $service) {}
+
+    public function index(): JsonResponse
+    {
+        $items = $this->service->getAll();
+        return $this->successResponse(payload: GroupResource::collection($items));
+    }
+
+    public function store(GroupRequest $request): JsonResponse
+    {
+        $item = $this->service->create($request->validated());
+        return $this->successResponse(
+            payload: new GroupResource($item),
+            message: __('messages.created'),
+            code: 201,
+        );
+    }
+
+    public function show(int $id): JsonResponse
+    {
+        $item = $this->service->findById($id);
+        return $this->successResponse(payload: new GroupResource($item));
+    }
+
+    public function update(GroupRequest $request, int $id): JsonResponse
+    {
+        $item = $this->service->update($id, $request->validated());
+        return $this->successResponse(
+            payload: new GroupResource($item),
+            message: __('messages.updated'),
+        );
+    }
+
+    public function destroy(int $id): JsonResponse
+    {
+        $this->service->delete($id);
+        return $this->successResponse(message: __('messages.deleted'), code: 204);
+    }
+}

+ 20 - 0
app/Http/Requests/GroupRequest.php

@@ -0,0 +1,20 @@
+<?php
+
+namespace App\Http\Requests;
+
+use Illuminate\Foundation\Http\FormRequest;
+
+class GroupRequest extends FormRequest
+{
+    public function rules(): array
+    {
+        $isCreate = $this->isMethod('POST') && !$this->route('id');
+
+        return [
+            'name'      => ($isCreate ? 'required' : 'sometimes|required') . '|string|max:255',
+            'status'    => 'sometimes|in:ACTIVE,INACTIVE',
+            'unit_ids'  => 'sometimes|nullable|array',
+            'unit_ids.*' => 'integer|exists:units,id',
+        ];
+    }
+}

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

@@ -0,0 +1,33 @@
+<?php
+
+namespace App\Http\Resources;
+
+use Carbon\Carbon;
+use Illuminate\Http\Request;
+use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
+use Illuminate\Http\Resources\Json\JsonResource;
+
+class GroupResource extends JsonResource
+{
+    public function toArray(Request $request): array
+    {
+        return [
+            'id'           => $this->id,
+            'name'         => $this->name,
+            'status'       => $this->status,
+            'active_units' => $this->whenLoaded('units', fn() => $this->units->count()),
+            'unit_ids'     => $this->whenLoaded('units', fn() => $this->units->pluck('id')),
+            'units'        => $this->whenLoaded('units', fn() => $this->units->map(fn($unit) => [
+                'id'           => $unit->id,
+                'fantasy_name' => $unit->fantasy_name,
+            ])),
+            'created_at' => Carbon::parse($this->created_at)->format('Y-m-d'),
+            'updated_at' => Carbon::parse($this->updated_at)->format('Y-m-d'),
+        ];
+    }
+
+    public static function collection($resource): AnonymousResourceCollection
+    {
+        return parent::collection($resource);
+    }
+}

+ 30 - 0
app/Models/Group.php

@@ -0,0 +1,30 @@
+<?php
+
+namespace App\Models;
+
+use App\Enums\DefaultStatusEnum;
+use Illuminate\Database\Eloquent\Factories\HasFactory;
+use Illuminate\Database\Eloquent\Model;
+use Illuminate\Database\Eloquent\Relations\BelongsToMany;
+use Illuminate\Database\Eloquent\SoftDeletes;
+
+class Group extends Model
+{
+    use HasFactory, SoftDeletes;
+
+    protected $table = 'groups';
+
+    protected $guarded = ['id'];
+
+    protected $casts = [
+        'status'     => DefaultStatusEnum::class,
+        'created_at' => 'datetime',
+        'updated_at' => 'datetime',
+        'deleted_at' => 'datetime',
+    ];
+
+    public function units(): BelongsToMany
+    {
+        return $this->belongsToMany(Unit::class, 'group_units');
+    }
+}

+ 5 - 0
app/Models/Unit.php

@@ -99,4 +99,9 @@ public function franchisees(): BelongsToMany
     {
         return $this->belongsToMany(Franchisee::class, 'franchisee_units');
     }
+
+    public function groups(): BelongsToMany
+    {
+        return $this->belongsToMany(Group::class, 'group_units');
+    }
 }

+ 67 - 0
app/Services/GroupService.php

@@ -0,0 +1,67 @@
+<?php
+
+namespace App\Services;
+
+use App\Models\Group;
+use Illuminate\Database\Eloquent\Collection;
+
+class GroupService
+{
+    public function getAll(): Collection
+    {
+        return Group::with('units')
+            ->orderBy('name')
+            ->get();
+    }
+
+    public function findById(int $id): ?Group
+    {
+        return Group::with('units')->find($id);
+    }
+
+    public function create(array $data): Group
+    {
+        $group = Group::create([
+            'name'   => $data['name'],
+            'status' => $data['status'] ?? 'ACTIVE',
+        ]);
+
+        if (!empty($data['unit_ids'])) {
+            $group->units()->sync($data['unit_ids']);
+        }
+
+        return $group->load('units');
+    }
+
+    public function update(int $id, array $data): ?Group
+    {
+        $group = $this->findById($id);
+
+        if (!$group) {
+            return null;
+        }
+
+        $group->update(array_filter([
+            'name'   => $data['name'] ?? null,
+            'status' => $data['status'] ?? null,
+        ], fn($v) => $v !== null));
+
+        if (array_key_exists('unit_ids', $data)) {
+            $group->units()->sync($data['unit_ids'] ?? []);
+        }
+
+        return $group->fresh('units');
+    }
+
+    public function delete(int $id): bool
+    {
+        $group = $this->findById($id);
+
+        if (!$group) {
+            return false;
+        }
+
+        $group->units()->detach();
+        return $group->delete();
+    }
+}

+ 27 - 0
database/migrations/2026_05_19_200000_create_groups_table.php

@@ -0,0 +1,27 @@
+<?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('groups', function (Blueprint $table) {
+            $table->id();
+            $table->string('name');
+            $table->string('status')->default('ACTIVE');
+            $table->timestamps();
+            $table->softDeletes();
+
+            $table->index('name');
+            $table->index('status');
+        });
+    }
+
+    public function down(): void
+    {
+        Schema::dropIfExists('groups');
+    }
+};

+ 25 - 0
database/migrations/2026_05_19_200001_create_group_units_table.php

@@ -0,0 +1,25 @@
+<?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('group_units', function (Blueprint $table) {
+            $table->id();
+            $table->foreignId('group_id')->constrained('groups')->cascadeOnDelete();
+            $table->foreignId('unit_id')->constrained('units')->cascadeOnDelete();
+            $table->timestamps();
+
+            $table->unique(['group_id', 'unit_id']);
+        });
+    }
+
+    public function down(): void
+    {
+        Schema::dropIfExists('group_units');
+    }
+};

+ 13 - 0
routes/authRoutes/group.php

@@ -0,0 +1,13 @@
+<?php
+
+use Illuminate\Support\Facades\Route;
+use App\Http\Controllers\GroupController;
+
+Route::controller(GroupController::class)->prefix('group')->group(function () {
+    Route::get('/', 'index');
+    Route::post('/', 'store');
+    Route::get('/{id}', 'show');
+    Route::put('/{id}', 'update');
+    Route::post('/{id}', 'update');
+    Route::delete('/{id}', 'destroy');
+});