瀏覽代碼

feat(services): regra de negocio

ebagabee 1 周之前
父節點
當前提交
e79575a8b0

+ 50 - 0
app/Services/FnmBaseBracketService.php

@@ -0,0 +1,50 @@
+<?php
+
+namespace App\Services;
+
+use App\Models\FnmBaseBracket;
+use Illuminate\Database\Eloquent\Collection;
+
+class FnmBaseBracketService
+{
+    public function getAll(): Collection
+    {
+        return FnmBaseBracket::orderBy('created_at', 'desc')
+            ->get();
+    }
+
+    public function findById(int $id): ?FnmBaseBracket
+    {
+        return FnmBaseBracket::find($id);
+    }
+
+    public function create(array $data): FnmBaseBracket
+    {
+        return FnmBaseBracket::create($data);
+    }
+
+    public function update(int $id, array $data): ?FnmBaseBracket
+    {
+        $model = $this->findById($id);
+
+        if (!$model) {
+            return null;
+        }
+
+        $model->update($data);
+        return $model->fresh();
+    }
+
+    public function delete(int $id): bool
+    {
+        $model = $this->findById($id);
+
+        if (!$model) {
+            return false;
+        }
+
+        return $model->delete();
+    }
+
+    // Add custom business logic methods here
+}

+ 49 - 0
app/Services/FranchiseeFnmBracketService.php

@@ -0,0 +1,49 @@
+<?php
+
+namespace App\Services;
+
+use App\Models\FranchiseeFnmBracket;
+use Illuminate\Database\Eloquent\Collection;
+
+class FranchiseeFnmBracketService
+{
+    public function getByFranchiseeId(int $franchiseeId): Collection
+    {
+        return FranchiseeFnmBracket::where('franchisee_id', $franchiseeId)
+            ->orderBy('start_month')
+            ->get();
+    }
+
+    public function findById(int $id): ?FranchiseeFnmBracket
+    {
+        return FranchiseeFnmBracket::find($id);
+    }
+
+    public function create(array $data): FranchiseeFnmBracket
+    {
+        return FranchiseeFnmBracket::create($data);
+    }
+
+    public function update(int $id, array $data): ?FranchiseeFnmBracket
+    {
+        $model = $this->findById($id);
+
+        if (!$model) {
+            return null;
+        }
+
+        $model->update($data);
+        return $model->fresh();
+    }
+
+    public function delete(int $id): bool
+    {
+        $model = $this->findById($id);
+
+        if (!$model) {
+            return false;
+        }
+
+        return $model->delete();
+    }
+}

+ 49 - 0
app/Services/FranchiseeMaintenanceBracketService.php

@@ -0,0 +1,49 @@
+<?php
+
+namespace App\Services;
+
+use App\Models\FranchiseeMaintenanceBracket;
+use Illuminate\Database\Eloquent\Collection;
+
+class FranchiseeMaintenanceBracketService
+{
+    public function getByFranchiseeId(int $franchiseeId): Collection
+    {
+        return FranchiseeMaintenanceBracket::where('franchisee_id', $franchiseeId)
+            ->orderBy('start_month')
+            ->get();
+    }
+
+    public function findById(int $id): ?FranchiseeMaintenanceBracket
+    {
+        return FranchiseeMaintenanceBracket::find($id);
+    }
+
+    public function create(array $data): FranchiseeMaintenanceBracket
+    {
+        return FranchiseeMaintenanceBracket::create($data);
+    }
+
+    public function update(int $id, array $data): ?FranchiseeMaintenanceBracket
+    {
+        $model = $this->findById($id);
+
+        if (!$model) {
+            return null;
+        }
+
+        $model->update($data);
+        return $model->fresh();
+    }
+
+    public function delete(int $id): bool
+    {
+        $model = $this->findById($id);
+
+        if (!$model) {
+            return false;
+        }
+
+        return $model->delete();
+    }
+}

+ 49 - 0
app/Services/FranchiseeRoyaltiesBracketService.php

@@ -0,0 +1,49 @@
+<?php
+
+namespace App\Services;
+
+use App\Models\FranchiseeRoyaltiesBracket;
+use Illuminate\Database\Eloquent\Collection;
+
+class FranchiseeRoyaltiesBracketService
+{
+    public function getByFranchiseeId(int $franchiseeId): Collection
+    {
+        return FranchiseeRoyaltiesBracket::where('franchisee_id', $franchiseeId)
+            ->orderBy('start_month')
+            ->get();
+    }
+
+    public function findById(int $id): ?FranchiseeRoyaltiesBracket
+    {
+        return FranchiseeRoyaltiesBracket::find($id);
+    }
+
+    public function create(array $data): FranchiseeRoyaltiesBracket
+    {
+        return FranchiseeRoyaltiesBracket::create($data);
+    }
+
+    public function update(int $id, array $data): ?FranchiseeRoyaltiesBracket
+    {
+        $model = $this->findById($id);
+
+        if (!$model) {
+            return null;
+        }
+
+        $model->update($data);
+        return $model->fresh();
+    }
+
+    public function delete(int $id): bool
+    {
+        $model = $this->findById($id);
+
+        if (!$model) {
+            return false;
+        }
+
+        return $model->delete();
+    }
+}

+ 90 - 0
app/Services/FranchiseeTbrService.php

@@ -0,0 +1,90 @@
+<?php
+
+namespace App\Services;
+
+use App\Models\FnmBaseBracket;
+use App\Models\FranchiseeFnmBracket;
+use App\Models\FranchiseeMaintenanceBracket;
+use App\Models\FranchiseeRoyaltiesBracket;
+use App\Models\FranchiseeTbr;
+use App\Models\MaintenanceBaseBracket;
+use App\Models\RoyaltiesBaseBracket;
+use Illuminate\Support\Facades\DB;
+use Illuminate\Pagination\LengthAwarePaginator;
+
+class FranchiseeTbrService
+{
+    public function paginate(int $perPage = 15): LengthAwarePaginator
+    {
+        return FranchiseeTbr::with(['franchisee', 'contract', 'inhabitantClassification'])
+            ->orderBy('created_at', 'desc')
+            ->paginate($perPage);
+    }
+
+    public function findById(int $id): ?FranchiseeTbr
+    {
+        return FranchiseeTbr::with([
+            'franchisee',
+            'contract',
+            'inhabitantClassification',
+            'royaltiesBracket',
+            'fnmBracket',
+            'maintenanceBracket',
+        ])->find($id);
+    }
+
+    public function createWithBrackets(array $data): FranchiseeTbr
+    {
+        return DB::transaction(function () use ($data) {
+            $franchiseeId = $data['franchisee_id'];
+
+            $royaltyBrackets     = $this->copyBaseBrackets(RoyaltiesBaseBracket::class, FranchiseeRoyaltiesBracket::class, $franchiseeId);
+            $fnmBrackets         = $this->copyBaseBrackets(FnmBaseBracket::class, FranchiseeFnmBracket::class, $franchiseeId);
+            $maintenanceBrackets = $this->copyBaseBrackets(MaintenanceBaseBracket::class, FranchiseeMaintenanceBracket::class, $franchiseeId);
+
+            return FranchiseeTbr::create(array_merge($data, [
+                'franchisee_royalties_bracket_id'   => $royaltyBrackets->first()?->id,
+                'franchisee_fnm_bracket_id'         => $fnmBrackets->first()?->id,
+                'franchisee_maintenance_bracket_id' => $maintenanceBrackets->first()?->id,
+            ]));
+        });
+    }
+
+    public function update(int $id, array $data): ?FranchiseeTbr
+    {
+        $model = $this->findById($id);
+
+        if (!$model) {
+            return null;
+        }
+
+        $model->update($data);
+        return $model->fresh();
+    }
+
+    public function delete(int $id): bool
+    {
+        $model = $this->findById($id);
+
+        if (!$model) {
+            return false;
+        }
+
+        return $model->delete();
+    }
+
+    private function copyBaseBrackets(string $baseClass, string $franchiseeClass, int $franchiseeId): \Illuminate\Database\Eloquent\Collection
+    {
+        $baseBrackets = $baseClass::orderBy('start_month')->get();
+
+        $copied = $baseBrackets->map(fn ($base) => $franchiseeClass::create([
+            'franchisee_id' => $franchiseeId,
+            'description'   => $base->description,
+            'start_month'   => $base->start_month,
+            'end_month'     => $base->end_month,
+            'percentage'    => $base->percentage,
+        ]));
+
+        return $copied;
+    }
+}

+ 53 - 0
app/Services/InhabitantClassificationService.php

@@ -0,0 +1,53 @@
+<?php
+
+namespace App\Services;
+
+use App\Models\InhabitantClassification;
+use Illuminate\Database\Eloquent\Collection;
+
+class InhabitantClassificationService
+{
+    public function getAll(): Collection
+    {
+        return InhabitantClassification::orderBy('description')->get();
+    }
+
+    public function getSelectList(): Collection
+    {
+        return InhabitantClassification::orderBy('description')
+            ->get(['id', 'description', 'acronym']);
+    }
+
+    public function findById(int $id): ?InhabitantClassification
+    {
+        return InhabitantClassification::find($id);
+    }
+
+    public function create(array $data): InhabitantClassification
+    {
+        return InhabitantClassification::create($data);
+    }
+
+    public function update(int $id, array $data): ?InhabitantClassification
+    {
+        $model = $this->findById($id);
+
+        if (!$model) {
+            return null;
+        }
+
+        $model->update($data);
+        return $model->fresh();
+    }
+
+    public function delete(int $id): bool
+    {
+        $model = $this->findById($id);
+
+        if (!$model) {
+            return false;
+        }
+
+        return $model->delete();
+    }
+}

+ 50 - 0
app/Services/MaintenanceBaseBracketService.php

@@ -0,0 +1,50 @@
+<?php
+
+namespace App\Services;
+
+use App\Models\MaintenanceBaseBracket;
+use Illuminate\Database\Eloquent\Collection;
+
+class MaintenanceBaseBracketService
+{
+    public function getAll(): Collection
+    {
+        return MaintenanceBaseBracket::orderBy('created_at', 'desc')
+            ->get();
+    }
+
+    public function findById(int $id): ?MaintenanceBaseBracket
+    {
+        return MaintenanceBaseBracket::find($id);
+    }
+
+    public function create(array $data): MaintenanceBaseBracket
+    {
+        return MaintenanceBaseBracket::create($data);
+    }
+
+    public function update(int $id, array $data): ?MaintenanceBaseBracket
+    {
+        $model = $this->findById($id);
+
+        if (!$model) {
+            return null;
+        }
+
+        $model->update($data);
+        return $model->fresh();
+    }
+
+    public function delete(int $id): bool
+    {
+        $model = $this->findById($id);
+
+        if (!$model) {
+            return false;
+        }
+
+        return $model->delete();
+    }
+
+    // Add custom business logic methods here
+}

+ 50 - 0
app/Services/RoyaltiesBaseBracketService.php

@@ -0,0 +1,50 @@
+<?php
+
+namespace App\Services;
+
+use App\Models\RoyaltiesBaseBracket;
+use Illuminate\Database\Eloquent\Collection;
+
+class RoyaltiesBaseBracketService
+{
+    public function getAll(): Collection
+    {
+        return RoyaltiesBaseBracket::orderBy('created_at', 'desc')
+            ->get();
+    }
+
+    public function findById(int $id): ?RoyaltiesBaseBracket
+    {
+        return RoyaltiesBaseBracket::find($id);
+    }
+
+    public function create(array $data): RoyaltiesBaseBracket
+    {
+        return RoyaltiesBaseBracket::create($data);
+    }
+
+    public function update(int $id, array $data): ?RoyaltiesBaseBracket
+    {
+        $model = $this->findById($id);
+
+        if (!$model) {
+            return null;
+        }
+
+        $model->update($data);
+        return $model->fresh();
+    }
+
+    public function delete(int $id): bool
+    {
+        $model = $this->findById($id);
+
+        if (!$model) {
+            return false;
+        }
+
+        return $model->delete();
+    }
+
+    // Add custom business logic methods here
+}

+ 154 - 0
app/Services/TbrCalculationService.php

@@ -0,0 +1,154 @@
+<?php
+
+namespace App\Services;
+
+use App\Models\FranchiseeFnmBracket;
+use App\Models\FranchiseeMaintenanceBracket;
+use App\Models\FranchiseeRoyaltiesBracket;
+use App\Models\FranchiseeTbr;
+use App\Models\FranchiseeUnit;
+use App\Models\TbrCalculation;
+use App\Models\Unit;
+use Illuminate\Support\Facades\DB;
+use Illuminate\Pagination\LengthAwarePaginator;
+use Illuminate\Support\Facades\Auth;
+
+class TbrCalculationService
+{
+    private const ROYALTIES_REVENUE_RATE = 0.08;
+    private const FNM_REVENUE_RATE       = 0.02;
+    private const EXEMPT_THRESHOLD_MONTH = 3;
+
+    public function paginate(int $perPage = 15): LengthAwarePaginator
+    {
+        return TbrCalculation::with(['unit', 'user'])
+            ->orderBy('created_at', 'desc')
+            ->paginate($perPage);
+    }
+
+    public function findById(int $id): ?TbrCalculation
+    {
+        return TbrCalculation::with([
+            'unit',
+            'user',
+            'royaltiesBracket',
+            'fnmBracket',
+            'maintenanceBracket',
+        ])->find($id);
+    }
+
+    public function calculate(array $data): TbrCalculation
+    {
+        return DB::transaction(function () use ($data) {
+            $unit = Unit::findOrFail($data['unit_id']);
+
+            $franchiseeUnit = FranchiseeUnit::where('unit_id', $unit->id)->firstOrFail();
+
+            $franchiseeTbr = FranchiseeTbr::where('franchisee_id', $franchiseeUnit->franchisee_id)
+                ->where('year', now()->year)
+                ->firstOrFail();
+
+            $tbrValue      = (float) $franchiseeTbr->tbr_value;
+            $contractMonth = (int) $data['contract_month_reference'];
+            $revenueValue  = (float) $data['revenue_value'];
+
+            $royaltiesBracket  = $this->findBracket(FranchiseeRoyaltiesBracket::class, $franchiseeUnit->franchisee_id, $contractMonth);
+            $fnmBracket        = $this->findBracket(FranchiseeFnmBracket::class, $franchiseeUnit->franchisee_id, $contractMonth);
+            $maintenanceBracket = $this->findBracket(FranchiseeMaintenanceBracket::class, $franchiseeUnit->franchisee_id, $contractMonth);
+
+            $royaltiesBracketValue  = round((float) $royaltiesBracket->percentage * $tbrValue, 2);
+            $fnmBracketValue        = round((float) $fnmBracket->percentage * $tbrValue, 2);
+            $maintenanceBracketValue = round((float) $maintenanceBracket->percentage * $tbrValue, 2);
+
+            [$royaltiesEffectiveValue, $royaltiesEffectivePercentage, $royaltiesAppliedCriteria,
+             $fnmEffectiveValue, $fnmEffectivePercentage] = $this->resolveEffectiveValues(
+                $contractMonth,
+                $revenueValue,
+                $royaltiesBracket,
+                $royaltiesBracketValue,
+                $fnmBracket,
+                $fnmBracketValue,
+            );
+
+            $maintenanceEffectiveValue      = $maintenanceBracketValue;
+            $maintenanceEffectivePercentage = (float) $maintenanceBracket->percentage;
+
+            $bracketSubtotal = round($royaltiesBracketValue + $fnmBracketValue + $maintenanceBracketValue, 2);
+            $subtotal        = round($royaltiesEffectiveValue + $fnmEffectiveValue + $maintenanceEffectiveValue, 2);
+
+            return TbrCalculation::create([
+                'unit_id'                          => $unit->id,
+                'revenue_value'                    => $revenueValue,
+                'contract_month_reference'         => $contractMonth,
+                'tbr_value'                        => $tbrValue,
+                'royalties_bracket_id'             => $royaltiesBracket->id,
+                'royalties_bracket_percentage'     => $royaltiesBracket->percentage,
+                'royalties_bracket_value'          => $royaltiesBracketValue,
+                'fnm_bracket_id'                   => $fnmBracket->id,
+                'fnm_bracket_percentage'           => $fnmBracket->percentage,
+                'fnm_bracket_value'                => $fnmBracketValue,
+                'maintenance_bracket_id'           => $maintenanceBracket->id,
+                'maintenance_bracket_percentage'   => $maintenanceBracket->percentage,
+                'maintenance_bracket_value'        => $maintenanceBracketValue,
+                'royalties_effective_percentage'   => $royaltiesEffectivePercentage,
+                'royalties_effective_value'        => $royaltiesEffectiveValue,
+                'fnm_effective_percentage'         => $fnmEffectivePercentage,
+                'fnm_effective_value'              => $fnmEffectiveValue,
+                'maintenance_effective_percentage' => $maintenanceEffectivePercentage,
+                'maintenance_effective_value'      => $maintenanceEffectiveValue,
+                'bracket_subtotal'                 => $bracketSubtotal,
+                'subtotal'                         => $subtotal,
+                'final_value'                      => $subtotal,
+                'user_id'                          => Auth::id(),
+                'royalties_applied_criteria'       => $royaltiesAppliedCriteria,
+                'receivable_generated'             => false,
+            ]);
+        });
+    }
+
+    private function resolveEffectiveValues(
+        int $contractMonth,
+        float $revenueValue,
+        FranchiseeRoyaltiesBracket $royaltiesBracket,
+        float $royaltiesBracketValue,
+        FranchiseeFnmBracket $fnmBracket,
+        float $fnmBracketValue,
+    ): array {
+        if ($contractMonth <= self::EXEMPT_THRESHOLD_MONTH) {
+            return [0.0, 0.0, 'tbr_fixo', 0.0, 0.0];
+        }
+
+        $royaltiesFromRevenue = round(self::ROYALTIES_REVENUE_RATE * $revenueValue, 2);
+        $fnmFromRevenue       = round(self::FNM_REVENUE_RATE * $revenueValue, 2);
+
+        if ($royaltiesBracketValue >= $royaltiesFromRevenue) {
+            $royaltiesEffectiveValue      = $royaltiesBracketValue;
+            $royaltiesEffectivePercentage = (float) $royaltiesBracket->percentage;
+            $royaltiesAppliedCriteria     = 'tbr_fixo';
+        } else {
+            $royaltiesEffectiveValue      = $royaltiesFromRevenue;
+            $royaltiesEffectivePercentage = self::ROYALTIES_REVENUE_RATE;
+            $royaltiesAppliedCriteria     = 'percentual_faturamento';
+        }
+
+        if ($fnmBracketValue >= $fnmFromRevenue) {
+            $fnmEffectiveValue      = $fnmBracketValue;
+            $fnmEffectivePercentage = (float) $fnmBracket->percentage;
+        } else {
+            $fnmEffectiveValue      = $fnmFromRevenue;
+            $fnmEffectivePercentage = self::FNM_REVENUE_RATE;
+        }
+
+        return [$royaltiesEffectiveValue, $royaltiesEffectivePercentage, $royaltiesAppliedCriteria, $fnmEffectiveValue, $fnmEffectivePercentage];
+    }
+
+    private function findBracket(string $modelClass, int $franchiseeId, int $contractMonth): mixed
+    {
+        return $modelClass::where('franchisee_id', $franchiseeId)
+            ->where('start_month', '<=', $contractMonth)
+            ->where(function ($q) use ($contractMonth) {
+                $q->whereNull('end_month')->orWhere('end_month', '>=', $contractMonth);
+            })
+            ->firstOrFail();
+    }
+}

+ 52 - 0
app/Services/TbrService.php

@@ -0,0 +1,52 @@
+<?php
+
+namespace App\Services;
+
+use App\Models\Tbr;
+use Illuminate\Database\Eloquent\Collection;
+
+class TbrService
+{
+    public function getAll(): Collection
+    {
+        return Tbr::orderBy('year', 'desc')->get();
+    }
+
+    public function findById(int $id): ?Tbr
+    {
+        return Tbr::find($id);
+    }
+
+    public function findByYear(int $year): ?Tbr
+    {
+        return Tbr::where('year', $year)->first();
+    }
+
+    public function create(array $data): Tbr
+    {
+        return Tbr::create($data);
+    }
+
+    public function update(int $id, array $data): ?Tbr
+    {
+        $model = $this->findById($id);
+
+        if (!$model) {
+            return null;
+        }
+
+        $model->update($data);
+        return $model->fresh();
+    }
+
+    public function delete(int $id): bool
+    {
+        $model = $this->findById($id);
+
+        if (!$model) {
+            return false;
+        }
+
+        return $model->delete();
+    }
+}