#3 Modulo Financeiro

Merge realizado
ebagabee mesclou 8 commits de Softpar/feat/GINC-GAB-modulo-financeiro em Softpar/development 1 semana atrás
74 arquivos alterados com 2857 adições e 5 exclusões
  1. 45 0
      app/Http/Controllers/FnmBaseBracketController.php
  2. 46 0
      app/Http/Controllers/FranchiseeFnmBracketController.php
  3. 46 0
      app/Http/Controllers/FranchiseeMaintenanceBracketController.php
  4. 46 0
      app/Http/Controllers/FranchiseeRoyaltiesBracketController.php
  5. 46 0
      app/Http/Controllers/FranchiseeTbrController.php
  6. 51 0
      app/Http/Controllers/InhabitantClassificationController.php
  7. 45 0
      app/Http/Controllers/MaintenanceBaseBracketController.php
  8. 45 0
      app/Http/Controllers/RoyaltiesBaseBracketController.php
  9. 34 0
      app/Http/Controllers/TbrCalculationController.php
  10. 45 0
      app/Http/Controllers/TbrController.php
  11. 28 0
      app/Http/Requests/FnmBaseBracketRequest.php
  12. 31 0
      app/Http/Requests/FranchiseeFnmBracketRequest.php
  13. 31 0
      app/Http/Requests/FranchiseeMaintenanceBracketRequest.php
  14. 31 0
      app/Http/Requests/FranchiseeRoyaltiesBracketRequest.php
  15. 43 0
      app/Http/Requests/FranchiseeTbrRequest.php
  16. 28 0
      app/Http/Requests/InhabitantClassificationRequest.php
  17. 28 0
      app/Http/Requests/MaintenanceBaseBracketRequest.php
  18. 28 0
      app/Http/Requests/RoyaltiesBaseBracketRequest.php
  19. 30 0
      app/Http/Requests/TbrCalculationRequest.php
  20. 27 0
      app/Http/Requests/TbrRequest.php
  21. 39 0
      app/Http/Resources/FnmBaseBracketResource.php
  22. 40 0
      app/Http/Resources/FranchiseeFnmBracketResource.php
  23. 40 0
      app/Http/Resources/FranchiseeMaintenanceBracketResource.php
  24. 40 0
      app/Http/Resources/FranchiseeRoyaltiesBracketResource.php
  25. 49 0
      app/Http/Resources/FranchiseeTbrResource.php
  26. 37 0
      app/Http/Resources/InhabitantClassificationResource.php
  27. 39 0
      app/Http/Resources/MaintenanceBaseBracketResource.php
  28. 39 0
      app/Http/Resources/RoyaltiesBaseBracketResource.php
  29. 60 0
      app/Http/Resources/TbrCalculationResource.php
  30. 37 0
      app/Http/Resources/TbrResource.php
  31. 30 0
      app/Models/FnmBaseBracket.php
  32. 38 0
      app/Models/FranchiseeFnmBracket.php
  33. 38 0
      app/Models/FranchiseeMaintenanceBracket.php
  34. 38 0
      app/Models/FranchiseeRoyaltiesBracket.php
  35. 78 0
      app/Models/FranchiseeTbr.php
  36. 27 0
      app/Models/InhabitantClassification.php
  37. 30 0
      app/Models/MaintenanceBaseBracket.php
  38. 30 0
      app/Models/RoyaltiesBaseBracket.php
  39. 28 0
      app/Models/Tbr.php
  40. 99 0
      app/Models/TbrCalculation.php
  41. 50 0
      app/Services/FnmBaseBracketService.php
  42. 49 0
      app/Services/FranchiseeFnmBracketService.php
  43. 49 0
      app/Services/FranchiseeMaintenanceBracketService.php
  44. 49 0
      app/Services/FranchiseeRoyaltiesBracketService.php
  45. 90 0
      app/Services/FranchiseeTbrService.php
  46. 53 0
      app/Services/InhabitantClassificationService.php
  47. 50 0
      app/Services/MaintenanceBaseBracketService.php
  48. 50 0
      app/Services/RoyaltiesBaseBracketService.php
  49. 154 0
      app/Services/TbrCalculationService.php
  50. 52 0
      app/Services/TbrService.php
  51. 23 0
      database/migrations/2026_04_23_165627_create_tbrs_table.php
  52. 23 0
      database/migrations/2026_04_23_165628_create_inhabitant_classifications_table.php
  53. 36 0
      database/migrations/2026_04_23_165629_create_franchisee_tbrs_table.php
  54. 25 0
      database/migrations/2026_04_23_165631_create_royalties_base_brackets_table.php
  55. 25 0
      database/migrations/2026_04_23_165632_create_fnm_base_brackets_table.php
  56. 25 0
      database/migrations/2026_04_23_165633_create_maintenance_base_brackets_table.php
  57. 28 0
      database/migrations/2026_04_23_165634_create_franchisee_royalties_brackets_table.php
  58. 28 0
      database/migrations/2026_04_23_165635_create_franchisee_fnm_brackets_table.php
  59. 28 0
      database/migrations/2026_04_23_165636_create_franchisee_maintenance_brackets_table.php
  60. 58 0
      database/migrations/2026_04_23_165638_create_tbr_calculations_table.php
  61. 1 0
      database/seeders/DatabaseSeeder.php
  62. 37 0
      database/seeders/PermissionSeeder.php
  63. 95 0
      database/seeders/TbrBaseBracketsSeeder.php
  64. 11 5
      database/seeders/UserTypePermissionSeeder.php
  65. 16 0
      routes/authRoutes/fnm_base_bracket.php
  66. 16 0
      routes/authRoutes/franchisee_fnm_bracket.php
  67. 16 0
      routes/authRoutes/franchisee_maintenance_bracket.php
  68. 16 0
      routes/authRoutes/franchisee_royalties_bracket.php
  69. 16 0
      routes/authRoutes/franchisee_tbr.php
  70. 18 0
      routes/authRoutes/inhabitant_classification.php
  71. 16 0
      routes/authRoutes/maintenance_base_bracket.php
  72. 16 0
      routes/authRoutes/royalties_base_bracket.php
  73. 16 0
      routes/authRoutes/tbr.php
  74. 12 0
      routes/authRoutes/tbr_calculation.php

+ 45 - 0
app/Http/Controllers/FnmBaseBracketController.php

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

+ 46 - 0
app/Http/Controllers/FranchiseeFnmBracketController.php

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

+ 46 - 0
app/Http/Controllers/FranchiseeMaintenanceBracketController.php

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

+ 46 - 0
app/Http/Controllers/FranchiseeRoyaltiesBracketController.php

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

+ 46 - 0
app/Http/Controllers/FranchiseeTbrController.php

@@ -0,0 +1,46 @@
+<?php
+
+namespace App\Http\Controllers;
+
+use App\Services\FranchiseeTbrService;
+use App\Http\Requests\FranchiseeTbrRequest;
+use App\Http\Resources\FranchiseeTbrResource;
+use Illuminate\Http\JsonResponse;
+use Illuminate\Http\Request;
+
+class FranchiseeTbrController extends Controller
+{
+    public function __construct(
+        protected FranchiseeTbrService $service,
+    ) {}
+
+    public function index(Request $request): JsonResponse
+    {
+        $items = $this->service->paginate($request->integer('per_page', 15));
+        return $this->successResponse(payload: FranchiseeTbrResource::collection($items));
+    }
+
+    public function store(FranchiseeTbrRequest $request): JsonResponse
+    {
+        $item = $this->service->createWithBrackets($request->validated());
+        return $this->successResponse(payload: new FranchiseeTbrResource($item), message: __('messages.created'), code: 201);
+    }
+
+    public function show(int $id): JsonResponse
+    {
+        $item = $this->service->findById($id);
+        return $this->successResponse(payload: new FranchiseeTbrResource($item));
+    }
+
+    public function update(FranchiseeTbrRequest $request, int $id): JsonResponse
+    {
+        $item = $this->service->update($id, $request->validated());
+        return $this->successResponse(payload: new FranchiseeTbrResource($item), message: __('messages.updated'));
+    }
+
+    public function destroy(int $id): JsonResponse
+    {
+        $this->service->delete($id);
+        return $this->successResponse(message: __('messages.deleted'), code: 204);
+    }
+}

+ 51 - 0
app/Http/Controllers/InhabitantClassificationController.php

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

+ 45 - 0
app/Http/Controllers/MaintenanceBaseBracketController.php

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

+ 45 - 0
app/Http/Controllers/RoyaltiesBaseBracketController.php

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

+ 34 - 0
app/Http/Controllers/TbrCalculationController.php

@@ -0,0 +1,34 @@
+<?php
+
+namespace App\Http\Controllers;
+
+use App\Services\TbrCalculationService;
+use App\Http\Requests\TbrCalculationRequest;
+use App\Http\Resources\TbrCalculationResource;
+use Illuminate\Http\JsonResponse;
+use Illuminate\Http\Request;
+
+class TbrCalculationController extends Controller
+{
+    public function __construct(
+        protected TbrCalculationService $service,
+    ) {}
+
+    public function index(Request $request): JsonResponse
+    {
+        $items = $this->service->paginate($request->integer('per_page', 15));
+        return $this->successResponse(payload: TbrCalculationResource::collection($items));
+    }
+
+    public function store(TbrCalculationRequest $request): JsonResponse
+    {
+        $item = $this->service->calculate($request->validated());
+        return $this->successResponse(payload: new TbrCalculationResource($item), message: __('messages.created'), code: 201);
+    }
+
+    public function show(int $id): JsonResponse
+    {
+        $item = $this->service->findById($id);
+        return $this->successResponse(payload: new TbrCalculationResource($item));
+    }
+}

+ 45 - 0
app/Http/Controllers/TbrController.php

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

+ 28 - 0
app/Http/Requests/FnmBaseBracketRequest.php

@@ -0,0 +1,28 @@
+<?php
+
+namespace App\Http\Requests;
+
+use Illuminate\Foundation\Http\FormRequest;
+
+class FnmBaseBracketRequest extends FormRequest
+{
+    public function rules(): array
+    {
+        return [
+            'description' => ['required', 'string', 'max:150'],
+            'start_month' => ['required', 'integer', 'min:1'],
+            'end_month'   => ['nullable', 'integer', 'min:1', 'gte:start_month'],
+            'percentage'  => ['required', 'numeric', 'min:0', 'max:1'],
+        ];
+    }
+
+    public function messages(): array
+    {
+        return [
+            'description.required' => 'A descrição é obrigatória.',
+            'start_month.required' => 'O mês inicial é obrigatório.',
+            'end_month.gte'        => 'O mês final deve ser maior ou igual ao mês inicial.',
+            'percentage.required'  => 'O percentual é obrigatório.',
+        ];
+    }
+}

+ 31 - 0
app/Http/Requests/FranchiseeFnmBracketRequest.php

@@ -0,0 +1,31 @@
+<?php
+
+namespace App\Http\Requests;
+
+use Illuminate\Foundation\Http\FormRequest;
+
+class FranchiseeFnmBracketRequest extends FormRequest
+{
+    public function rules(): array
+    {
+        return [
+            'franchisee_id' => ['required', 'integer', 'exists:franchisees,id'],
+            'description'   => ['required', 'string', 'max:150'],
+            'start_month'   => ['required', 'integer', 'min:1'],
+            'end_month'     => ['nullable', 'integer', 'min:1', 'gte:start_month'],
+            'percentage'    => ['required', 'numeric', 'min:0', 'max:1'],
+        ];
+    }
+
+    public function messages(): array
+    {
+        return [
+            'franchisee_id.required' => 'O franqueado é obrigatório.',
+            'franchisee_id.exists'   => 'Franqueado não encontrado.',
+            'description.required'   => 'A descrição é obrigatória.',
+            'start_month.required'   => 'O mês inicial é obrigatório.',
+            'end_month.gte'          => 'O mês final deve ser maior ou igual ao mês inicial.',
+            'percentage.required'    => 'O percentual é obrigatório.',
+        ];
+    }
+}

+ 31 - 0
app/Http/Requests/FranchiseeMaintenanceBracketRequest.php

@@ -0,0 +1,31 @@
+<?php
+
+namespace App\Http\Requests;
+
+use Illuminate\Foundation\Http\FormRequest;
+
+class FranchiseeMaintenanceBracketRequest extends FormRequest
+{
+    public function rules(): array
+    {
+        return [
+            'franchisee_id' => ['required', 'integer', 'exists:franchisees,id'],
+            'description'   => ['required', 'string', 'max:150'],
+            'start_month'   => ['required', 'integer', 'min:1'],
+            'end_month'     => ['nullable', 'integer', 'min:1', 'gte:start_month'],
+            'percentage'    => ['required', 'numeric', 'min:0', 'max:1'],
+        ];
+    }
+
+    public function messages(): array
+    {
+        return [
+            'franchisee_id.required' => 'O franqueado é obrigatório.',
+            'franchisee_id.exists'   => 'Franqueado não encontrado.',
+            'description.required'   => 'A descrição é obrigatória.',
+            'start_month.required'   => 'O mês inicial é obrigatório.',
+            'end_month.gte'          => 'O mês final deve ser maior ou igual ao mês inicial.',
+            'percentage.required'    => 'O percentual é obrigatório.',
+        ];
+    }
+}

+ 31 - 0
app/Http/Requests/FranchiseeRoyaltiesBracketRequest.php

@@ -0,0 +1,31 @@
+<?php
+
+namespace App\Http\Requests;
+
+use Illuminate\Foundation\Http\FormRequest;
+
+class FranchiseeRoyaltiesBracketRequest extends FormRequest
+{
+    public function rules(): array
+    {
+        return [
+            'franchisee_id' => ['required', 'integer', 'exists:franchisees,id'],
+            'description'   => ['required', 'string', 'max:150'],
+            'start_month'   => ['required', 'integer', 'min:1'],
+            'end_month'     => ['nullable', 'integer', 'min:1', 'gte:start_month'],
+            'percentage'    => ['required', 'numeric', 'min:0', 'max:1'],
+        ];
+    }
+
+    public function messages(): array
+    {
+        return [
+            'franchisee_id.required' => 'O franqueado é obrigatório.',
+            'franchisee_id.exists'   => 'Franqueado não encontrado.',
+            'description.required'   => 'A descrição é obrigatória.',
+            'start_month.required'   => 'O mês inicial é obrigatório.',
+            'end_month.gte'          => 'O mês final deve ser maior ou igual ao mês inicial.',
+            'percentage.required'    => 'O percentual é obrigatório.',
+        ];
+    }
+}

+ 43 - 0
app/Http/Requests/FranchiseeTbrRequest.php

@@ -0,0 +1,43 @@
+<?php
+
+namespace App\Http\Requests;
+
+use Illuminate\Foundation\Http\FormRequest;
+
+class FranchiseeTbrRequest extends FormRequest
+{
+    public function rules(): array
+    {
+        return [
+            'franchisee_id'                  => ['required', 'integer', 'exists:franchisees,id'],
+            'contract_id'                    => ['required', 'integer', 'exists:franchisee_contracts,id'],
+            'inhabitant_classification_id'   => ['required', 'integer', 'exists:inhabitant_classifications,id'],
+            'year'                           => ['required', 'integer', 'min:2000', 'max:2100'],
+            'tbr_value'                      => ['required', 'numeric', 'min:0'],
+            'start_date'                     => ['required', 'date'],
+            'invoice_due_day'                => ['required', 'integer', 'min:1', 'max:31'],
+            'base_royalties_percentage'      => ['required', 'numeric', 'min:0', 'max:1'],
+            'base_fnm_percentage'            => ['required', 'numeric', 'min:0', 'max:1'],
+        ];
+    }
+
+    public function messages(): array
+    {
+        return [
+            'franchisee_id.required'                => 'O franqueado é obrigatório.',
+            'franchisee_id.exists'                  => 'Franqueado não encontrado.',
+            'contract_id.required'                  => 'O contrato é obrigatório.',
+            'contract_id.exists'                    => 'Contrato não encontrado.',
+            'inhabitant_classification_id.required' => 'A classificação de habitantes é obrigatória.',
+            'inhabitant_classification_id.exists'   => 'Classificação de habitantes não encontrada.',
+            'year.required'                         => 'O ano é obrigatório.',
+            'tbr_value.required'                    => 'O valor da TBR é obrigatório.',
+            'start_date.required'                   => 'A data de início é obrigatória.',
+            'invoice_due_day.required'              => 'O dia de vencimento do boleto é obrigatório.',
+            'invoice_due_day.min'                   => 'O dia de vencimento deve ser entre 1 e 31.',
+            'invoice_due_day.max'                   => 'O dia de vencimento deve ser entre 1 e 31.',
+            'base_royalties_percentage.required'    => 'O percentual base de royalties é obrigatório.',
+            'base_fnm_percentage.required'          => 'O percentual base do FNM é obrigatório.',
+        ];
+    }
+}

+ 28 - 0
app/Http/Requests/InhabitantClassificationRequest.php

@@ -0,0 +1,28 @@
+<?php
+
+namespace App\Http\Requests;
+
+use Illuminate\Foundation\Http\FormRequest;
+
+class InhabitantClassificationRequest extends FormRequest
+{
+    public function rules(): array
+    {
+        $id = $this->route('id');
+
+        return [
+            'description' => ['required', 'string', 'max:150'],
+            'acronym'     => ['required', 'string', 'max:2', "unique:inhabitant_classifications,acronym,{$id}"],
+        ];
+    }
+
+    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.',
+        ];
+    }
+}

+ 28 - 0
app/Http/Requests/MaintenanceBaseBracketRequest.php

@@ -0,0 +1,28 @@
+<?php
+
+namespace App\Http\Requests;
+
+use Illuminate\Foundation\Http\FormRequest;
+
+class MaintenanceBaseBracketRequest extends FormRequest
+{
+    public function rules(): array
+    {
+        return [
+            'description' => ['required', 'string', 'max:150'],
+            'start_month' => ['required', 'integer', 'min:1'],
+            'end_month'   => ['nullable', 'integer', 'min:1', 'gte:start_month'],
+            'percentage'  => ['required', 'numeric', 'min:0', 'max:1'],
+        ];
+    }
+
+    public function messages(): array
+    {
+        return [
+            'description.required' => 'A descrição é obrigatória.',
+            'start_month.required' => 'O mês inicial é obrigatório.',
+            'end_month.gte'        => 'O mês final deve ser maior ou igual ao mês inicial.',
+            'percentage.required'  => 'O percentual é obrigatório.',
+        ];
+    }
+}

+ 28 - 0
app/Http/Requests/RoyaltiesBaseBracketRequest.php

@@ -0,0 +1,28 @@
+<?php
+
+namespace App\Http\Requests;
+
+use Illuminate\Foundation\Http\FormRequest;
+
+class RoyaltiesBaseBracketRequest extends FormRequest
+{
+    public function rules(): array
+    {
+        return [
+            'description' => ['required', 'string', 'max:150'],
+            'start_month' => ['required', 'integer', 'min:1'],
+            'end_month'   => ['nullable', 'integer', 'min:1', 'gte:start_month'],
+            'percentage'  => ['required', 'numeric', 'min:0', 'max:1'],
+        ];
+    }
+
+    public function messages(): array
+    {
+        return [
+            'description.required' => 'A descrição é obrigatória.',
+            'start_month.required' => 'O mês inicial é obrigatório.',
+            'end_month.gte'        => 'O mês final deve ser maior ou igual ao mês inicial.',
+            'percentage.required'  => 'O percentual é obrigatório.',
+        ];
+    }
+}

+ 30 - 0
app/Http/Requests/TbrCalculationRequest.php

@@ -0,0 +1,30 @@
+<?php
+
+namespace App\Http\Requests;
+
+use Illuminate\Foundation\Http\FormRequest;
+
+class TbrCalculationRequest extends FormRequest
+{
+    public function rules(): array
+    {
+        return [
+            'unit_id'                  => ['required', 'integer', 'exists:units,id'],
+            'revenue_value'            => ['required', 'numeric', 'min:0'],
+            'contract_month_reference' => ['required', 'integer', 'min:1', 'max:60'],
+        ];
+    }
+
+    public function messages(): array
+    {
+        return [
+            'unit_id.required'                  => 'A unidade é obrigatória.',
+            'unit_id.exists'                    => 'Unidade não encontrada.',
+            'revenue_value.required'            => 'O valor do faturamento é obrigatório.',
+            'revenue_value.min'                 => 'O faturamento não pode ser negativo.',
+            'contract_month_reference.required' => 'O mês de referência do contrato é obrigatório.',
+            'contract_month_reference.min'      => 'O mês de referência deve ser entre 1 e 60.',
+            'contract_month_reference.max'      => 'O mês de referência deve ser entre 1 e 60.',
+        ];
+    }
+}

+ 27 - 0
app/Http/Requests/TbrRequest.php

@@ -0,0 +1,27 @@
+<?php
+
+namespace App\Http\Requests;
+
+use Illuminate\Foundation\Http\FormRequest;
+
+class TbrRequest extends FormRequest
+{
+    public function rules(): array
+    {
+        $tbrId = $this->route('id');
+
+        return [
+            'year'      => ['required', 'integer', 'min:2000', 'max:2100', "unique:tbrs,year,{$tbrId}"],
+            'tbr_value' => ['required', 'numeric', 'min:0'],
+        ];
+    }
+
+    public function messages(): array
+    {
+        return [
+            'year.required'      => 'O ano é obrigatório.',
+            'year.unique'        => 'Já existe uma TBR para este ano.',
+            'tbr_value.required' => 'O valor da TBR é obrigatório.',
+        ];
+    }
+}

+ 39 - 0
app/Http/Resources/FnmBaseBracketResource.php

@@ -0,0 +1,39 @@
+<?php
+
+namespace App\Http\Resources;
+
+use Carbon\Carbon;
+use Illuminate\Http\Request;
+use Illuminate\Http\Resources\Json\JsonResource;
+use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
+use App\Models\FnmBaseBracket;
+
+class FnmBaseBracketResource extends JsonResource
+{
+    /**
+     * Transform the resource into an array.
+     *
+     * @return array<string, mixed>
+     */
+    public function toArray(Request $request): array
+    {
+        return [
+            'id'          => $this->id,
+            'description' => $this->description,
+            'start_month' => $this->start_month,
+            'end_month'   => $this->end_month,
+            'percentage'  => $this->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'),
+        ];
+    }
+
+    /**
+     * @param \Illuminate\Database\Eloquent\Collection<FnmBaseBracket> $resource
+     * @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection<FnmBaseBracketResource>
+     */
+    public static function collection($resource): AnonymousResourceCollection
+    {
+        return parent::collection($resource);
+    }
+}

+ 40 - 0
app/Http/Resources/FranchiseeFnmBracketResource.php

@@ -0,0 +1,40 @@
+<?php
+
+namespace App\Http\Resources;
+
+use Carbon\Carbon;
+use Illuminate\Http\Request;
+use Illuminate\Http\Resources\Json\JsonResource;
+use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
+use App\Models\FranchiseeFnmBracket;
+
+class FranchiseeFnmBracketResource extends JsonResource
+{
+    /**
+     * Transform the resource into an array.
+     *
+     * @return array<string, mixed>
+     */
+    public function toArray(Request $request): array
+    {
+        return [
+            'id'            => $this->id,
+            'franchisee_id' => $this->franchisee_id,
+            'description'   => $this->description,
+            'start_month'   => $this->start_month,
+            'end_month'     => $this->end_month,
+            'percentage'    => $this->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'),
+        ];
+    }
+
+    /**
+     * @param \Illuminate\Database\Eloquent\Collection<FranchiseeFnmBracket> $resource
+     * @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection<FranchiseeFnmBracketResource>
+     */
+    public static function collection($resource): AnonymousResourceCollection
+    {
+        return parent::collection($resource);
+    }
+}

+ 40 - 0
app/Http/Resources/FranchiseeMaintenanceBracketResource.php

@@ -0,0 +1,40 @@
+<?php
+
+namespace App\Http\Resources;
+
+use Carbon\Carbon;
+use Illuminate\Http\Request;
+use Illuminate\Http\Resources\Json\JsonResource;
+use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
+use App\Models\FranchiseeMaintenanceBracket;
+
+class FranchiseeMaintenanceBracketResource extends JsonResource
+{
+    /**
+     * Transform the resource into an array.
+     *
+     * @return array<string, mixed>
+     */
+    public function toArray(Request $request): array
+    {
+        return [
+            'id'            => $this->id,
+            'franchisee_id' => $this->franchisee_id,
+            'description'   => $this->description,
+            'start_month'   => $this->start_month,
+            'end_month'     => $this->end_month,
+            'percentage'    => $this->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'),
+        ];
+    }
+
+    /**
+     * @param \Illuminate\Database\Eloquent\Collection<FranchiseeMaintenanceBracket> $resource
+     * @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection<FranchiseeMaintenanceBracketResource>
+     */
+    public static function collection($resource): AnonymousResourceCollection
+    {
+        return parent::collection($resource);
+    }
+}

+ 40 - 0
app/Http/Resources/FranchiseeRoyaltiesBracketResource.php

@@ -0,0 +1,40 @@
+<?php
+
+namespace App\Http\Resources;
+
+use Carbon\Carbon;
+use Illuminate\Http\Request;
+use Illuminate\Http\Resources\Json\JsonResource;
+use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
+use App\Models\FranchiseeRoyaltiesBracket;
+
+class FranchiseeRoyaltiesBracketResource extends JsonResource
+{
+    /**
+     * Transform the resource into an array.
+     *
+     * @return array<string, mixed>
+     */
+    public function toArray(Request $request): array
+    {
+        return [
+            'id'             => $this->id,
+            'franchisee_id'  => $this->franchisee_id,
+            'description'    => $this->description,
+            'start_month'    => $this->start_month,
+            'end_month'      => $this->end_month,
+            'percentage'     => $this->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'),
+        ];
+    }
+
+    /**
+     * @param \Illuminate\Database\Eloquent\Collection<FranchiseeRoyaltiesBracket> $resource
+     * @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection<FranchiseeRoyaltiesBracketResource>
+     */
+    public static function collection($resource): AnonymousResourceCollection
+    {
+        return parent::collection($resource);
+    }
+}

+ 49 - 0
app/Http/Resources/FranchiseeTbrResource.php

@@ -0,0 +1,49 @@
+<?php
+
+namespace App\Http\Resources;
+
+use Carbon\Carbon;
+use Illuminate\Http\Request;
+use Illuminate\Http\Resources\Json\JsonResource;
+use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
+use App\Models\FranchiseeTbr;
+use App\Http\Resources\InhabitantClassificationResource;
+
+class FranchiseeTbrResource extends JsonResource
+{
+    /**
+     * Transform the resource into an array.
+     *
+     * @return array<string, mixed>
+     */
+    public function toArray(Request $request): array
+    {
+        return [
+            'id'                                  => $this->id,
+            'franchisee_id'                       => $this->franchisee_id,
+            'contract_id'                         => $this->contract_id,
+            'inhabitant_classification_id'        => $this->inhabitant_classification_id,
+            'year'                                => $this->year,
+            'tbr_value'                           => $this->tbr_value,
+            'start_date'                          => $this->start_date?->format('Y-m-d'),
+            'invoice_due_day'                     => $this->invoice_due_day,
+            'base_royalties_percentage'           => $this->base_royalties_percentage,
+            'base_fnm_percentage'                 => $this->base_fnm_percentage,
+            'franchisee_royalties_bracket_id'     => $this->franchisee_royalties_bracket_id,
+            'franchisee_fnm_bracket_id'           => $this->franchisee_fnm_bracket_id,
+            'franchisee_maintenance_bracket_id'   => $this->franchisee_maintenance_bracket_id,
+            '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'),
+            'inhabitant_classification'           => new InhabitantClassificationResource($this->whenLoaded('inhabitantClassification')),
+        ];
+    }
+
+    /**
+     * @param \Illuminate\Database\Eloquent\Collection<FranchiseeTbr> $resource
+     * @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection<FranchiseeTbrResource>
+     */
+    public static function collection($resource): AnonymousResourceCollection
+    {
+        return parent::collection($resource);
+    }
+}

+ 37 - 0
app/Http/Resources/InhabitantClassificationResource.php

@@ -0,0 +1,37 @@
+<?php
+
+namespace App\Http\Resources;
+
+use Carbon\Carbon;
+use Illuminate\Http\Request;
+use Illuminate\Http\Resources\Json\JsonResource;
+use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
+use App\Models\InhabitantClassification;
+
+class InhabitantClassificationResource extends JsonResource
+{
+    /**
+     * Transform the resource into an array.
+     *
+     * @return array<string, mixed>
+     */
+    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'),
+        ];
+    }
+
+    /**
+     * @param \Illuminate\Database\Eloquent\Collection<InhabitantClassification> $resource
+     * @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection<InhabitantClassificationResource>
+     */
+    public static function collection($resource): AnonymousResourceCollection
+    {
+        return parent::collection($resource);
+    }
+}

+ 39 - 0
app/Http/Resources/MaintenanceBaseBracketResource.php

@@ -0,0 +1,39 @@
+<?php
+
+namespace App\Http\Resources;
+
+use Carbon\Carbon;
+use Illuminate\Http\Request;
+use Illuminate\Http\Resources\Json\JsonResource;
+use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
+use App\Models\MaintenanceBaseBracket;
+
+class MaintenanceBaseBracketResource extends JsonResource
+{
+    /**
+     * Transform the resource into an array.
+     *
+     * @return array<string, mixed>
+     */
+    public function toArray(Request $request): array
+    {
+        return [
+            'id'          => $this->id,
+            'description' => $this->description,
+            'start_month' => $this->start_month,
+            'end_month'   => $this->end_month,
+            'percentage'  => $this->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'),
+        ];
+    }
+
+    /**
+     * @param \Illuminate\Database\Eloquent\Collection<MaintenanceBaseBracket> $resource
+     * @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection<MaintenanceBaseBracketResource>
+     */
+    public static function collection($resource): AnonymousResourceCollection
+    {
+        return parent::collection($resource);
+    }
+}

+ 39 - 0
app/Http/Resources/RoyaltiesBaseBracketResource.php

@@ -0,0 +1,39 @@
+<?php
+
+namespace App\Http\Resources;
+
+use Carbon\Carbon;
+use Illuminate\Http\Request;
+use Illuminate\Http\Resources\Json\JsonResource;
+use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
+use App\Models\RoyaltiesBaseBracket;
+
+class RoyaltiesBaseBracketResource extends JsonResource
+{
+    /**
+     * Transform the resource into an array.
+     *
+     * @return array<string, mixed>
+     */
+    public function toArray(Request $request): array
+    {
+        return [
+            'id'          => $this->id,
+            'description' => $this->description,
+            'start_month' => $this->start_month,
+            'end_month'   => $this->end_month,
+            'percentage'  => $this->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'),
+        ];
+    }
+
+    /**
+     * @param \Illuminate\Database\Eloquent\Collection<RoyaltiesBaseBracket> $resource
+     * @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection<RoyaltiesBaseBracketResource>
+     */
+    public static function collection($resource): AnonymousResourceCollection
+    {
+        return parent::collection($resource);
+    }
+}

+ 60 - 0
app/Http/Resources/TbrCalculationResource.php

@@ -0,0 +1,60 @@
+<?php
+
+namespace App\Http\Resources;
+
+use Carbon\Carbon;
+use Illuminate\Http\Request;
+use Illuminate\Http\Resources\Json\JsonResource;
+use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
+use App\Models\TbrCalculation;
+
+class TbrCalculationResource extends JsonResource
+{
+    /**
+     * Transform the resource into an array.
+     *
+     * @return array<string, mixed>
+     */
+    public function toArray(Request $request): array
+    {
+        return [
+            'id'                               => $this->id,
+            'unit_id'                          => $this->unit_id,
+            'revenue_value'                    => $this->revenue_value,
+            'contract_month_reference'         => $this->contract_month_reference,
+            'tbr_value'                        => $this->tbr_value,
+            'royalties_bracket_id'             => $this->royalties_bracket_id,
+            'royalties_bracket_percentage'     => $this->royalties_bracket_percentage,
+            'royalties_bracket_value'          => $this->royalties_bracket_value,
+            'fnm_bracket_id'                   => $this->fnm_bracket_id,
+            'fnm_bracket_percentage'           => $this->fnm_bracket_percentage,
+            'fnm_bracket_value'                => $this->fnm_bracket_value,
+            'maintenance_bracket_id'           => $this->maintenance_bracket_id,
+            'maintenance_bracket_percentage'   => $this->maintenance_bracket_percentage,
+            'maintenance_bracket_value'        => $this->maintenance_bracket_value,
+            'royalties_effective_percentage'   => $this->royalties_effective_percentage,
+            'royalties_effective_value'        => $this->royalties_effective_value,
+            'fnm_effective_percentage'         => $this->fnm_effective_percentage,
+            'fnm_effective_value'              => $this->fnm_effective_value,
+            'maintenance_effective_percentage' => $this->maintenance_effective_percentage,
+            'maintenance_effective_value'      => $this->maintenance_effective_value,
+            'bracket_subtotal'                 => $this->bracket_subtotal,
+            'subtotal'                         => $this->subtotal,
+            'final_value'                      => $this->final_value,
+            'user_id'                          => $this->user_id,
+            'royalties_applied_criteria'       => $this->royalties_applied_criteria,
+            'receivable_generated'             => $this->receivable_generated,
+            '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'),
+        ];
+    }
+
+    /**
+     * @param \Illuminate\Database\Eloquent\Collection<TbrCalculation> $resource
+     * @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection<TbrCalculationResource>
+     */
+    public static function collection($resource): AnonymousResourceCollection
+    {
+        return parent::collection($resource);
+    }
+}

+ 37 - 0
app/Http/Resources/TbrResource.php

@@ -0,0 +1,37 @@
+<?php
+
+namespace App\Http\Resources;
+
+use Carbon\Carbon;
+use Illuminate\Http\Request;
+use Illuminate\Http\Resources\Json\JsonResource;
+use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
+use App\Models\Tbr;
+
+class TbrResource extends JsonResource
+{
+    /**
+     * Transform the resource into an array.
+     *
+     * @return array<string, mixed>
+     */
+    public function toArray(Request $request): array
+    {
+        return [
+            'id'         => $this->id,
+            'year'       => $this->year,
+            'tbr_value'  => $this->tbr_value,
+            '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'),
+        ];
+    }
+
+    /**
+     * @param \Illuminate\Database\Eloquent\Collection<Tbr> $resource
+     * @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection<TbrResource>
+     */
+    public static function collection($resource): AnonymousResourceCollection
+    {
+        return parent::collection($resource);
+    }
+}

+ 30 - 0
app/Models/FnmBaseBracket.php

@@ -0,0 +1,30 @@
+<?php
+
+namespace App\Models;
+
+use Illuminate\Database\Eloquent\Factories\HasFactory;
+use Illuminate\Database\Eloquent\Model;
+
+/**
+ * @property int $id
+ * @property string $description
+ * @property int $start_month
+ * @property int|null $end_month
+ * @property float $percentage
+ * @property \Carbon\Carbon $created_at
+ * @property \Carbon\Carbon $updated_at
+ */
+class FnmBaseBracket extends Model
+{
+    use HasFactory;
+
+    protected $table = 'fnm_base_brackets';
+
+    protected $guarded = ['id'];
+
+    protected $casts = [
+        'percentage' => 'decimal:4',
+        'created_at' => 'datetime',
+        'updated_at' => 'datetime',
+    ];
+}

+ 38 - 0
app/Models/FranchiseeFnmBracket.php

@@ -0,0 +1,38 @@
+<?php
+
+namespace App\Models;
+
+use Illuminate\Database\Eloquent\Factories\HasFactory;
+use Illuminate\Database\Eloquent\Model;
+use Illuminate\Database\Eloquent\Relations\BelongsTo;
+
+/**
+ * @property int $id
+ * @property int $franchisee_id
+ * @property string $description
+ * @property int $start_month
+ * @property int|null $end_month
+ * @property float $percentage
+ * @property \Carbon\Carbon $created_at
+ * @property \Carbon\Carbon $updated_at
+ * @property-read \App\Models\Franchisee $franchisee
+ */
+class FranchiseeFnmBracket extends Model
+{
+    use HasFactory;
+
+    protected $table = 'franchisee_fnm_brackets';
+
+    protected $guarded = ['id'];
+
+    protected $casts = [
+        'percentage' => 'decimal:4',
+        'created_at' => 'datetime',
+        'updated_at' => 'datetime',
+    ];
+
+    public function franchisee(): BelongsTo
+    {
+        return $this->belongsTo(Franchisee::class, 'franchisee_id');
+    }
+}

+ 38 - 0
app/Models/FranchiseeMaintenanceBracket.php

@@ -0,0 +1,38 @@
+<?php
+
+namespace App\Models;
+
+use Illuminate\Database\Eloquent\Factories\HasFactory;
+use Illuminate\Database\Eloquent\Model;
+use Illuminate\Database\Eloquent\Relations\BelongsTo;
+
+/**
+ * @property int $id
+ * @property int $franchisee_id
+ * @property string $description
+ * @property int $start_month
+ * @property int|null $end_month
+ * @property float $percentage
+ * @property \Carbon\Carbon $created_at
+ * @property \Carbon\Carbon $updated_at
+ * @property-read \App\Models\Franchisee $franchisee
+ */
+class FranchiseeMaintenanceBracket extends Model
+{
+    use HasFactory;
+
+    protected $table = 'franchisee_maintenance_brackets';
+
+    protected $guarded = ['id'];
+
+    protected $casts = [
+        'percentage' => 'decimal:4',
+        'created_at' => 'datetime',
+        'updated_at' => 'datetime',
+    ];
+
+    public function franchisee(): BelongsTo
+    {
+        return $this->belongsTo(Franchisee::class, 'franchisee_id');
+    }
+}

+ 38 - 0
app/Models/FranchiseeRoyaltiesBracket.php

@@ -0,0 +1,38 @@
+<?php
+
+namespace App\Models;
+
+use Illuminate\Database\Eloquent\Factories\HasFactory;
+use Illuminate\Database\Eloquent\Model;
+use Illuminate\Database\Eloquent\Relations\BelongsTo;
+
+/**
+ * @property int $id
+ * @property int $franchisee_id
+ * @property string $description
+ * @property int $start_month
+ * @property int|null $end_month
+ * @property float $percentage
+ * @property \Carbon\Carbon $created_at
+ * @property \Carbon\Carbon $updated_at
+ * @property-read \App\Models\Franchisee $franchisee
+ */
+class FranchiseeRoyaltiesBracket extends Model
+{
+    use HasFactory;
+
+    protected $table = 'franchisee_royalties_brackets';
+
+    protected $guarded = ['id'];
+
+    protected $casts = [
+        'percentage' => 'decimal:4',
+        'created_at' => 'datetime',
+        'updated_at' => 'datetime',
+    ];
+
+    public function franchisee(): BelongsTo
+    {
+        return $this->belongsTo(Franchisee::class, 'franchisee_id');
+    }
+}

+ 78 - 0
app/Models/FranchiseeTbr.php

@@ -0,0 +1,78 @@
+<?php
+
+namespace App\Models;
+
+use Illuminate\Database\Eloquent\Factories\HasFactory;
+use Illuminate\Database\Eloquent\Model;
+use Illuminate\Database\Eloquent\Relations\BelongsTo;
+
+/**
+ * @property int $id
+ * @property int $franchisee_id
+ * @property int $contract_id
+ * @property int $inhabitant_classification_id
+ * @property int $year
+ * @property float $tbr_value
+ * @property \Carbon\Carbon $start_date
+ * @property int $invoice_due_day
+ * @property float $base_royalties_percentage
+ * @property float $base_fnm_percentage
+ * @property int|null $franchisee_royalties_bracket_id
+ * @property int|null $franchisee_fnm_bracket_id
+ * @property int|null $franchisee_maintenance_bracket_id
+ * @property \Carbon\Carbon $created_at
+ * @property \Carbon\Carbon $updated_at
+ * @property-read \App\Models\Franchisee $franchisee
+ * @property-read \App\Models\FranchiseeContract $contract
+ * @property-read \App\Models\InhabitantClassification $inhabitantClassification
+ * @property-read \App\Models\FranchiseeRoyaltiesBracket|null $royaltiesBracket
+ * @property-read \App\Models\FranchiseeFnmBracket|null $fnmBracket
+ * @property-read \App\Models\FranchiseeMaintenanceBracket|null $maintenanceBracket
+ */
+class FranchiseeTbr extends Model
+{
+    use HasFactory;
+
+    protected $table = 'franchisee_tbrs';
+
+    protected $guarded = ['id'];
+
+    protected $casts = [
+        'tbr_value'               => 'decimal:2',
+        'base_royalties_percentage' => 'decimal:4',
+        'base_fnm_percentage'     => 'decimal:4',
+        'start_date'              => 'date',
+        'created_at'              => 'datetime',
+        'updated_at'              => 'datetime',
+    ];
+
+    public function franchisee(): BelongsTo
+    {
+        return $this->belongsTo(Franchisee::class, 'franchisee_id');
+    }
+
+    public function contract(): BelongsTo
+    {
+        return $this->belongsTo(FranchiseeContract::class, 'contract_id');
+    }
+
+    public function inhabitantClassification(): BelongsTo
+    {
+        return $this->belongsTo(InhabitantClassification::class, 'inhabitant_classification_id');
+    }
+
+    public function royaltiesBracket(): BelongsTo
+    {
+        return $this->belongsTo(FranchiseeRoyaltiesBracket::class, 'franchisee_royalties_bracket_id');
+    }
+
+    public function fnmBracket(): BelongsTo
+    {
+        return $this->belongsTo(FranchiseeFnmBracket::class, 'franchisee_fnm_bracket_id');
+    }
+
+    public function maintenanceBracket(): BelongsTo
+    {
+        return $this->belongsTo(FranchiseeMaintenanceBracket::class, 'franchisee_maintenance_bracket_id');
+    }
+}

+ 27 - 0
app/Models/InhabitantClassification.php

@@ -0,0 +1,27 @@
+<?php
+
+namespace App\Models;
+
+use Illuminate\Database\Eloquent\Factories\HasFactory;
+use Illuminate\Database\Eloquent\Model;
+
+/**
+ * @property int $id
+ * @property string $description
+ * @property string $acronym
+ * @property \Carbon\Carbon $created_at
+ * @property \Carbon\Carbon $updated_at
+ */
+class InhabitantClassification extends Model
+{
+    use HasFactory;
+
+    protected $table = 'inhabitant_classifications';
+
+    protected $guarded = ['id'];
+
+    protected $casts = [
+        'created_at' => 'datetime',
+        'updated_at' => 'datetime',
+    ];
+}

+ 30 - 0
app/Models/MaintenanceBaseBracket.php

@@ -0,0 +1,30 @@
+<?php
+
+namespace App\Models;
+
+use Illuminate\Database\Eloquent\Factories\HasFactory;
+use Illuminate\Database\Eloquent\Model;
+
+/**
+ * @property int $id
+ * @property string $description
+ * @property int $start_month
+ * @property int|null $end_month
+ * @property float $percentage
+ * @property \Carbon\Carbon $created_at
+ * @property \Carbon\Carbon $updated_at
+ */
+class MaintenanceBaseBracket extends Model
+{
+    use HasFactory;
+
+    protected $table = 'maintenance_base_brackets';
+
+    protected $guarded = ['id'];
+
+    protected $casts = [
+        'percentage' => 'decimal:4',
+        'created_at' => 'datetime',
+        'updated_at' => 'datetime',
+    ];
+}

+ 30 - 0
app/Models/RoyaltiesBaseBracket.php

@@ -0,0 +1,30 @@
+<?php
+
+namespace App\Models;
+
+use Illuminate\Database\Eloquent\Factories\HasFactory;
+use Illuminate\Database\Eloquent\Model;
+
+/**
+ * @property int $id
+ * @property string $description
+ * @property int $start_month
+ * @property int|null $end_month
+ * @property float $percentage
+ * @property \Carbon\Carbon $created_at
+ * @property \Carbon\Carbon $updated_at
+ */
+class RoyaltiesBaseBracket extends Model
+{
+    use HasFactory;
+
+    protected $table = 'royalties_base_brackets';
+
+    protected $guarded = ['id'];
+
+    protected $casts = [
+        'percentage' => 'decimal:4',
+        'created_at' => 'datetime',
+        'updated_at' => 'datetime',
+    ];
+}

+ 28 - 0
app/Models/Tbr.php

@@ -0,0 +1,28 @@
+<?php
+
+namespace App\Models;
+
+use Illuminate\Database\Eloquent\Factories\HasFactory;
+use Illuminate\Database\Eloquent\Model;
+
+/**
+ * @property int $id
+ * @property int $year
+ * @property float $tbr_value
+ * @property \Carbon\Carbon $created_at
+ * @property \Carbon\Carbon $updated_at
+ */
+class Tbr extends Model
+{
+    use HasFactory;
+
+    protected $table = 'tbrs';
+
+    protected $guarded = ['id'];
+
+    protected $casts = [
+        'tbr_value'  => 'decimal:2',
+        'created_at' => 'datetime',
+        'updated_at' => 'datetime',
+    ];
+}

+ 99 - 0
app/Models/TbrCalculation.php

@@ -0,0 +1,99 @@
+<?php
+
+namespace App\Models;
+
+use Illuminate\Database\Eloquent\Factories\HasFactory;
+use Illuminate\Database\Eloquent\Model;
+use Illuminate\Database\Eloquent\Relations\BelongsTo;
+
+/**
+ * @property int $id
+ * @property int $unit_id
+ * @property float $revenue_value
+ * @property int $contract_month_reference
+ * @property float $tbr_value
+ * @property int $fnm_bracket_id
+ * @property float $fnm_bracket_percentage
+ * @property float $fnm_bracket_value
+ * @property int $maintenance_bracket_id
+ * @property float $maintenance_bracket_percentage
+ * @property float $maintenance_bracket_value
+ * @property int $royalties_bracket_id
+ * @property float $royalties_bracket_percentage
+ * @property float $royalties_bracket_value
+ * @property float $fnm_effective_percentage
+ * @property float $fnm_effective_value
+ * @property float $royalties_effective_percentage
+ * @property float $royalties_effective_value
+ * @property float $maintenance_effective_percentage
+ * @property float $maintenance_effective_value
+ * @property float $bracket_subtotal
+ * @property float $subtotal
+ * @property float $final_value
+ * @property int $user_id
+ * @property string $royalties_applied_criteria
+ * @property bool $receivable_generated
+ * @property \Carbon\Carbon $created_at
+ * @property \Carbon\Carbon $updated_at
+ * @property-read \App\Models\Unit $unit
+ * @property-read \App\Models\FranchiseeFnmBracket $fnmBracket
+ * @property-read \App\Models\FranchiseeMaintenanceBracket $maintenanceBracket
+ * @property-read \App\Models\FranchiseeRoyaltiesBracket $royaltiesBracket
+ * @property-read \App\Models\User $user
+ */
+class TbrCalculation extends Model
+{
+    use HasFactory;
+
+    protected $table = 'tbr_calculations';
+
+    protected $guarded = ['id'];
+
+    protected $casts = [
+        'revenue_value'                  => 'decimal:2',
+        'tbr_value'                      => 'decimal:2',
+        'fnm_bracket_percentage'         => 'decimal:4',
+        'fnm_bracket_value'              => 'decimal:2',
+        'maintenance_bracket_percentage' => 'decimal:4',
+        'maintenance_bracket_value'      => 'decimal:2',
+        'royalties_bracket_percentage'   => 'decimal:4',
+        'royalties_bracket_value'        => 'decimal:2',
+        'fnm_effective_percentage'       => 'decimal:4',
+        'fnm_effective_value'            => 'decimal:2',
+        'royalties_effective_percentage' => 'decimal:4',
+        'royalties_effective_value'      => 'decimal:2',
+        'maintenance_effective_percentage' => 'decimal:4',
+        'maintenance_effective_value'    => 'decimal:2',
+        'bracket_subtotal'               => 'decimal:2',
+        'subtotal'                       => 'decimal:2',
+        'final_value'                    => 'decimal:2',
+        'receivable_generated'           => 'boolean',
+        'created_at'                     => 'datetime',
+        'updated_at'                     => 'datetime',
+    ];
+
+    public function unit(): BelongsTo
+    {
+        return $this->belongsTo(Unit::class, 'unit_id');
+    }
+
+    public function fnmBracket(): BelongsTo
+    {
+        return $this->belongsTo(FranchiseeFnmBracket::class, 'fnm_bracket_id');
+    }
+
+    public function maintenanceBracket(): BelongsTo
+    {
+        return $this->belongsTo(FranchiseeMaintenanceBracket::class, 'maintenance_bracket_id');
+    }
+
+    public function royaltiesBracket(): BelongsTo
+    {
+        return $this->belongsTo(FranchiseeRoyaltiesBracket::class, 'royalties_bracket_id');
+    }
+
+    public function user(): BelongsTo
+    {
+        return $this->belongsTo(User::class, 'user_id');
+    }
+}

+ 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();
+    }
+}

+ 23 - 0
database/migrations/2026_04_23_165627_create_tbrs_table.php

@@ -0,0 +1,23 @@
+<?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('tbrs', function (Blueprint $table) {
+            $table->id();
+            $table->unsignedSmallInteger('year')->unique();
+            $table->decimal('tbr_value', 10, 2);
+            $table->timestamps();
+        });
+    }
+
+    public function down(): void
+    {
+        Schema::dropIfExists('tbrs');
+    }
+};

+ 23 - 0
database/migrations/2026_04_23_165628_create_inhabitant_classifications_table.php

@@ -0,0 +1,23 @@
+<?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('inhabitant_classifications', function (Blueprint $table) {
+            $table->id();
+            $table->string('description', 150);
+            $table->string('acronym', 2)->unique();
+            $table->timestamps();
+        });
+    }
+
+    public function down(): void
+    {
+        Schema::dropIfExists('inhabitant_classifications');
+    }
+};

+ 36 - 0
database/migrations/2026_04_23_165629_create_franchisee_tbrs_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('franchisee_tbrs', function (Blueprint $table) {
+            $table->id();
+            $table->foreignId('franchisee_id')->constrained('franchisees')->onDelete('cascade');
+            $table->foreignId('contract_id')->constrained('franchisee_contracts')->onDelete('cascade');
+            $table->foreignId('inhabitant_classification_id')->constrained('inhabitant_classifications');
+            $table->unsignedSmallInteger('year');
+            $table->decimal('tbr_value', 10, 2);
+            $table->date('start_date');
+            $table->tinyInteger('invoice_due_day');
+            $table->decimal('base_royalties_percentage', 5, 4);
+            $table->decimal('base_fnm_percentage', 5, 4);
+            $table->unsignedBigInteger('franchisee_royalties_bracket_id')->nullable();
+            $table->unsignedBigInteger('franchisee_fnm_bracket_id')->nullable();
+            $table->unsignedBigInteger('franchisee_maintenance_bracket_id')->nullable();
+            $table->timestamps();
+
+            $table->index('franchisee_id');
+            $table->index('contract_id');
+        });
+    }
+
+    public function down(): void
+    {
+        Schema::dropIfExists('franchisee_tbrs');
+    }
+};

+ 25 - 0
database/migrations/2026_04_23_165631_create_royalties_base_brackets_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('royalties_base_brackets', function (Blueprint $table) {
+            $table->id();
+            $table->string('description', 150);
+            $table->unsignedInteger('start_month');
+            $table->unsignedInteger('end_month')->nullable();
+            $table->decimal('percentage', 5, 4);
+            $table->timestamps();
+        });
+    }
+
+    public function down(): void
+    {
+        Schema::dropIfExists('royalties_base_brackets');
+    }
+};

+ 25 - 0
database/migrations/2026_04_23_165632_create_fnm_base_brackets_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('fnm_base_brackets', function (Blueprint $table) {
+            $table->id();
+            $table->string('description', 150);
+            $table->unsignedInteger('start_month');
+            $table->unsignedInteger('end_month')->nullable();
+            $table->decimal('percentage', 5, 4);
+            $table->timestamps();
+        });
+    }
+
+    public function down(): void
+    {
+        Schema::dropIfExists('fnm_base_brackets');
+    }
+};

+ 25 - 0
database/migrations/2026_04_23_165633_create_maintenance_base_brackets_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('maintenance_base_brackets', function (Blueprint $table) {
+            $table->id();
+            $table->string('description', 150);
+            $table->unsignedInteger('start_month');
+            $table->unsignedInteger('end_month')->nullable();
+            $table->decimal('percentage', 5, 4);
+            $table->timestamps();
+        });
+    }
+
+    public function down(): void
+    {
+        Schema::dropIfExists('maintenance_base_brackets');
+    }
+};

+ 28 - 0
database/migrations/2026_04_23_165634_create_franchisee_royalties_brackets_table.php

@@ -0,0 +1,28 @@
+<?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('franchisee_royalties_brackets', function (Blueprint $table) {
+            $table->id();
+            $table->foreignId('franchisee_id')->constrained('franchisees')->onDelete('cascade');
+            $table->string('description', 150);
+            $table->unsignedInteger('start_month');
+            $table->unsignedInteger('end_month')->nullable();
+            $table->decimal('percentage', 5, 4);
+            $table->timestamps();
+
+            $table->index('franchisee_id');
+        });
+    }
+
+    public function down(): void
+    {
+        Schema::dropIfExists('franchisee_royalties_brackets');
+    }
+};

+ 28 - 0
database/migrations/2026_04_23_165635_create_franchisee_fnm_brackets_table.php

@@ -0,0 +1,28 @@
+<?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('franchisee_fnm_brackets', function (Blueprint $table) {
+            $table->id();
+            $table->foreignId('franchisee_id')->constrained('franchisees')->onDelete('cascade');
+            $table->string('description', 150);
+            $table->unsignedInteger('start_month');
+            $table->unsignedInteger('end_month')->nullable();
+            $table->decimal('percentage', 5, 4);
+            $table->timestamps();
+
+            $table->index('franchisee_id');
+        });
+    }
+
+    public function down(): void
+    {
+        Schema::dropIfExists('franchisee_fnm_brackets');
+    }
+};

+ 28 - 0
database/migrations/2026_04_23_165636_create_franchisee_maintenance_brackets_table.php

@@ -0,0 +1,28 @@
+<?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('franchisee_maintenance_brackets', function (Blueprint $table) {
+            $table->id();
+            $table->foreignId('franchisee_id')->constrained('franchisees')->onDelete('cascade');
+            $table->string('description', 150);
+            $table->unsignedInteger('start_month');
+            $table->unsignedInteger('end_month')->nullable();
+            $table->decimal('percentage', 5, 4);
+            $table->timestamps();
+
+            $table->index('franchisee_id');
+        });
+    }
+
+    public function down(): void
+    {
+        Schema::dropIfExists('franchisee_maintenance_brackets');
+    }
+};

+ 58 - 0
database/migrations/2026_04_23_165638_create_tbr_calculations_table.php

@@ -0,0 +1,58 @@
+<?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('tbr_calculations', function (Blueprint $table) {
+            $table->id();
+            $table->foreignId('unit_id')->constrained('units');
+            $table->decimal('revenue_value', 12, 2);
+            $table->unsignedInteger('contract_month_reference');
+            $table->decimal('tbr_value', 10, 2);
+
+            $table->foreignId('fnm_bracket_id')->constrained('franchisee_fnm_brackets');
+            $table->decimal('fnm_bracket_percentage', 5, 4);
+            $table->decimal('fnm_bracket_value', 10, 2);
+
+            $table->foreignId('maintenance_bracket_id')->constrained('franchisee_maintenance_brackets');
+            $table->decimal('maintenance_bracket_percentage', 5, 4);
+            $table->decimal('maintenance_bracket_value', 10, 2);
+
+            $table->foreignId('royalties_bracket_id')->constrained('franchisee_royalties_brackets');
+            $table->decimal('royalties_bracket_percentage', 5, 4);
+            $table->decimal('royalties_bracket_value', 10, 2);
+
+            $table->decimal('fnm_effective_percentage', 5, 4);
+            $table->decimal('fnm_effective_value', 10, 2);
+
+            $table->decimal('royalties_effective_percentage', 5, 4);
+            $table->decimal('royalties_effective_value', 10, 2);
+
+            $table->decimal('maintenance_effective_percentage', 5, 4);
+            $table->decimal('maintenance_effective_value', 10, 2);
+
+            $table->decimal('bracket_subtotal', 10, 2);
+            $table->decimal('subtotal', 10, 2);
+            $table->decimal('final_value', 10, 2);
+
+            $table->foreignId('user_id')->constrained('users');
+            $table->enum('royalties_applied_criteria', ['tbr_fixo', 'percentual_faturamento']);
+            $table->boolean('receivable_generated')->default(false);
+
+            $table->timestamps();
+
+            $table->index('unit_id');
+            $table->index('user_id');
+        });
+    }
+
+    public function down(): void
+    {
+        Schema::dropIfExists('tbr_calculations');
+    }
+};

+ 1 - 0
database/seeders/DatabaseSeeder.php

@@ -16,6 +16,7 @@ public function run(): void
             PermissionSeeder::class,
             UserTypePermissionSeeder::class,
             BrazilCitiesSeeder::class,
+            TbrBaseBracketsSeeder::class,
         ]);
     }
 }

+ 37 - 0
database/seeders/PermissionSeeder.php

@@ -34,6 +34,43 @@ public function run(): void
                     ],
                 ],
             ],
+            [
+                "scope" => "tbr",
+                "description" => "TBR",
+                "bits" => Permission::ALL_PERMS,
+                "children" => [
+                    [
+                        "scope" => "royalties-base-bracket",
+                        "description" => "Faixas de Royalties Base",
+                        "bits" => Permission::ALL_PERMS,
+                        "children" => [],
+                    ],
+                    [
+                        "scope" => "fnm-base-bracket",
+                        "description" => "Faixas de FNM Base",
+                        "bits" => Permission::ALL_PERMS,
+                        "children" => [],
+                    ],
+                    [
+                        "scope" => "maintenance-base-bracket",
+                        "description" => "Faixas de Manutenção Base",
+                        "bits" => Permission::ALL_PERMS,
+                        "children" => [],
+                    ],
+                    [
+                        "scope" => "franchisee-tbr",
+                        "description" => "TBR por Franqueado",
+                        "bits" => Permission::ALL_PERMS,
+                        "children" => [],
+                    ],
+                    [
+                        "scope" => "tbr-calculation",
+                        "description" => "Cálculo de TBR",
+                        "bits" => Permission::VIEW | Permission::ADD,
+                        "children" => [],
+                    ],
+                ],
+            ],
             [
                 "scope" => "config",
                 "description" => "Configurações",

+ 95 - 0
database/seeders/TbrBaseBracketsSeeder.php

@@ -0,0 +1,95 @@
+<?php
+
+namespace Database\Seeders;
+
+use Illuminate\Database\Seeder;
+use Illuminate\Support\Facades\DB;
+
+class TbrBaseBracketsSeeder extends Seeder
+{
+    public function run(): void
+    {
+        $now = now();
+
+        DB::table('royalties_base_brackets')->insert([
+            [
+                'description' => 'Isento',
+                'start_month' => 1,
+                'end_month'   => 3,
+                'percentage'  => 0.0000,
+                'created_at'  => $now,
+                'updated_at'  => $now,
+            ],
+            [
+                'description' => 'Maior entre % fixo TBR ou 8% do faturamento',
+                'start_month' => 4,
+                'end_month'   => 12,
+                'percentage'  => 0.0800,
+                'created_at'  => $now,
+                'updated_at'  => $now,
+            ],
+            [
+                'description' => 'Maior entre % fixo TBR ou 8% do faturamento',
+                'start_month' => 13,
+                'end_month'   => 60,
+                'percentage'  => 0.0800,
+                'created_at'  => $now,
+                'updated_at'  => $now,
+            ],
+        ]);
+
+        DB::table('fnm_base_brackets')->insert([
+            [
+                'description' => 'Isento',
+                'start_month' => 1,
+                'end_month'   => 3,
+                'percentage'  => 0.0000,
+                'created_at'  => $now,
+                'updated_at'  => $now,
+            ],
+            [
+                'description' => 'Maior entre: % fixo TBR ou 2% do faturamento',
+                'start_month' => 4,
+                'end_month'   => 12,
+                'percentage'  => 0.0200,
+                'created_at'  => $now,
+                'updated_at'  => $now,
+            ],
+            [
+                'description' => 'Maior entre: % fixo TBR ou 2% do faturamento',
+                'start_month' => 13,
+                'end_month'   => 60,
+                'percentage'  => 0.0200,
+                'created_at'  => $now,
+                'updated_at'  => $now,
+            ],
+        ]);
+
+        DB::table('maintenance_base_brackets')->insert([
+            [
+                'description' => '30% fixo da TBR',
+                'start_month' => 1,
+                'end_month'   => 3,
+                'percentage'  => 0.3000,
+                'created_at'  => $now,
+                'updated_at'  => $now,
+            ],
+            [
+                'description' => '30% fixo da TBR',
+                'start_month' => 4,
+                'end_month'   => 12,
+                'percentage'  => 0.3000,
+                'created_at'  => $now,
+                'updated_at'  => $now,
+            ],
+            [
+                'description' => '30% fixo da TBR',
+                'start_month' => 13,
+                'end_month'   => 60,
+                'percentage'  => 0.3000,
+                'created_at'  => $now,
+                'updated_at'  => $now,
+            ],
+        ]);
+    }
+}

+ 11 - 5
database/seeders/UserTypePermissionSeeder.php

@@ -25,11 +25,17 @@ public function run(): void
                     break;
                 case UserTypeEnum::USER:
                     $dataToSync = [
-                        ['scope' => 'dashboard',      'bits' => Permission::VIEW],
-                        ['scope' => 'config.user',    'bits' => Permission::VIEW | Permission::EDIT],
-                        ['scope' => 'config.city',    'bits' => Permission::VIEW],
-                        ['scope' => 'config.country', 'bits' => Permission::VIEW],
-                        ['scope' => 'config.state',   'bits' => Permission::VIEW],
+                        ['scope' => 'dashboard',               'bits' => Permission::VIEW],
+                        ['scope' => 'config.user',             'bits' => Permission::VIEW | Permission::EDIT],
+                        ['scope' => 'config.city',             'bits' => Permission::VIEW],
+                        ['scope' => 'config.country',          'bits' => Permission::VIEW],
+                        ['scope' => 'config.state',            'bits' => Permission::VIEW],
+                        ['scope' => 'tbr',                     'bits' => Permission::VIEW],
+                        ['scope' => 'royalties-base-bracket',  'bits' => Permission::VIEW],
+                        ['scope' => 'fnm-base-bracket',        'bits' => Permission::VIEW],
+                        ['scope' => 'maintenance-base-bracket','bits' => Permission::VIEW],
+                        ['scope' => 'franchisee-tbr',          'bits' => Permission::VIEW],
+                        ['scope' => 'tbr-calculation',         'bits' => Permission::VIEW],
                     ];
                     break;
                 case UserTypeEnum::GUEST:

+ 16 - 0
routes/authRoutes/fnm_base_bracket.php

@@ -0,0 +1,16 @@
+<?php
+
+use Illuminate\Support\Facades\Route;
+use App\Http\Controllers\FnmBaseBracketController;
+
+Route::controller(FnmBaseBracketController::class)->prefix('fnm-base-bracket')->group(function () {
+    Route::get('/', 'index')->middleware('permission:fnm-base-bracket,view');
+
+    Route::post('/', 'store')->middleware('permission:fnm-base-bracket,add');
+
+    Route::get('/{id}', 'show')->middleware('permission:fnm-base-bracket,view');
+
+    Route::put('/{id}', 'update')->middleware('permission:fnm-base-bracket,edit');
+
+    Route::delete('/{id}', 'destroy')->middleware('permission:fnm-base-bracket,delete');
+});

+ 16 - 0
routes/authRoutes/franchisee_fnm_bracket.php

@@ -0,0 +1,16 @@
+<?php
+
+use Illuminate\Support\Facades\Route;
+use App\Http\Controllers\FranchiseeFnmBracketController;
+
+Route::controller(FranchiseeFnmBracketController::class)->prefix('franchisee-fnm-bracket')->group(function () {
+    Route::get('/', 'index')->middleware('permission:franchisee-fnm-bracket,view');
+
+    Route::post('/', 'store')->middleware('permission:franchisee-fnm-bracket,add');
+
+    Route::get('/{id}', 'show')->middleware('permission:franchisee-fnm-bracket,view');
+
+    Route::put('/{id}', 'update')->middleware('permission:franchisee-fnm-bracket,edit');
+
+    Route::delete('/{id}', 'destroy')->middleware('permission:franchisee-fnm-bracket,delete');
+});

+ 16 - 0
routes/authRoutes/franchisee_maintenance_bracket.php

@@ -0,0 +1,16 @@
+<?php
+
+use Illuminate\Support\Facades\Route;
+use App\Http\Controllers\FranchiseeMaintenanceBracketController;
+
+Route::controller(FranchiseeMaintenanceBracketController::class)->prefix('franchisee-maintenance-bracket')->group(function () {
+    Route::get('/', 'index')->middleware('permission:franchisee-maintenance-bracket,view');
+
+    Route::post('/', 'store')->middleware('permission:franchisee-maintenance-bracket,add');
+
+    Route::get('/{id}', 'show')->middleware('permission:franchisee-maintenance-bracket,view');
+
+    Route::put('/{id}', 'update')->middleware('permission:franchisee-maintenance-bracket,edit');
+
+    Route::delete('/{id}', 'destroy')->middleware('permission:franchisee-maintenance-bracket,delete');
+});

+ 16 - 0
routes/authRoutes/franchisee_royalties_bracket.php

@@ -0,0 +1,16 @@
+<?php
+
+use Illuminate\Support\Facades\Route;
+use App\Http\Controllers\FranchiseeRoyaltiesBracketController;
+
+Route::controller(FranchiseeRoyaltiesBracketController::class)->prefix('franchisee-royalties-bracket')->group(function () {
+    Route::get('/', 'index')->middleware('permission:franchisee-royalties-bracket,view');
+
+    Route::post('/', 'store')->middleware('permission:franchisee-royalties-bracket,add');
+
+    Route::get('/{id}', 'show')->middleware('permission:franchisee-royalties-bracket,view');
+
+    Route::put('/{id}', 'update')->middleware('permission:franchisee-royalties-bracket,edit');
+
+    Route::delete('/{id}', 'destroy')->middleware('permission:franchisee-royalties-bracket,delete');
+});

+ 16 - 0
routes/authRoutes/franchisee_tbr.php

@@ -0,0 +1,16 @@
+<?php
+
+use Illuminate\Support\Facades\Route;
+use App\Http\Controllers\FranchiseeTbrController;
+
+Route::controller(FranchiseeTbrController::class)->prefix('franchisee-tbr')->group(function () {
+    Route::get('/', 'index')->middleware('permission:franchisee-tbr,view');
+
+    Route::post('/', 'store')->middleware('permission:franchisee-tbr,add');
+
+    Route::get('/{id}', 'show')->middleware('permission:franchisee-tbr,view');
+
+    Route::put('/{id}', 'update')->middleware('permission:franchisee-tbr,edit');
+
+    Route::delete('/{id}', 'destroy')->middleware('permission:franchisee-tbr,delete');
+});

+ 18 - 0
routes/authRoutes/inhabitant_classification.php

@@ -0,0 +1,18 @@
+<?php
+
+use Illuminate\Support\Facades\Route;
+use App\Http\Controllers\InhabitantClassificationController;
+
+Route::controller(InhabitantClassificationController::class)->prefix('inhabitant-classification')->group(function () {
+    Route::get('/all/select', 'selectList');
+
+    Route::get('/', 'index')->middleware('permission:inhabitant-classification,view');
+
+    Route::post('/', 'store')->middleware('permission:inhabitant-classification,add');
+
+    Route::get('/{id}', 'show')->middleware('permission:inhabitant-classification,view');
+
+    Route::put('/{id}', 'update')->middleware('permission:inhabitant-classification,edit');
+
+    Route::delete('/{id}', 'destroy')->middleware('permission:inhabitant-classification,delete');
+});

+ 16 - 0
routes/authRoutes/maintenance_base_bracket.php

@@ -0,0 +1,16 @@
+<?php
+
+use Illuminate\Support\Facades\Route;
+use App\Http\Controllers\MaintenanceBaseBracketController;
+
+Route::controller(MaintenanceBaseBracketController::class)->prefix('maintenance-base-bracket')->group(function () {
+    Route::get('/', 'index')->middleware('permission:maintenance-base-bracket,view');
+
+    Route::post('/', 'store')->middleware('permission:maintenance-base-bracket,add');
+
+    Route::get('/{id}', 'show')->middleware('permission:maintenance-base-bracket,view');
+
+    Route::put('/{id}', 'update')->middleware('permission:maintenance-base-bracket,edit');
+
+    Route::delete('/{id}', 'destroy')->middleware('permission:maintenance-base-bracket,delete');
+});

+ 16 - 0
routes/authRoutes/royalties_base_bracket.php

@@ -0,0 +1,16 @@
+<?php
+
+use Illuminate\Support\Facades\Route;
+use App\Http\Controllers\RoyaltiesBaseBracketController;
+
+Route::controller(RoyaltiesBaseBracketController::class)->prefix('royalties-base-bracket')->group(function () {
+    Route::get('/', 'index')->middleware('permission:royalties-base-bracket,view');
+
+    Route::post('/', 'store')->middleware('permission:royalties-base-bracket,add');
+
+    Route::get('/{id}', 'show')->middleware('permission:royalties-base-bracket,view');
+
+    Route::put('/{id}', 'update')->middleware('permission:royalties-base-bracket,edit');
+
+    Route::delete('/{id}', 'destroy')->middleware('permission:royalties-base-bracket,delete');
+});

+ 16 - 0
routes/authRoutes/tbr.php

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

+ 12 - 0
routes/authRoutes/tbr_calculation.php

@@ -0,0 +1,12 @@
+<?php
+
+use Illuminate\Support\Facades\Route;
+use App\Http\Controllers\TbrCalculationController;
+
+Route::controller(TbrCalculationController::class)->prefix('tbr-calculation')->group(function () {
+    Route::get('/', 'index')->middleware('permission:tbr-calculation,view');
+
+    Route::post('/', 'store')->middleware('permission:tbr-calculation,add');
+
+    Route::get('/{id}', 'show')->middleware('permission:tbr-calculation,view');
+});