| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300 |
- <?php
- namespace Tests\Feature\Financeiro;
- use App\Models\City;
- use App\Models\Country;
- use App\Models\FranchiseeContract;
- use App\Models\InhabitantClassification;
- use App\Models\MunicipalitySize;
- use App\Models\State;
- use App\Models\Tbr;
- use App\Models\Unit;
- use App\Models\User;
- use App\Models\UserType;
- use Illuminate\Foundation\Testing\RefreshDatabase;
- use Illuminate\Support\Facades\Bus;
- use Laravel\Sanctum\Sanctum;
- use Tests\TestCase;
- /**
- * Camada HTTP das rotas de cálculo de contrato (routes/authRoutes/franchisor_tbr.php).
- *
- * O frontend (src/api/tbr_calculation.js) já tem previewTbrCalculation(),
- * createTbrCalculation() e generateReceivable(id) prontos, mas as rotas
- * preview/store/{id}/generate-receivable não existiam — foram registradas
- * agora e são cobertas aqui junto com index/preview-batch/generate-batch.
- */
- class TbrCalculationRoutesTest extends TestCase
- {
- use RefreshDatabase;
- private Unit $unit;
- private MunicipalitySize $size;
- protected function setUp(): void
- {
- parent::setUp();
- Bus::fake();
- $country = Country::create(['name' => 'Brasil', 'code' => 'BR']);
- $state = State::create(['name' => 'Paraná', 'code' => 'PR', 'country_id' => $country->id]);
- $city = City::create(['name' => 'Maringá', 'country_id' => $country->id, 'state_id' => $state->id]);
- $this->unit = Unit::create([
- 'fantasy_name' => 'Unidade Teste',
- 'social_reason' => 'Unidade Teste LTDA',
- 'cnpj' => '00000000000191',
- 'street' => 'Rua Teste',
- 'neighborhood' => 'Centro',
- 'postal_code' => '87000000',
- 'city_id' => $city->id,
- 'state_id' => $state->id,
- 'email' => 'unidade@teste.com',
- 'name_responsible' => 'Responsável Teste',
- ]);
- $this->size = MunicipalitySize::create(['acronym' => 'GP', 'description' => 'De 100 mil a 200 mil habitantes']);
- foreach ([[1, 3, 0.0], [4, 12, 0.75], [13, 60, 1.00]] as [$start, $end, $percentage]) {
- InhabitantClassification::create([
- 'municipality_size_id' => $this->size->id,
- 'description' => "Faixa {$start}-{$end}",
- 'start' => $start,
- 'end' => $end,
- 'tbr_percentage' => $percentage,
- 'is_renewal' => false,
- ]);
- }
- Tbr::create([
- 'year' => 2026, 'tbr_value' => 1000.00,
- 'royalties_percentage' => 0.08, 'fnm_percentage' => 0.20, 'maintenance_percentage' => 0.30,
- ]);
- FranchiseeContract::create([
- 'unit_id' => $this->unit->id,
- 'protocol' => 1,
- 'name' => 'Contrato de Franquia',
- 'description' => 'Contrato de teste',
- 'start_date' => '2026-01-01',
- 'end_date' => '2031-01-01',
- 'signature_date' => '2026-01-01',
- 'validity_months' => 60,
- 'invoice_due_date' => 10,
- 'municipality_size_id' => $this->size->id,
- 'tbr_fixed_value' => 1000.00,
- ]);
- }
- /** Usuário ADMIN autenticado via Sanctum: hasPermission() libera qualquer scope. */
- private function actingAsAdmin(): User
- {
- $userType = UserType::create([
- 'slug' => 'ADMIN_TEST',
- 'label' => 'Admin Teste',
- 'is_system' => true,
- 'access_scope' => 'franchisor',
- 'system_key' => 'ADMIN',
- 'scope_key' => 'franchisor',
- ]);
- $user = User::create([
- 'name' => 'Admin Teste',
- 'email' => 'admin.teste@example.com',
- 'password' => bcrypt('password'),
- 'franchisor_user_type_id' => $userType->id,
- ]);
- Sanctum::actingAs($user, ['access']);
- return $user;
- }
- public function test_rotas_de_calculo_exigem_autenticacao(): void
- {
- $this->getJson('/api/tbr-calculation')->assertStatus(401);
- $this->postJson('/api/tbr-calculation/preview-batch', [])->assertStatus(401);
- $this->postJson('/api/tbr-calculation/generate-batch', [])->assertStatus(401);
- }
- public function test_index_lista_calculos_ja_gravados(): void
- {
- $this->actingAsAdmin();
- $this->postJson('/api/tbr-calculation/generate-batch', [
- 'reference_year' => 2026, 'reference_month' => 4,
- ])->assertStatus(201);
- $response = $this->getJson('/api/tbr-calculation');
- $response->assertOk();
- $this->assertCount(1, $response->json('payload'));
- }
- public function test_preview_batch_retorna_calculo_por_unidade_sem_gravar_nada(): void
- {
- $this->actingAsAdmin();
- $response = $this->postJson('/api/tbr-calculation/preview-batch', [
- 'reference_year' => 2026, 'reference_month' => 4,
- ]);
- $response->assertOk();
- $payload = $response->json('payload');
- $this->assertCount(1, $payload);
- $this->assertSame($this->unit->id, $payload[0]['unit_id']);
- $this->assertEquals(750.0, $payload[0]['royalties_effective_value']);
- $this->assertEquals(300.0, $payload[0]['maintenance_effective_value']);
- $this->assertDatabaseCount('tbr_calculations', 0);
- }
- public function test_preview_batch_valida_ano_e_mes_obrigatorios(): void
- {
- $this->actingAsAdmin();
- $this->postJson('/api/tbr-calculation/preview-batch', [])
- ->assertStatus(422)
- ->assertJsonValidationErrors(['reference_year', 'reference_month']);
- }
- public function test_generate_batch_gera_titulo_e_marca_calculo_como_gerado(): void
- {
- $this->actingAsAdmin();
- $response = $this->postJson('/api/tbr-calculation/generate-batch', [
- 'reference_year' => 2026, 'reference_month' => 4,
- ]);
- $response->assertStatus(201);
- $this->assertSame(1, $response->json('payload.generated_count'));
- $this->assertDatabaseHas('tbr_calculations', [
- 'unit_id' => $this->unit->id,
- 'contract_month_reference' => 4,
- 'receivable_generated' => true,
- ]);
- $this->assertDatabaseHas('franchisee_account_receives', [
- 'unit_id' => $this->unit->id,
- ]);
- Bus::assertDispatched(\App\Jobs\SyncFranchiseeChargeJob::class);
- }
- public function test_generate_batch_pula_unidade_que_ja_tem_titulo_no_mes(): void
- {
- $this->actingAsAdmin();
- $this->postJson('/api/tbr-calculation/generate-batch', [
- 'reference_year' => 2026, 'reference_month' => 4,
- ])->assertStatus(201);
- $response = $this->postJson('/api/tbr-calculation/generate-batch', [
- 'reference_year' => 2026, 'reference_month' => 4,
- ]);
- $response->assertStatus(201);
- $this->assertSame(0, $response->json('payload.generated_count'));
- $this->assertSame(1, $response->json('payload.skipped_count'));
- }
- public function test_preview_calcula_uma_unidade_sem_gravar_nada(): void
- {
- $this->actingAsAdmin();
- $response = $this->postJson('/api/tbr-calculation/preview', [
- 'unit_id' => $this->unit->id, 'reference_year' => 2026, 'reference_month' => 4,
- ]);
- $response->assertOk();
- $this->assertEquals(750.0, $response->json('payload.royalties_effective_value'));
- $this->assertDatabaseCount('tbr_calculations', 0);
- }
- public function test_store_grava_o_calculo_de_uma_unidade(): void
- {
- $this->actingAsAdmin();
- $response = $this->postJson('/api/tbr-calculation', [
- 'unit_id' => $this->unit->id, 'reference_year' => 2026, 'reference_month' => 4,
- ]);
- $response->assertStatus(201);
- $this->assertDatabaseHas('tbr_calculations', [
- 'unit_id' => $this->unit->id,
- 'contract_month_reference' => 4,
- 'receivable_generated' => false,
- ]);
- }
- public function test_show_retorna_um_calculo_gravado(): void
- {
- $this->actingAsAdmin();
- $id = $this->postJson('/api/tbr-calculation', [
- 'unit_id' => $this->unit->id, 'reference_year' => 2026, 'reference_month' => 4,
- ])->json('payload.id');
- $response = $this->getJson("/api/tbr-calculation/{$id}");
- $response->assertOk();
- $this->assertSame($id, $response->json('payload.id'));
- }
- public function test_generate_receivable_gera_titulo_para_um_calculo_especifico(): void
- {
- $this->actingAsAdmin();
- $id = $this->postJson('/api/tbr-calculation', [
- 'unit_id' => $this->unit->id, 'reference_year' => 2026, 'reference_month' => 4,
- ])->json('payload.id');
- $response = $this->postJson("/api/tbr-calculation/{$id}/generate-receivable");
- $response->assertStatus(201);
- $this->assertDatabaseHas('tbr_calculations', ['id' => $id, 'receivable_generated' => true]);
- $this->assertDatabaseHas('franchisee_account_receives', ['unit_id' => $this->unit->id]);
- Bus::assertDispatched(\App\Jobs\SyncFranchiseeChargeJob::class);
- }
- public function test_generate_receivable_bloqueia_segunda_geracao_para_o_mesmo_calculo(): void
- {
- $this->actingAsAdmin();
- $id = $this->postJson('/api/tbr-calculation', [
- 'unit_id' => $this->unit->id, 'reference_year' => 2026, 'reference_month' => 4,
- ])->json('payload.id');
- $this->postJson("/api/tbr-calculation/{$id}/generate-receivable")->assertStatus(201);
- $this->postJson("/api/tbr-calculation/{$id}/generate-receivable")
- ->assertStatus(422)
- ->assertJsonValidationErrors(['tbr_calculation_id']);
- }
- public function test_generate_batch_pode_ser_filtrado_por_unit_ids(): void
- {
- $this->actingAsAdmin();
- $outraUnidade = Unit::create([
- 'fantasy_name' => 'Outra Unidade', 'social_reason' => 'Outra Unidade LTDA',
- 'cnpj' => '00000000000272', 'street' => 'Rua Teste', 'neighborhood' => 'Centro',
- 'postal_code' => '87000000', 'city_id' => $this->unit->city_id, 'state_id' => $this->unit->state_id,
- 'email' => 'outra@teste.com', 'name_responsible' => 'Responsável Teste',
- ]);
- $response = $this->postJson('/api/tbr-calculation/generate-batch', [
- 'reference_year' => 2026, 'reference_month' => 4, 'unit_ids' => [$outraUnidade->id],
- ]);
- // Outra Unidade não tem contrato cadastrado: filtro por ela não gera nada.
- $response->assertStatus(201);
- $this->assertSame(0, $response->json('payload.generated_count'));
- }
- }
|