TbrBillingPreviewServiceTest.php 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. <?php
  2. namespace Tests\Unit\Financeiro;
  3. use App\Models\City;
  4. use App\Models\Country;
  5. use App\Models\FranchiseeContract;
  6. use App\Models\InhabitantClassification;
  7. use App\Models\MunicipalitySize;
  8. use App\Models\State;
  9. use App\Models\Tbr;
  10. use App\Models\Unit;
  11. use App\Models\UnitFinancial;
  12. use App\Services\TbrBillingPreviewService;
  13. use Carbon\Carbon;
  14. use Illuminate\Foundation\Testing\RefreshDatabase;
  15. use Illuminate\Support\Facades\Bus;
  16. use Tests\TestCase;
  17. /**
  18. * A tela de billing preview (GET /tbr-billing-preview) tinha uma segunda
  19. * implementação da regra de royalties/FNM/manutenção, divergente da oficial
  20. * (não comparava com faturamento, ignorava as flags charge_roi/charge_fnm).
  21. * Ela agora delega para TbrCalculationService::previewBatch() — este teste
  22. * garante que a tela mostra os mesmos números e critérios do cálculo oficial.
  23. */
  24. class TbrBillingPreviewServiceTest extends TestCase
  25. {
  26. use RefreshDatabase;
  27. private TbrBillingPreviewService $service;
  28. private Unit $unit;
  29. protected function setUp(): void
  30. {
  31. parent::setUp();
  32. Bus::fake();
  33. Carbon::setTestNow(Carbon::create(2026, 4, 15));
  34. $this->service = app(TbrBillingPreviewService::class);
  35. $country = Country::create(['name' => 'Brasil', 'code' => 'BR']);
  36. $state = State::create(['name' => 'Paraná', 'code' => 'PR', 'country_id' => $country->id]);
  37. $city = City::create(['name' => 'Maringá', 'country_id' => $country->id, 'state_id' => $state->id]);
  38. $this->unit = Unit::create([
  39. 'fantasy_name' => 'Unidade Teste', 'social_reason' => 'Unidade Teste LTDA',
  40. 'cnpj' => '00000000000191', 'street' => 'Rua Teste', 'neighborhood' => 'Centro',
  41. 'postal_code' => '87000000', 'city_id' => $city->id, 'state_id' => $state->id,
  42. 'email' => 'unidade@teste.com', 'name_responsible' => 'Responsável Teste',
  43. ]);
  44. $size = MunicipalitySize::create(['acronym' => 'GP', 'description' => 'De 100 mil a 200 mil habitantes']);
  45. foreach ([[1, 3, 0.0], [4, 12, 0.75], [13, 60, 1.00]] as [$start, $end, $percentage]) {
  46. InhabitantClassification::create([
  47. 'municipality_size_id' => $size->id, 'description' => "Faixa {$start}-{$end}",
  48. 'start' => $start, 'end' => $end, 'tbr_percentage' => $percentage, 'is_renewal' => false,
  49. ]);
  50. }
  51. Tbr::create([
  52. 'year' => 2026, 'tbr_value' => 1000.00,
  53. 'royalties_percentage' => 0.08, 'fnm_percentage' => 0.20, 'maintenance_percentage' => 0.30,
  54. ]);
  55. FranchiseeContract::create([
  56. 'unit_id' => $this->unit->id, 'protocol' => 1, 'name' => 'Contrato de Franquia',
  57. 'description' => 'Contrato de teste', 'start_date' => '2026-01-01', 'end_date' => '2031-01-01',
  58. 'signature_date' => '2026-01-01', 'validity_months' => 60, 'invoice_due_date' => 10,
  59. 'municipality_size_id' => $size->id, 'tbr_fixed_value' => 1000.00,
  60. ]);
  61. }
  62. protected function tearDown(): void
  63. {
  64. Carbon::setTestNow();
  65. parent::tearDown();
  66. }
  67. /**
  68. * Regra: A tela usa exatamente a mesma fórmula do cálculo oficial — fixo (75%
  69. * da faixa GP direto sobre a TBR = R$ 750,00) vence porque não há faturamento
  70. * lançado (nenhuma parcela cadastrada).
  71. */
  72. public function test_usa_a_mesma_regra_do_calculo_oficial(): void
  73. {
  74. $result = $this->service->getAll()->firstWhere('id', $this->unit->id);
  75. $this->assertNotNull($result);
  76. $this->assertEquals(750.0, $result['royalties_value']);
  77. $this->assertSame('Fixo TBR', $result['royalties_rule']);
  78. $this->assertEquals(200.0, $result['fnm_value']);
  79. $this->assertSame('Fixo TBR', $result['fnm_rule']);
  80. $this->assertEquals(300.0, $result['maintenance_value']);
  81. $this->assertEquals(1250.0, $result['total']);
  82. }
  83. /**
  84. * Regra: Respeita a flag charge_roi da unidade — royalties zerado, rótulo
  85. * "Não cobrado", assim como no cálculo oficial.
  86. */
  87. public function test_respeita_a_flag_charge_roi(): void
  88. {
  89. UnitFinancial::create(['unit_id' => $this->unit->id, 'charge_roi' => false, 'charge_fnm' => true]);
  90. $result = $this->service->getAll()->firstWhere('id', $this->unit->id);
  91. $this->assertEquals(0.0, $result['royalties_value']);
  92. $this->assertSame('Não cobrado', $result['royalties_rule']);
  93. }
  94. /**
  95. * Regra: Mês 1-3 aparece como "Isento" em vez de "Fixo TBR".
  96. */
  97. public function test_marca_isento_nos_meses_1_a_3(): void
  98. {
  99. Carbon::setTestNow(Carbon::create(2026, 2, 15)); // mês de contrato 2
  100. $result = $this->service->getAll()->firstWhere('id', $this->unit->id);
  101. $this->assertEquals(0.0, $result['royalties_value']);
  102. $this->assertSame('Isento', $result['royalties_rule']);
  103. $this->assertEquals(0.0, $result['fnm_value']);
  104. $this->assertSame('Isento', $result['fnm_rule']);
  105. $this->assertEquals(300.0, $result['maintenance_value']);
  106. }
  107. }