reconstruction of the project

This commit is contained in:
root
2026-03-08 16:33:24 -04:00
parent 23b7db1107
commit c8de5f7edc
9157 changed files with 77877 additions and 1073823 deletions
@@ -0,0 +1,94 @@
<?php
namespace Tests\Unit\Services\Badges;
use App\Services\Badges\BadgeFormDataService;
use App\Services\Badges\BadgeTextFormatter;
use App\Services\Badges\BadgeUserLookupService;
use Mockery;
use Tests\TestCase;
class BadgeFormDataServiceTest extends TestCase
{
protected function tearDown(): void
{
Mockery::close();
parent::tearDown();
}
public function test_build_formats_users_and_assigns_latest_class_for_teacherish_roles(): void
{
$lookup = Mockery::mock(BadgeUserLookupService::class);
$formatter = new BadgeTextFormatter();
$lookup->shouldReceive('fetchStaffList')
->once()
->with('2025-2026', [10, 20])
->andReturn([
[
'id' => 10,
'firstname' => 'John',
'lastname' => 'Doe',
'roles' => 'teacher_assistant,admin',
],
[
'id' => 20,
'firstname' => 'Sara',
'lastname' => 'Smith',
'roles' => 'staff',
],
]);
$lookup->shouldReceive('getLatestClassForUser')
->once()
->with(10, '2025-2026')
->andReturn([
'class_section_id' => 5,
'class_section_name' => '3-A',
]);
$lookup->shouldReceive('getAvailableSchoolYears')
->once()
->andReturn(['2025-2026', '2024-2025']);
$service = new BadgeFormDataService($lookup, $formatter);
$result = $service->build('2025-2026', [10, 20], 'teacher');
$this->assertSame('2025-2026', $result['selectedYear']);
$this->assertSame([10, 20], $result['selectedUserIds']);
$this->assertSame('teacher', $result['active_role']);
$this->assertCount(2, $result['users']);
$this->assertSame(10, $result['users'][0]['user_id']);
$this->assertSame('Teacher Assistant, Admin', $result['users'][0]['roles']);
$this->assertSame('teacher_assistant', $result['users'][0]['role_name_raw']);
$this->assertSame('Teacher Assistant', $result['users'][0]['role_name']);
$this->assertSame(5, $result['users'][0]['class_section_id']);
$this->assertSame('3-A', $result['users'][0]['class_section_name']);
$this->assertSame(20, $result['users'][1]['user_id']);
$this->assertSame('Staff', $result['users'][1]['roles']);
$this->assertNull($result['users'][1]['class_section_id']);
}
public function test_build_defaults_invalid_active_role_to_teacher(): void
{
$lookup = Mockery::mock(BadgeUserLookupService::class);
$formatter = new BadgeTextFormatter();
$lookup->shouldReceive('fetchStaffList')
->once()
->andReturn([]);
$lookup->shouldReceive('getAvailableSchoolYears')
->once()
->andReturn([]);
$service = new BadgeFormDataService($lookup, $formatter);
$result = $service->build('2025-2026', [], 'invalid-role');
$this->assertSame('teacher', $result['active_role']);
}
}
@@ -0,0 +1,132 @@
<?php
namespace Tests\Unit\Services\Badges;
use App\Services\Badges\BadgePdfService;
use App\Services\Badges\BadgePrintLogService;
use App\Services\Badges\BadgeTextFormatter;
use App\Services\Badges\BadgeUserLookupService;
use Mockery;
use Symfony\Component\HttpFoundation\Response as SymfonyResponse;
use Tests\TestCase;
class BadgePdfServiceTest extends TestCase
{
protected function tearDown(): void
{
Mockery::close();
parent::tearDown();
}
public function test_generate_returns_pdf_response_and_logs_prints(): void
{
$lookup = Mockery::mock(BadgeUserLookupService::class);
$printLog = Mockery::mock(BadgePrintLogService::class);
$formatter = new BadgeTextFormatter();
$lookup->shouldReceive('getUserInfoById')
->once()
->with(10, '2025-2026')
->andReturn([
'user_id' => 10,
'name' => 'John Doe',
'role' => 'Teacher',
'roles' => 'Teacher',
'role_name_raw' => 'teacher',
'roles_raw' => 'teacher',
'class_section_name' => '3-A',
'school_name' => 'Al Rahma Sunday School',
'school_logo' => null,
'isgl_logo' => null,
'school_year' => '2025-2026',
]);
$printLog->shouldReceive('logSafely')
->once()
->with([10], 1, '2025-2026', [], [], 1);
$service = new BadgePdfService($lookup, $printLog, $formatter);
$response = $service->generate(
userIds: [10],
schoolYear: '2025-2026',
rolesMap: [],
classesMap: [],
actorId: 1
);
$this->assertInstanceOf(SymfonyResponse::class, $response);
$this->assertSame('application/pdf', $response->headers->get('Content-Type'));
$this->assertStringContainsString('inline; filename="Staff_Badges.pdf"', $response->headers->get('Content-Disposition'));
$this->assertNotEmpty($response->getContent());
}
public function test_generate_returns_empty_state_pdf_when_no_valid_users_found(): void
{
$lookup = Mockery::mock(BadgeUserLookupService::class);
$printLog = Mockery::mock(BadgePrintLogService::class);
$formatter = new BadgeTextFormatter();
$lookup->shouldReceive('getUserInfoById')
->once()
->with(99, null)
->andReturn(null);
$printLog->shouldReceive('logSafely')
->once()
->with([99], null, null, [], [], 1);
$service = new BadgePdfService($lookup, $printLog, $formatter);
$response = $service->generate(
userIds: [99],
schoolYear: null,
rolesMap: [],
classesMap: [],
actorId: null
);
$this->assertSame('application/pdf', $response->headers->get('Content-Type'));
$this->assertNotEmpty($response->getContent());
}
public function test_generate_deduplicates_same_badge_content(): void
{
$lookup = Mockery::mock(BadgeUserLookupService::class);
$printLog = Mockery::mock(BadgePrintLogService::class);
$formatter = new BadgeTextFormatter();
$userInfo = [
'user_id' => 10,
'name' => 'John Doe',
'role' => 'Teacher',
'roles' => 'Teacher',
'role_name_raw' => 'teacher',
'roles_raw' => 'teacher',
'class_section_name' => '3-A',
'school_name' => 'Al Rahma Sunday School',
'school_logo' => null,
'isgl_logo' => null,
'school_year' => '2025-2026',
];
$lookup->shouldReceive('getUserInfoById')->twice()->andReturn($userInfo);
$printLog->shouldReceive('logSafely')
->once()
->with([10], 7, '2025-2026', [], [], 1);
$service = new BadgePdfService($lookup, $printLog, $formatter);
$response = $service->generate(
userIds: [10, 10],
schoolYear: '2025-2026',
rolesMap: [],
classesMap: [],
actorId: 7
);
$this->assertSame(200, $response->getStatusCode());
$this->assertSame('application/pdf', $response->headers->get('Content-Type'));
}
}
@@ -0,0 +1,94 @@
<?php
namespace Tests\Unit\Services\Badges;
use App\Models\BadgePrintLog;
use App\Services\Badges\BadgePrintLogService;
use App\Services\Badges\BadgeTextFormatter;
use Illuminate\Support\Facades\Log;
use Mockery;
use Tests\TestCase;
class BadgePrintLogServiceTest extends TestCase
{
protected function tearDown(): void
{
Mockery::close();
parent::tearDown();
}
public function test_get_status_normalizes_ids_before_calling_model(): void
{
$model = Mockery::mock(BadgePrintLog::class);
$formatter = new BadgeTextFormatter();
$expected = [
5 => ['count' => 2, 'last_printed_at' => '2026-03-06 10:00:00', 'last_printed_by' => 1],
];
$model->shouldReceive('getStatus')
->once()
->with([5, 7], '2025-2026')
->andReturn($expected);
$service = new BadgePrintLogService($model, $formatter);
$result = $service->getStatus(['5', '7', '5', ''], '2025-2026');
$this->assertSame($expected, $result);
}
public function test_log_normalizes_ids_and_returns_inserted_count(): void
{
$model = Mockery::mock(BadgePrintLog::class);
$formatter = new BadgeTextFormatter();
$model->shouldReceive('logPrints')
->once()
->with(
[10, 20],
99,
'2025-2026',
['10' => 'Teacher'],
['10' => '3-A'],
1
)
->andReturn(2);
$service = new BadgePrintLogService($model, $formatter);
$result = $service->log(
userIds: ['10', '20', '10'],
actorId: 99,
schoolYear: '2025-2026',
rolesMap: ['10' => 'Teacher'],
classesMap: ['10' => '3-A'],
copies: 1
);
$this->assertSame(2, $result);
}
public function test_log_safely_swallows_exceptions_and_logs_error(): void
{
Log::spy();
$model = Mockery::mock(BadgePrintLog::class);
$formatter = new BadgeTextFormatter();
$model->shouldReceive('logPrints')
->once()
->andThrow(new \RuntimeException('table missing'));
$service = new BadgePrintLogService($model, $formatter);
$service->logSafely(
userIds: [1, 2],
actorId: 5,
schoolYear: '2025-2026'
);
Log::shouldHaveReceived('error')->once();
$this->assertTrue(true);
}
}
@@ -0,0 +1,98 @@
<?php
namespace Tests\Unit\Services\Badges;
use App\Services\Badges\BadgeTextFormatter;
use FPDF;
use Tests\TestCase;
class BadgeTextFormatterTest extends TestCase
{
protected BadgeTextFormatter $formatter;
protected function setUp(): void
{
parent::setUp();
$this->formatter = new BadgeTextFormatter();
}
public function test_normalize_ids_filters_and_deduplicates(): void
{
$result = $this->formatter->normalizeIds([
' 5 ',
'',
null,
'7',
5,
'0',
-1,
'12',
]);
$this->assertSame([5, 7, 12], $result);
}
public function test_norm_removes_extra_spaces_and_control_chars(): void
{
$input = " Head \x07 of School ";
$result = $this->formatter->norm($input);
$this->assertSame('Head of School', $result);
}
public function test_format_role_handles_special_words_and_acronyms(): void
{
$this->assertSame('Head of School', $this->formatter->formatRole('HEAD_OF_SCHOOL'));
$this->assertSame('Teacher Assistant', $this->formatter->formatRole('teacher_assistant'));
$this->assertSame('HR Manager', $this->formatter->formatRole('hr manager'));
$this->assertSame('PTA Head', $this->formatter->formatRole('pta head'));
}
public function test_format_roles_csv_formats_each_role(): void
{
$result = $this->formatter->formatRolesCsv('teacher_assistant, head_of_school, hr');
$this->assertSame('Teacher Assistant, Head of School, HR', $result);
}
public function test_format_class_normalizes_known_values(): void
{
$this->assertSame('KG', $this->formatter->formatClass('kindergarten'));
$this->assertSame('KG', $this->formatter->formatClass('kg'));
$this->assertSame('Youth', $this->formatter->formatClass('youth'));
$this->assertSame('3-A', $this->formatter->formatClass('3-A'));
}
public function test_resolve_role_prefers_first_available_candidate(): void
{
$info = [
'role_name' => '',
'roles' => 'teacher_assistant, admin',
'job_title' => 'ignored because roles wins first',
];
$result = $this->formatter->resolveRole($info);
$this->assertSame('teacher_assistant', $result);
}
public function test_to_pdf_returns_string(): void
{
$result = $this->formatter->toPdf('Al Rahma Sunday School');
$this->assertIsString($result);
$this->assertNotSame('', $result);
}
public function test_fit_text_returns_size_within_bounds(): void
{
$pdf = new FPDF();
$pdf->AddPage();
$pdf->SetFont('Arial', '', 12);
$size = $this->formatter->fitText($pdf, 'Very Long Badge Label Text', 11, 7, 50);
$this->assertGreaterThanOrEqual(7, $size);
$this->assertLessThanOrEqual(11, $size);
}
}