Parcourir la source

feat: add insercao das faixas ao criar unit

Gustavo Mantovani il y a 1 mois
Parent
commit
2d14b18d8a

+ 34 - 20
app/Http/Requests/InhabitantClassificationRequest.php

@@ -12,25 +12,17 @@ public function rules(): array
         $id = $this->route('id');
 
         $rules = [
-            'description' => ['sometimes', 'string', 'max:150'],
-
-            'acronym' => [
-                'sometimes',
-                'string',
-                'max:2',
-                Rule::unique('inhabitant_classifications', 'acronym')->ignore($id),
-            ],
+            'description'    => ['sometimes', 'string', 'max:150'],
+            'start'          => ['sometimes', 'integer', 'min:1'],
+            'end'            => ['sometimes', 'integer', 'min:1', 'gte:start'],
+            'tbr_percentage' => ['sometimes', 'numeric', 'min:0', 'max:1'],
         ];
 
         if ($this->isMethod('post')) {
-            $rules['description'][0] = 'required|string|max:150';
-
-            $rules['acronym'][0] = [
-                'required',
-                'string',
-                'max:2',
-                Rule::unique('inhabitant_classifications', 'acronym')->ignore($id),
-            ];
+            $rules['description']    = ['required', 'string', 'max:150'];
+            $rules['start']          = ['required', 'integer', 'min:1'];
+            $rules['end']            = ['required', 'integer', 'min:1', 'gte:start'];
+            $rules['tbr_percentage'] = ['required', 'numeric', 'min:0', 'max:1'];
         }
 
         return $rules;
@@ -39,10 +31,32 @@ public function rules(): array
     public function messages(): array
     {
         return [
-            'description.required' => 'A descrição é obrigatória.',
-            'acronym.required'     => 'A sigla é obrigatória.',
-            'acronym.max'          => 'A sigla deve ter no máximo 2 caracteres.',
-            'acronym.unique'       => 'Esta sigla já está em uso.',
+            'description.required'    => 'A descrição é obrigatória.',
+            'start.required'          => 'O mês de início é obrigatório.',
+            'end.required'            => 'O mês de fim é obrigatório.',
+            'end.gte'                 => 'O mês de fim deve ser maior ou igual ao início.',
+            'tbr_percentage.required' => 'A porcentagem do TBR é obrigatória.',
         ];
     }
+
+    protected function prepareForValidation()
+    {
+        if ($this->route('id')) {
+            $model = \App\Models\InhabitantClassification::find($this->route('id'));
+
+            if ($model) {
+                $data = [];
+
+                if (!$this->has('start')) {
+                    $data['start'] = $model->start;
+                }
+
+                if (!$this->has('end')) {
+                    $data['end'] = $model->end;
+                }
+
+                $this->merge($data);
+            }
+        }
+    }
 }

+ 12 - 17
app/Http/Requests/UnitInhabitantClassificationRequest.php

@@ -13,29 +13,24 @@ public function rules(): array
         $unitId = $this->input('unit_id');
 
         return [
-            'unit_id'     => ['required', 'integer', 'exists:units,id'],
-            'description' => ['required', 'string', 'max:150'],
-
-            'acronym' => [
-                'required',
-                'string',
-                'max:2',
-                Rule::unique('unit_inhabitant_classifications', 'acronym')
-                    ->where('unit_id', $unitId)
-                    ->ignore($id),
-            ],
+            'unit_id'        => ['required', 'integer', 'exists:units,id'],
+            'description'    => ['required', 'string', 'max:150'],
+            'start'          => ['required', 'integer', 'min:1'],
+            'end'            => ['required', 'integer', 'min:1', 'gte:start'],
+            'tbr_percentage' => ['required', 'numeric', 'min:0', 'max:1'],
         ];
     }
 
     public function messages(): array
     {
         return [
-            'unit_id.required'     => 'A unidade é obrigatória.',
-            'unit_id.exists'       => 'A unidade informada não existe.',
-            'description.required' => 'A descrição é obrigatória.',
-            'acronym.required'     => 'A sigla é obrigatória.',
-            'acronym.max'          => 'A sigla deve ter no máximo 2 caracteres.',
-            'acronym.unique'       => 'Esta sigla já está em uso para esta unidade.',
+            'unit_id.required'        => 'A unidade é obrigatória.',
+            'unit_id.exists'          => 'A unidade informada não existe.',
+            'description.required'    => 'A descrição é obrigatória.',
+            'start.required'          => 'O mês de início é obrigatório.',
+            'end.required'            => 'O mês de fim é obrigatório.',
+            'end.gte'                 => 'O mês de fim deve ser maior ou igual ao início.',
+            'tbr_percentage.required' => 'A porcentagem do TBR é obrigatória.',
         ];
     }
 }

+ 7 - 5
app/Http/Resources/InhabitantClassificationResource.php

@@ -18,11 +18,13 @@ class InhabitantClassificationResource extends JsonResource
     public function toArray(Request $request): array
     {
         return [
-            'id'          => $this->id,
-            'description' => $this->description,
-            'acronym'     => $this->acronym,
-            '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'),
+            'id'             => $this->id,
+            'description'    => $this->description,
+            'start'          => $this->start,
+            'end'            => $this->end,
+            'tbr_percentage' => $this->tbr_percentage,
+            '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'),
         ];
     }
 

+ 8 - 6
app/Http/Resources/UnitInhabitantClassificationResource.php

@@ -18,12 +18,14 @@ class UnitInhabitantClassificationResource extends JsonResource
     public function toArray(Request $request): array
     {
         return [
-            'id'          => $this->id,
-            'unit_id'     => $this->unit_id,
-            'description' => $this->description,
-            'acronym'     => $this->acronym,
-            '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'),
+            'id'             => $this->id,
+            'unit_id'        => $this->unit_id,
+            'description'    => $this->description,
+            'start'          => $this->start,
+            'end'            => $this->end,
+            'tbr_percentage' => $this->tbr_percentage,
+            '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'),
         ];
     }
 

+ 38 - 21
app/Services/InhabitantClassificationService.php

@@ -17,7 +17,7 @@ public function getAll(): Collection
     public function getSelectList(): Collection
     {
         return InhabitantClassification::orderBy('id')
-            ->get(['id', 'description', 'acronym']);
+            ->get(['id', 'description', 'start', 'end', 'tbr_percentage']);
     }
 
     public function findById(int $id): ?InhabitantClassification
@@ -40,13 +40,20 @@ public function update(int $id, array $data): ?InhabitantClassification
             return null;
         }
 
-        $oldDescription = $model->description;
-        $oldAcronym     = $model->acronym;
+        $oldStart          = $model->start;
+        $oldEnd            = $model->end;
+        $oldTbrPercentage  = $model->tbr_percentage;
+        $oldDescription    = $model->description;
 
         $model->update($data);
         $updated = $model->fresh();
 
-        $this->propagateUpdateToUnits($updated, $oldDescription, $oldAcronym);
+        $this->propagateUpdateToUnits($updated, [
+            'description'    => $oldDescription,
+            'start'          => $oldStart,
+            'end'            => $oldEnd,
+            'tbr_percentage' => $oldTbrPercentage,
+        ]);
 
         return $updated;
     }
@@ -66,42 +73,52 @@ public function delete(int $id): bool
 
     private function propagateToAllUnits(InhabitantClassification $parent): void
     {
-        $existingUnitIds = UnitInhabitantClassification::where('acronym', $parent->acronym)
+        $existingUnitIds = UnitInhabitantClassification::where('start', $parent->start)
+            ->where('end', $parent->end)
             ->pluck('unit_id');
 
         Unit::whereNotIn('id', $existingUnitIds)
             ->each(function (Unit $unit) use ($parent) {
                 UnitInhabitantClassification::create([
-                    'unit_id'     => $unit->id,
-                    'description' => $parent->description,
-                    'acronym'     => $parent->acronym,
+                    'unit_id'        => $unit->id,
+                    'description'    => $parent->description,
+                    'start'          => $parent->start,
+                    'end'            => $parent->end,
+                    'tbr_percentage' => $parent->tbr_percentage,
                 ]);
             });
     }
 
-    private function propagateUpdateToUnits(InhabitantClassification $parent, string $oldDescription, string $oldAcronym): void
+    private function propagateUpdateToUnits(InhabitantClassification $parent, array $old): void
     {
-        // propaga a atualizacao para as classificacoes de unidades que tenham a mesma descricao e sigla antigas
-
-        UnitInhabitantClassification::where('acronym', $oldAcronym)
-            ->where('description', $oldDescription)
+        // propaga a atualizacao para as classificacoes de unidades que tenham os mesmos valores antigos
+        UnitInhabitantClassification::where('start', $old['start'])
+            ->where('end', $old['end'])
+            ->where('tbr_percentage', $old['tbr_percentage'])
+            ->where('description', $old['description'])
             ->update([
-                'description' => $parent->description,
-                'acronym'     => $parent->acronym,
+                'description'    => $parent->description,
+                'start'          => $parent->start,
+                'end'            => $parent->end,
+                'tbr_percentage' => $parent->tbr_percentage,
             ]);
 
-        $coveredUnitIds = UnitInhabitantClassification::whereIn('acronym', array_unique([$parent->acronym, $oldAcronym]))
+        // garante que todas as unidades tenham a classificacao, criando para as que ainda nao tem
+        $coveredUnitIds = UnitInhabitantClassification::where(function ($q) use ($parent, $old) {
+                $q->where(fn($q) => $q->where('start', $parent->start)->where('end', $parent->end))
+                  ->orWhere(fn($q) => $q->where('start', $old['start'])->where('end', $old['end']));
+            })
             ->pluck('unit_id')
             ->unique();
 
-        // garante que todas as unidades tenham a classificacao atualizada, criando para as que ainda nao tem
-
         Unit::whereNotIn('id', $coveredUnitIds)
             ->each(function (Unit $unit) use ($parent) {
                 UnitInhabitantClassification::create([
-                    'unit_id'     => $unit->id,
-                    'description' => $parent->description,
-                    'acronym'     => $parent->acronym,
+                    'unit_id'        => $unit->id,
+                    'description'    => $parent->description,
+                    'start'          => $parent->start,
+                    'end'            => $parent->end,
+                    'tbr_percentage' => $parent->tbr_percentage,
                 ]);
             });
     }

+ 21 - 0
app/Services/UnitService.php

@@ -5,7 +5,9 @@
 use App\Models\ClassPackage;
 use App\Models\Franchisee;
 use App\Models\FranchiseeUnit;
+use App\Models\InhabitantClassification;
 use App\Models\Unit;
+use App\Models\UnitInhabitantClassification;
 use Illuminate\Database\Eloquent\Collection;
 use Illuminate\Http\UploadedFile;
 use Illuminate\Support\Facades\Storage;
@@ -63,6 +65,7 @@ public function create(array $data): Unit
         ]);
 
         $this->replicatePackagesToUnit($unit->id);
+        $this->replicateInhabitantClassificationsToUnit($unit->id);
 
         return $unit;
     }
@@ -97,6 +100,8 @@ public function delete(int $id): bool
         return $model->delete();
     }
 
+    //
+
     private function replicatePackagesToUnit(int $unitId): void
     {
         ClassPackage::with('products')->get()->each(function (ClassPackage $package) use ($unitId) {
@@ -104,6 +109,19 @@ private function replicatePackagesToUnit(int $unitId): void
         });
     }
 
+    private function replicateInhabitantClassificationsToUnit(int $unitId): void
+    {
+        InhabitantClassification::all()->each(function (InhabitantClassification $parent) use ($unitId) {
+            UnitInhabitantClassification::create([
+                'unit_id'        => $unitId,
+                'description'    => $parent->description,
+                'start'          => $parent->start,
+                'end'            => $parent->end,
+                'tbr_percentage' => $parent->tbr_percentage,
+            ]);
+        });
+    }
+
     private function handleAvatar(array $data, ?string $oldAvatarPath = null): array
     {
         if (!isset($data['avatar'])) {
@@ -114,15 +132,18 @@ private function handleAvatar(array $data, ?string $oldAvatarPath = null): array
             if ($oldAvatarPath) {
                 Storage::delete($oldAvatarPath);
             }
+
             $data['avatar_url'] = $data['avatar']->store('units/avatars');
         } elseif (is_null($data['avatar'])) {
             if ($oldAvatarPath) {
                 Storage::delete($oldAvatarPath);
             }
+
             $data['avatar_url'] = null;
         }
 
         unset($data['avatar']);
+
         return $data;
     }
 }

+ 68 - 0
database/migrations/2026_05_06_180111_update_inhabitant_classifications_table.php

@@ -0,0 +1,68 @@
+<?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::table('inhabitant_classifications', function (Blueprint $table) {
+            $table->dropUnique(['acronym']);
+            $table->dropColumn('acronym');
+
+            $table->tinyInteger('start')
+                ->unsigned()
+                ->nullable();
+
+            $table->tinyInteger('end')
+                ->unsigned()
+                ->nullable();
+
+            $table->decimal('tbr_percentage', 5, 4)
+                ->nullable();
+
+            $table->unique(['start', 'end']);
+        });
+
+        Schema::table('unit_inhabitant_classifications', function (Blueprint $table) {
+            $table->dropUnique(['unit_id', 'acronym']);
+            $table->dropColumn('acronym');
+
+            $table->tinyInteger('start')
+                ->unsigned()
+                ->nullable();
+
+            $table->tinyInteger('end')
+                ->unsigned()
+                ->nullable();
+
+            $table->decimal('tbr_percentage', 5, 4)
+                ->nullable();
+
+            $table->unique(['unit_id', 'start', 'end']);
+        });
+    }
+
+    public function down(): void
+    {
+        Schema::table('inhabitant_classifications', function (Blueprint $table) {
+            $table->dropUnique(['start', 'end']);
+            $table->dropColumn(['start', 'end', 'tbr_percentage']);
+
+            $table->string('acronym', 2)
+                ->unique()
+                ->nullable();
+        });
+
+        Schema::table('unit_inhabitant_classifications', function (Blueprint $table) {
+            $table->dropUnique(['unit_id', 'start', 'end']);
+            $table->dropColumn(['start', 'end', 'tbr_percentage']);
+
+            $table->string('acronym', 2)->after('description')->nullable();
+
+            $table->unique(['unit_id', 'acronym']);
+        });
+    }
+};