TbrCalculationRoutesTest.php 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. <?php
  2. namespace Tests\Feature\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\User;
  12. use App\Models\UserType;
  13. use Illuminate\Foundation\Testing\RefreshDatabase;
  14. use Illuminate\Support\Facades\Bus;
  15. use Laravel\Sanctum\Sanctum;
  16. use Tests\TestCase;
  17. /**
  18. * Camada HTTP das rotas de cálculo de contrato (routes/authRoutes/franchisor_tbr.php).
  19. *
  20. * Só GET /tbr-calculation, POST /tbr-calculation/preview-batch e
  21. * POST /tbr-calculation/generate-batch estão registradas hoje — os métodos
  22. * preview/store/show/generateReceivable existem no TbrCalculationController mas
  23. * não têm rota, então ficam fora daqui.
  24. */
  25. class TbrCalculationRoutesTest extends TestCase
  26. {
  27. use RefreshDatabase;
  28. private Unit $unit;
  29. private MunicipalitySize $size;
  30. protected function setUp(): void
  31. {
  32. parent::setUp();
  33. Bus::fake();
  34. $country = Country::create(['name' => 'Brasil', 'code' => 'BR']);
  35. $state = State::create(['name' => 'Paraná', 'code' => 'PR', 'country_id' => $country->id]);
  36. $city = City::create(['name' => 'Maringá', 'country_id' => $country->id, 'state_id' => $state->id]);
  37. $this->unit = Unit::create([
  38. 'fantasy_name' => 'Unidade Teste',
  39. 'social_reason' => 'Unidade Teste LTDA',
  40. 'cnpj' => '00000000000191',
  41. 'street' => 'Rua Teste',
  42. 'neighborhood' => 'Centro',
  43. 'postal_code' => '87000000',
  44. 'city_id' => $city->id,
  45. 'state_id' => $state->id,
  46. 'email' => 'unidade@teste.com',
  47. 'name_responsible' => 'Responsável Teste',
  48. ]);
  49. $this->size = MunicipalitySize::create(['acronym' => 'GP', 'description' => 'De 100 mil a 200 mil habitantes']);
  50. foreach ([[1, 3, 0.0], [4, 12, 0.75], [13, 60, 1.00]] as [$start, $end, $percentage]) {
  51. InhabitantClassification::create([
  52. 'municipality_size_id' => $this->size->id,
  53. 'description' => "Faixa {$start}-{$end}",
  54. 'start' => $start,
  55. 'end' => $end,
  56. 'tbr_percentage' => $percentage,
  57. 'is_renewal' => false,
  58. ]);
  59. }
  60. Tbr::create([
  61. 'year' => 2026, 'tbr_value' => 1000.00,
  62. 'royalties_percentage' => 0.08, 'fnm_percentage' => 0.20, 'maintenance_percentage' => 0.30,
  63. ]);
  64. FranchiseeContract::create([
  65. 'unit_id' => $this->unit->id,
  66. 'protocol' => 1,
  67. 'name' => 'Contrato de Franquia',
  68. 'description' => 'Contrato de teste',
  69. 'start_date' => '2026-01-01',
  70. 'end_date' => '2031-01-01',
  71. 'signature_date' => '2026-01-01',
  72. 'validity_months' => 60,
  73. 'invoice_due_date' => 10,
  74. 'municipality_size_id' => $this->size->id,
  75. 'tbr_fixed_value' => 1000.00,
  76. ]);
  77. }
  78. /** Usuário ADMIN autenticado via Sanctum: hasPermission() libera qualquer scope. */
  79. private function actingAsAdmin(): User
  80. {
  81. $userType = UserType::create([
  82. 'slug' => 'ADMIN_TEST',
  83. 'label' => 'Admin Teste',
  84. 'is_system' => true,
  85. 'access_scope' => 'franchisor',
  86. 'system_key' => 'ADMIN',
  87. 'scope_key' => 'franchisor',
  88. ]);
  89. $user = User::create([
  90. 'name' => 'Admin Teste',
  91. 'email' => 'admin.teste@example.com',
  92. 'password' => bcrypt('password'),
  93. 'franchisor_user_type_id' => $userType->id,
  94. ]);
  95. Sanctum::actingAs($user, ['access']);
  96. return $user;
  97. }
  98. public function test_rotas_de_calculo_exigem_autenticacao(): void
  99. {
  100. $this->getJson('/api/tbr-calculation')->assertStatus(401);
  101. $this->postJson('/api/tbr-calculation/preview-batch', [])->assertStatus(401);
  102. $this->postJson('/api/tbr-calculation/generate-batch', [])->assertStatus(401);
  103. }
  104. public function test_index_lista_calculos_ja_gravados(): void
  105. {
  106. $this->actingAsAdmin();
  107. $this->postJson('/api/tbr-calculation/generate-batch', [
  108. 'reference_year' => 2026, 'reference_month' => 4,
  109. ])->assertStatus(201);
  110. $response = $this->getJson('/api/tbr-calculation');
  111. $response->assertOk();
  112. $this->assertCount(1, $response->json('payload'));
  113. }
  114. public function test_preview_batch_retorna_calculo_por_unidade_sem_gravar_nada(): void
  115. {
  116. $this->actingAsAdmin();
  117. $response = $this->postJson('/api/tbr-calculation/preview-batch', [
  118. 'reference_year' => 2026, 'reference_month' => 4,
  119. ]);
  120. $response->assertOk();
  121. $payload = $response->json('payload');
  122. $this->assertCount(1, $payload);
  123. $this->assertSame($this->unit->id, $payload[0]['unit_id']);
  124. $this->assertEquals(750.0, $payload[0]['royalties_effective_value']);
  125. $this->assertEquals(300.0, $payload[0]['maintenance_effective_value']);
  126. $this->assertDatabaseCount('tbr_calculations', 0);
  127. }
  128. public function test_preview_batch_valida_ano_e_mes_obrigatorios(): void
  129. {
  130. $this->actingAsAdmin();
  131. $this->postJson('/api/tbr-calculation/preview-batch', [])
  132. ->assertStatus(422)
  133. ->assertJsonValidationErrors(['reference_year', 'reference_month']);
  134. }
  135. public function test_generate_batch_gera_titulo_e_marca_calculo_como_gerado(): void
  136. {
  137. $this->actingAsAdmin();
  138. $response = $this->postJson('/api/tbr-calculation/generate-batch', [
  139. 'reference_year' => 2026, 'reference_month' => 4,
  140. ]);
  141. $response->assertStatus(201);
  142. $this->assertSame(1, $response->json('payload.generated_count'));
  143. $this->assertDatabaseHas('tbr_calculations', [
  144. 'unit_id' => $this->unit->id,
  145. 'contract_month_reference' => 4,
  146. 'receivable_generated' => true,
  147. ]);
  148. $this->assertDatabaseHas('franchisee_account_receives', [
  149. 'unit_id' => $this->unit->id,
  150. ]);
  151. Bus::assertDispatched(\App\Jobs\SyncFranchiseeChargeJob::class);
  152. }
  153. public function test_generate_batch_pula_unidade_que_ja_tem_titulo_no_mes(): void
  154. {
  155. $this->actingAsAdmin();
  156. $this->postJson('/api/tbr-calculation/generate-batch', [
  157. 'reference_year' => 2026, 'reference_month' => 4,
  158. ])->assertStatus(201);
  159. $response = $this->postJson('/api/tbr-calculation/generate-batch', [
  160. 'reference_year' => 2026, 'reference_month' => 4,
  161. ]);
  162. $response->assertStatus(201);
  163. $this->assertSame(0, $response->json('payload.generated_count'));
  164. $this->assertSame(1, $response->json('payload.skipped_count'));
  165. }
  166. public function test_generate_batch_pode_ser_filtrado_por_unit_ids(): void
  167. {
  168. $this->actingAsAdmin();
  169. $outraUnidade = Unit::create([
  170. 'fantasy_name' => 'Outra Unidade', 'social_reason' => 'Outra Unidade LTDA',
  171. 'cnpj' => '00000000000272', 'street' => 'Rua Teste', 'neighborhood' => 'Centro',
  172. 'postal_code' => '87000000', 'city_id' => $this->unit->city_id, 'state_id' => $this->unit->state_id,
  173. 'email' => 'outra@teste.com', 'name_responsible' => 'Responsável Teste',
  174. ]);
  175. $response = $this->postJson('/api/tbr-calculation/generate-batch', [
  176. 'reference_year' => 2026, 'reference_month' => 4, 'unit_ids' => [$outraUnidade->id],
  177. ]);
  178. // Outra Unidade não tem contrato cadastrado: filtro por ela não gera nada.
  179. $response->assertStatus(201);
  180. $this->assertSame(0, $response->json('payload.generated_count'));
  181. }
  182. }