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