| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279 |
- <?php
- namespace Tests\Unit;
- use App\Http\Requests\UnitRequest;
- use App\Http\Resources\UnitResource;
- use App\Models\StudentContract;
- use App\Models\Unit;
- use App\Services\StudentContractService;
- use Illuminate\Http\Request;
- use Illuminate\Support\Facades\Validator as ValidatorFacade;
- use Tests\TestCase;
- class StudentContractProtocolTest extends TestCase
- {
- public function test_it_generates_first_protocol_as_000001_when_no_contracts_exist(): void
- {
- $service = new class extends StudentContractService {
- public function getMaxProtocolNumber(): int
- {
- return 0;
- }
- };
- $this->assertSame('000001', $service->generateNextProtocol());
- }
- public function test_it_generates_sequential_protocol_based_on_max_existing_number(): void
- {
- $service = new class extends StudentContractService {
- public int $max = 0;
- public function getMaxProtocolNumber(): int
- {
- return $this->max;
- }
- };
- $service->max = 1;
- $this->assertSame('000002', $service->generateNextProtocol());
- $service->max = 9;
- $this->assertSame('000010', $service->generateNextProtocol());
- $service->max = 99;
- $this->assertSame('000100', $service->generateNextProtocol());
- $service->max = 999;
- $this->assertSame('001000', $service->generateNextProtocol());
- $service->max = 999999;
- $this->assertSame('1000000', $service->generateNextProtocol());
- }
- public function test_it_respects_global_sequence_across_multiple_units(): void
- {
- // Simulating contracts across multiple units:
- // Unit 1 created contract 000001, Unit 2 created contract 000002, Unit 1 created contract 000003
- $existingContracts = collect([
- (object) ['unit_id' => 1, 'protocol' => '000001'],
- (object) ['unit_id' => 2, 'protocol' => '000002'],
- (object) ['unit_id' => 1, 'protocol' => '000003'],
- ]);
- $service = new class($existingContracts) extends StudentContractService {
- public function __construct(private $contracts) {}
- public function getMaxProtocolNumber(): int
- {
- return $this->contracts
- ->filter(fn ($c) => ctype_digit((string) $c->protocol))
- ->map(fn ($c) => (int) $c->protocol)
- ->max() ?? 0;
- }
- };
- // Next protocol for ANY unit should be 000004
- $this->assertSame('000004', $service->generateNextProtocol());
- }
- public function test_it_ignores_non_numeric_manual_protocols_when_calculating_next_sequence(): void
- {
- $existingContracts = collect([
- (object) ['unit_id' => 1, 'protocol' => '000005'],
- (object) ['unit_id' => 2, 'protocol' => 'CUSTOM-ABC-123'],
- (object) ['unit_id' => 1, 'protocol' => 'CONTRATO-2026'],
- ]);
- $service = new class($existingContracts) extends StudentContractService {
- public function __construct(private $contracts) {}
- public function getMaxProtocolNumber(): int
- {
- return $this->contracts
- ->filter(fn ($c) => ctype_digit((string) $c->protocol))
- ->map(fn ($c) => (int) $c->protocol)
- ->max() ?? 0;
- }
- };
- // Highest numeric is 5, so next sequence is 000006
- $this->assertSame('000006', $service->generateNextProtocol());
- }
- public function test_it_recalculates_protocol_in_automatic_mode_when_creating_contract(): void
- {
- $unit = new Unit;
- $unit->id = 10;
- $unit->automatic_protocol = true;
- $service = new class($unit) extends StudentContractService {
- public array $capturedData = [];
- public function __construct(private Unit $mockUnit) {}
- protected function findUnit(int $unitId): ?Unit
- {
- return $this->mockUnit;
- }
- public function generateNextProtocol(): string
- {
- return '000007';
- }
- public function create(array $data): StudentContract
- {
- if (! empty($data['due_day'])) {
- $data['recurring_day'] = (int) $data['due_day'];
- }
- unset($data['due_day']);
- $unitId = $data['unit_id'] ?? null;
- $isAutomatic = true;
- if ($unitId) {
- $unit = $this->findUnit($unitId);
- if ($unit && $unit->automatic_protocol === false) {
- $isAutomatic = false;
- }
- }
- if ($isAutomatic) {
- $data['protocol'] = $this->generateNextProtocol();
- }
- $this->capturedData = $data;
- $contract = new StudentContract;
- $contract->setRawAttributes($data);
- return $contract;
- }
- };
- // Client sent old/stale protocol '000001'
- $contract = $service->create([
- 'unit_id' => 10,
- 'protocol' => '000001',
- 'status' => 'active',
- ]);
- // Service recalculates to '000007'
- $this->assertSame('000007', $contract->protocol);
- $this->assertSame('000007', $service->capturedData['protocol']);
- }
- public function test_it_preserves_custom_protocol_when_unit_automatic_protocol_is_disabled(): void
- {
- $unit = new Unit;
- $unit->id = 20;
- $unit->automatic_protocol = false;
- $service = new class($unit) extends StudentContractService {
- public array $capturedData = [];
- public function __construct(private Unit $mockUnit) {}
- protected function findUnit(int $unitId): ?Unit
- {
- return $this->mockUnit;
- }
- public function generateNextProtocol(): string
- {
- return '000099';
- }
- public function create(array $data): StudentContract
- {
- if (! empty($data['due_day'])) {
- $data['recurring_day'] = (int) $data['due_day'];
- }
- unset($data['due_day']);
- $unitId = $data['unit_id'] ?? null;
- $isAutomatic = true;
- if ($unitId) {
- $unit = $this->findUnit($unitId);
- if ($unit && $unit->automatic_protocol === false) {
- $isAutomatic = false;
- }
- }
- if ($isAutomatic) {
- $data['protocol'] = $this->generateNextProtocol();
- }
- $this->capturedData = $data;
- $contract = new StudentContract;
- $contract->setRawAttributes($data);
- return $contract;
- }
- };
- // Franchisee with manual mode enters custom protocol
- $contract = $service->create([
- 'unit_id' => 20,
- 'protocol' => 'MANUAL-2026-001',
- 'status' => 'active',
- ]);
- $this->assertSame('MANUAL-2026-001', $contract->protocol);
- $this->assertSame('MANUAL-2026-001', $service->capturedData['protocol']);
- }
- public function test_unit_model_casts_automatic_protocol_to_boolean(): void
- {
- $unit = new Unit;
- $unit->automatic_protocol = 1;
- $this->assertTrue($unit->automatic_protocol);
- $unit->automatic_protocol = 0;
- $this->assertFalse($unit->automatic_protocol);
- $unit->automatic_protocol = 'true';
- $this->assertTrue($unit->automatic_protocol);
- }
- public function test_unit_resource_includes_automatic_protocol(): void
- {
- $unit = new Unit;
- $unit->id = 1;
- $unit->name = 'Unidade Teste';
- $unit->social_reason = 'Unidade Teste LTDA';
- $unit->automatic_protocol = false;
- $unit->created_at = now();
- $unit->updated_at = now();
- $resource = new UnitResource($unit);
- $array = $resource->toArray(Request::create('/'));
- $this->assertArrayHasKey('automatic_protocol', $array);
- $this->assertFalse($array['automatic_protocol']);
- $unit->automatic_protocol = true;
- $resourceTrue = new UnitResource($unit);
- $arrayTrue = $resourceTrue->toArray(Request::create('/'));
- $this->assertTrue($arrayTrue['automatic_protocol']);
- }
- public function test_unit_request_validates_automatic_protocol_as_boolean(): void
- {
- $rules = ['automatic_protocol' => (new UnitRequest)->rules()['automatic_protocol']];
- $validValidator = ValidatorFacade::make(['automatic_protocol' => true], $rules);
- $this->assertFalse($validValidator->errors()->has('automatic_protocol'));
- $validFalseValidator = ValidatorFacade::make(['automatic_protocol' => false], $rules);
- $this->assertFalse($validFalseValidator->errors()->has('automatic_protocol'));
- $invalidValidator = ValidatorFacade::make(['automatic_protocol' => 'not-a-boolean'], $rules);
- $this->assertTrue($invalidValidator->errors()->has('automatic_protocol'));
- }
- }
|