add inventory and supply logic

This commit is contained in:
root
2026-03-10 18:21:08 -04:00
parent 17d73e2f92
commit 25e7b3c67c
62 changed files with 3846 additions and 2781 deletions
@@ -0,0 +1,41 @@
<?php
namespace Tests\Unit\Services\Inventory;
use App\Services\Inventory\InventoryCategoryService;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\DB;
use Tests\TestCase;
class InventoryCategoryServiceTest extends TestCase
{
use RefreshDatabase;
public function test_create_category(): void
{
$service = new InventoryCategoryService();
$result = $service->create([
'type' => 'office',
'name' => 'Supplies',
]);
$this->assertTrue($result['ok']);
$this->assertDatabaseHas('inventory_categories', ['name' => 'Supplies']);
}
public function test_update_category(): void
{
$categoryId = DB::table('inventory_categories')->insertGetId([
'type' => 'office',
'name' => 'Office',
'created_at' => now(),
'updated_at' => now(),
]);
$service = new InventoryCategoryService();
$result = $service->update($categoryId, ['name' => 'Updated']);
$this->assertTrue($result['ok']);
$this->assertDatabaseHas('inventory_categories', ['id' => $categoryId, 'name' => 'Updated']);
}
}
@@ -0,0 +1,78 @@
<?php
namespace Tests\Unit\Services\Inventory;
use App\Services\Inventory\InventoryContextService;
use App\Services\Inventory\InventoryItemService;
use App\Services\Inventory\InventoryMovementService;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\DB;
use Tests\TestCase;
class InventoryItemServiceTest extends TestCase
{
use RefreshDatabase;
public function test_create_creates_item_and_movement(): void
{
$this->seedConfig();
$categoryId = $this->seedCategory();
$service = new InventoryItemService(new InventoryContextService(), new InventoryMovementService(new InventoryContextService()));
$result = $service->create([
'type' => 'classroom',
'category_id' => $categoryId,
'name' => 'Markers',
'quantity' => 2,
]);
$this->assertTrue($result['ok']);
$this->assertDatabaseHas('inventory_items', ['name' => 'Markers']);
$this->assertDatabaseHas('inventory_movements', ['movement_type' => 'initial']);
}
public function test_update_updates_item(): void
{
$this->seedConfig();
$categoryId = $this->seedCategory();
$itemId = $this->seedItem($categoryId);
$service = new InventoryItemService(new InventoryContextService(), new InventoryMovementService(new InventoryContextService()));
$result = $service->update($itemId, ['name' => 'Updated'], 1);
$this->assertTrue($result['ok']);
$this->assertDatabaseHas('inventory_items', ['id' => $itemId, 'name' => 'Updated']);
}
private function seedConfig(): void
{
DB::table('configuration')->insert([
['config_key' => 'school_year', 'config_value' => '2025-2026'],
['config_key' => 'semester', 'config_value' => 'Fall'],
]);
}
private function seedCategory(): int
{
return DB::table('inventory_categories')->insertGetId([
'type' => 'classroom',
'name' => 'Classroom',
'created_at' => now(),
'updated_at' => now(),
]);
}
private function seedItem(int $categoryId): int
{
return DB::table('inventory_items')->insertGetId([
'type' => 'classroom',
'category_id' => $categoryId,
'name' => 'Item',
'quantity' => 1,
'semester' => 'Fall',
'school_year' => '2025-2026',
'created_at' => now(),
'updated_at' => now(),
]);
}
}
@@ -0,0 +1,59 @@
<?php
namespace Tests\Unit\Services\Inventory;
use App\Services\Inventory\InventoryContextService;
use App\Services\Inventory\InventoryMovementService;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\DB;
use Tests\TestCase;
class InventoryMovementServiceTest extends TestCase
{
use RefreshDatabase;
public function test_create_movement(): void
{
$this->seedConfig();
$itemId = $this->seedItem();
$service = new InventoryMovementService(new InventoryContextService());
$result = $service->create([
'item_id' => $itemId,
'qty_change' => 2,
'movement_type' => 'in',
], 1);
$this->assertTrue($result['ok']);
$this->assertDatabaseHas('inventory_movements', ['item_id' => $itemId]);
}
private function seedConfig(): void
{
DB::table('configuration')->insert([
['config_key' => 'school_year', 'config_value' => '2025-2026'],
['config_key' => 'semester', 'config_value' => 'Fall'],
]);
}
private function seedItem(): int
{
$categoryId = DB::table('inventory_categories')->insertGetId([
'type' => 'office',
'name' => 'Office',
'created_at' => now(),
'updated_at' => now(),
]);
return DB::table('inventory_items')->insertGetId([
'type' => 'office',
'category_id' => $categoryId,
'name' => 'Printer',
'quantity' => 10,
'semester' => 'Fall',
'school_year' => '2025-2026',
'created_at' => now(),
'updated_at' => now(),
]);
}
}
@@ -0,0 +1,54 @@
<?php
namespace Tests\Unit\Services\Inventory;
use App\Services\Inventory\InventoryContextService;
use App\Services\Inventory\InventorySummaryService;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\DB;
use Tests\TestCase;
class InventorySummaryServiceTest extends TestCase
{
use RefreshDatabase;
public function test_summary_returns_items(): void
{
$this->seedConfig();
$this->seedItem();
$service = new InventorySummaryService(new InventoryContextService());
$result = $service->summary('classroom', '2025-2026');
$this->assertNotEmpty($result['items']);
}
private function seedConfig(): void
{
DB::table('configuration')->insert([
['config_key' => 'school_year', 'config_value' => '2025-2026'],
['config_key' => 'semester', 'config_value' => 'Fall'],
]);
}
private function seedItem(): void
{
$categoryId = DB::table('inventory_categories')->insertGetId([
'type' => 'classroom',
'name' => 'Classroom',
'created_at' => now(),
'updated_at' => now(),
]);
DB::table('inventory_items')->insert([
'type' => 'classroom',
'category_id' => $categoryId,
'name' => 'Item',
'quantity' => 2,
'semester' => 'Fall',
'school_year' => '2025-2026',
'created_at' => now(),
'updated_at' => now(),
]);
}
}
@@ -0,0 +1,193 @@
<?php
namespace Tests\Unit\Services\Inventory;
use App\Services\Inventory\InventoryContextService;
use App\Services\Inventory\InventoryMovementService;
use App\Services\Inventory\InventoryTeacherDistributionService;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\DB;
use Tests\TestCase;
class InventoryTeacherDistributionServiceTest extends TestCase
{
use RefreshDatabase;
public function test_form_data_requires_teacher_role(): void
{
$this->seedConfig();
$userId = $this->seedUser();
$service = new InventoryTeacherDistributionService(
new InventoryContextService(),
new InventoryMovementService(new InventoryContextService())
);
$result = $service->formData($userId, null, null);
$this->assertFalse($result['ok']);
}
public function test_distribute_success(): void
{
$this->seedConfig();
$userId = $this->seedUser();
$this->seedTeacherRole($userId);
$classSectionId = $this->seedClassSection();
$this->seedTeacherClass($userId, $classSectionId);
$studentId = $this->seedStudent(100, $userId);
$this->seedStudentClass($studentId, $classSectionId);
$categoryId = $this->seedCategory();
$bookId = $this->seedItem($categoryId);
$service = new InventoryTeacherDistributionService(
new InventoryContextService(),
new InventoryMovementService(new InventoryContextService())
);
$result = $service->distribute($userId, [
'item_id' => $bookId,
'class_section_id' => $classSectionId,
'student_ids' => [$studentId],
]);
$this->assertTrue($result['ok']);
$this->assertDatabaseHas('inventory_movements', ['item_id' => $bookId, 'movement_type' => 'distribution']);
}
private function seedConfig(): void
{
DB::table('configuration')->insert([
['config_key' => 'school_year', 'config_value' => '2025-2026'],
['config_key' => 'semester', 'config_value' => 'Fall'],
]);
}
private function seedUser(): int
{
return DB::table('users')->insertGetId([
'firstname' => 'Teacher',
'lastname' => 'User',
'cellphone' => '9999999999',
'email' => 'teacher@example.com',
'address_street' => '123 Street',
'city' => 'City',
'state' => 'ST',
'zip' => '12345',
'accept_school_policy' => 1,
'password' => bcrypt('password'),
'user_type' => 'primary',
'semester' => 'Fall',
'school_year' => '2025-2026',
'status' => 'Active',
]);
}
private function seedTeacherRole(int $userId): void
{
$roleId = DB::table('roles')->insertGetId([
'name' => 'teacher',
'dashboard_route' => 'teacher',
'priority' => 1,
'is_active' => 1,
]);
DB::table('user_roles')->insert([
'user_id' => $userId,
'role_id' => $roleId,
'created_at' => now(),
'updated_at' => now(),
]);
}
private function seedClassSection(): int
{
DB::table('classes')->insert([
'id' => 1,
'class_name' => 'Grade 1',
'created_at' => now(),
'updated_at' => now(),
]);
DB::table('classSection')->insert([
'class_section_id' => 200,
'class_section_name' => 'Grade 1',
'class_id' => 1,
'semester' => 'Fall',
'school_year' => '2025-2026',
'created_at' => now(),
'updated_at' => now(),
]);
return 200;
}
private function seedTeacherClass(int $userId, int $classSectionId): void
{
DB::table('teacher_class')->insert([
'teacher_id' => $userId,
'class_section_id' => $classSectionId,
'position' => 'main',
'school_year' => '2025-2026',
'created_at' => now(),
'updated_at' => now(),
]);
}
private function seedStudent(int $id, int $parentId): int
{
DB::table('students')->insert([
'id' => $id,
'school_id' => 'SCH1',
'firstname' => 'Student',
'lastname' => 'One',
'age' => 10,
'gender' => 'Male',
'photo_consent' => 1,
'parent_id' => $parentId,
'year_of_registration' => '2025-2026',
'semester' => 'Fall',
'school_year' => '2025-2026',
'is_active' => 1,
]);
return $id;
}
private function seedStudentClass(int $studentId, int $classSectionId): void
{
DB::table('student_class')->insert([
'student_id' => $studentId,
'class_section_id' => $classSectionId,
'school_year' => '2025-2026',
'semester' => 'Fall',
'is_event_only' => 0,
'created_at' => now(),
'updated_at' => now(),
]);
}
private function seedCategory(): int
{
return DB::table('inventory_categories')->insertGetId([
'type' => 'book',
'name' => 'Books',
'created_at' => now(),
'updated_at' => now(),
]);
}
private function seedItem(int $categoryId): int
{
return DB::table('inventory_items')->insertGetId([
'type' => 'book',
'category_id' => $categoryId,
'name' => 'Book',
'quantity' => 2,
'semester' => 'Fall',
'school_year' => '2025-2026',
'created_at' => now(),
'updated_at' => now(),
]);
}
}
@@ -0,0 +1,40 @@
<?php
namespace Tests\Unit\Services\Inventory;
use App\Services\Inventory\SupplierService;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\DB;
use Tests\TestCase;
class SupplierServiceTest extends TestCase
{
use RefreshDatabase;
public function test_create_supplier(): void
{
$service = new SupplierService();
$result = $service->create([
'name' => 'Supplier A',
'email' => 'a@example.com',
]);
$this->assertTrue($result['ok']);
$this->assertDatabaseHas('suppliers', ['name' => 'Supplier A']);
}
public function test_update_supplier(): void
{
$id = DB::table('suppliers')->insertGetId([
'name' => 'Supplier B',
'created_at' => now(),
'updated_at' => now(),
]);
$service = new SupplierService();
$result = $service->update($id, ['name' => 'Supplier Updated']);
$this->assertTrue($result['ok']);
$this->assertDatabaseHas('suppliers', ['id' => $id, 'name' => 'Supplier Updated']);
}
}
@@ -0,0 +1,37 @@
<?php
namespace Tests\Unit\Services\Inventory;
use App\Services\Inventory\SupplyCategoryService;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\DB;
use Tests\TestCase;
class SupplyCategoryServiceTest extends TestCase
{
use RefreshDatabase;
public function test_create_category(): void
{
$service = new SupplyCategoryService();
$result = $service->create(['name' => 'Paper']);
$this->assertTrue($result['ok']);
$this->assertDatabaseHas('supply_categories', ['name' => 'Paper']);
}
public function test_update_category(): void
{
$id = DB::table('supply_categories')->insertGetId([
'name' => 'Pens',
'created_at' => now(),
'updated_at' => now(),
]);
$service = new SupplyCategoryService();
$result = $service->update($id, ['name' => 'Pens Updated']);
$this->assertTrue($result['ok']);
$this->assertDatabaseHas('supply_categories', ['id' => $id, 'name' => 'Pens Updated']);
}
}