saufen/tests/Feature/Service/InventoryServiceTest.php
2025-05-31 21:43:13 +02:00

251 lines
11 KiB
PHP

<?php
declare(strict_types=1);
namespace Tests\Feature\Service;
use Override;
use Tests\TestCase;
use App\Entity\DrinkType;
use App\Entity\InventoryRecord;
use App\Service\InventoryService;
use App\Service\ConfigurationService;
use App\Enum\SystemSettingKey;
use App\Repository\DrinkTypeRepository;
use App\Repository\InventoryRecordRepository;
use DateTimeImmutable;
class InventoryServiceTest extends TestCase
{
private InventoryService $service;
private DrinkTypeRepository $drinkTypeRepository;
private InventoryRecordRepository $inventoryRecordRepository;
private ConfigurationService $configService;
private DrinkType $drinkType;
#[Override]
public function setUp(): void
{
parent::setUp();
$this->setUpDB();
$this->drinkTypeRepository = $this->container->get(DrinkTypeRepository::class);
$this->inventoryRecordRepository = $this->container->get(InventoryRecordRepository::class);
$this->configService = $this->container->get(ConfigurationService::class);
$this->service = $this->container->get(InventoryService::class);
// Create a drink type for testing
$this->drinkType = new DrinkType('Cola', 'Refreshing cola drink', 10);
$this->drinkTypeRepository->save($this->drinkType);
}
public function testGetAllInventoryRecords(): void
{
// Initially the repository should be empty
$this->assertCount(0, $this->service->getAllInventoryRecords());
// Create some inventory records
$record1 = new InventoryRecord($this->drinkType, 5, new DateTimeImmutable('2023-01-01'));
$record2 = new InventoryRecord($this->drinkType, 10, new DateTimeImmutable('2023-01-02'));
$this->inventoryRecordRepository->save($record1);
$this->inventoryRecordRepository->save($record2);
// Now getAllInventoryRecords should return both records
$records = $this->service->getAllInventoryRecords();
$this->assertCount(2, $records);
$this->assertContainsOnlyInstancesOf(InventoryRecord::class, $records);
}
public function testGetInventoryRecordsByDrinkType(): void
{
// Create another drink type
$anotherDrinkType = new DrinkType('Fanta', 'Orange soda', 5);
$this->drinkTypeRepository->save($anotherDrinkType);
// Create inventory records for both drink types
$record1 = new InventoryRecord($this->drinkType, 5, new DateTimeImmutable('2023-01-01'));
$record2 = new InventoryRecord($this->drinkType, 10, new DateTimeImmutable('2023-01-02'));
$record3 = new InventoryRecord($anotherDrinkType, 15, new DateTimeImmutable('2023-01-03'));
$this->inventoryRecordRepository->save($record1);
$this->inventoryRecordRepository->save($record2);
$this->inventoryRecordRepository->save($record3);
// Get records for the first drink type
$records = $this->service->getInventoryRecordsByDrinkType($this->drinkType);
$this->assertCount(2, $records);
$this->assertContainsOnlyInstancesOf(InventoryRecord::class, $records);
// Check that the records are for the correct drink type
foreach ($records as $record) {
$this->assertEquals($this->drinkType->getId(), $record->getDrinkType()->getId());
}
// Get records for the second drink type
$records = $this->service->getInventoryRecordsByDrinkType($anotherDrinkType);
$this->assertCount(1, $records);
$this->assertEquals($anotherDrinkType->getId(), $records[0]->getDrinkType()->getId());
}
public function testGetLatestInventoryRecord(): void
{
// Create inventory records with different timestamps
$record1 = new InventoryRecord($this->drinkType, 5, new DateTimeImmutable('2023-01-01'));
$record2 = new InventoryRecord($this->drinkType, 10, new DateTimeImmutable('2023-01-02'));
$record3 = new InventoryRecord($this->drinkType, 15, new DateTimeImmutable('2023-01-03'));
$this->inventoryRecordRepository->save($record1);
$this->inventoryRecordRepository->save($record2);
$this->inventoryRecordRepository->save($record3);
// Get the latest record
$latestRecord = $this->service->getLatestInventoryRecord($this->drinkType);
$this->assertInstanceOf(InventoryRecord::class, $latestRecord);
$this->assertEquals(15, $latestRecord->getQuantity());
$this->assertEquals('2023-01-03', $latestRecord->getTimestamp()->format('Y-m-d'));
}
public function testGetInventoryRecordsByTimeRange(): void
{
// Create inventory records with different timestamps
$record1 = new InventoryRecord($this->drinkType, 5, new DateTimeImmutable('2023-01-01'));
$record2 = new InventoryRecord($this->drinkType, 10, new DateTimeImmutable('2023-01-02'));
$record3 = new InventoryRecord($this->drinkType, 15, new DateTimeImmutable('2023-01-03'));
$record4 = new InventoryRecord($this->drinkType, 20, new DateTimeImmutable('2023-01-04'));
$record5 = new InventoryRecord($this->drinkType, 25, new DateTimeImmutable('2023-01-05'));
$this->inventoryRecordRepository->save($record1);
$this->inventoryRecordRepository->save($record2);
$this->inventoryRecordRepository->save($record3);
$this->inventoryRecordRepository->save($record4);
$this->inventoryRecordRepository->save($record5);
// Get records in a specific range
$start = new DateTimeImmutable('2023-01-02');
$end = new DateTimeImmutable('2023-01-04');
$records = $this->service->getInventoryRecordsByTimeRange($start, $end);
$this->assertCount(3, $records);
// Check that the records are within the range
foreach ($records as $record) {
$timestamp = $record->getTimestamp();
$this->assertTrue($timestamp >= $start && $timestamp <= $end);
}
}
public function testGetCurrentStockLevel(): void
{
// Initially there should be no stock
$this->assertEquals(0, $this->service->getCurrentStockLevel($this->drinkType));
// Create inventory records with different timestamps
$record1 = new InventoryRecord($this->drinkType, 5, new DateTimeImmutable('2023-01-01'));
$record2 = new InventoryRecord($this->drinkType, 10, new DateTimeImmutable('2023-01-02'));
$record3 = new InventoryRecord($this->drinkType, 15, new DateTimeImmutable('2023-01-03'));
$this->inventoryRecordRepository->save($record1);
$this->inventoryRecordRepository->save($record2);
$this->inventoryRecordRepository->save($record3);
// The current stock level should be from the latest record
$this->assertEquals(15, $this->service->getCurrentStockLevel($this->drinkType));
}
public function testGetStockDifference(): void
{
// Create inventory records
$record = new InventoryRecord($this->drinkType, 15, new DateTimeImmutable('2023-01-01'));
$this->inventoryRecordRepository->save($record);
// The drink type has a desired stock of 10, and a current stock of 15
// So the difference should be 5 (excess)
$this->assertEquals(5, $this->service->getStockDifference($this->drinkType));
// Create a new record with less stock
$record = new InventoryRecord($this->drinkType, 5, new DateTimeImmutable('2023-01-02'));
$this->inventoryRecordRepository->save($record);
// Now the current stock is 5, and the desired stock is 10
// So the difference should be -5 (shortage)
$this->assertEquals(-5, $this->service->getStockDifference($this->drinkType));
}
public function testUpdateStockLevel(): void
{
// Update the stock level with a specific timestamp
$timestamp1 = new DateTimeImmutable('2023-01-01 10:00:00');
$record = $this->service->updateStockLevel($this->drinkType, 15, $timestamp1);
// Check that the record was created correctly
$this->assertInstanceOf(InventoryRecord::class, $record);
$this->assertEquals($this->drinkType->getId(), $record->getDrinkType()->getId());
$this->assertEquals(15, $record->getQuantity());
$this->assertEquals($timestamp1, $record->getTimestamp());
// Check that the current stock level is updated
$this->assertEquals(15, $this->service->getCurrentStockLevel($this->drinkType));
// Update the stock level again with a later timestamp
$timestamp2 = new DateTimeImmutable('2023-01-02 10:00:00');
$record = $this->service->updateStockLevel($this->drinkType, 20, $timestamp2);
// Check that the record was created correctly
$this->assertEquals(20, $record->getQuantity());
$this->assertEquals($timestamp2, $record->getTimestamp());
// Check that the current stock level is updated to the latest record's quantity
$this->assertEquals(20, $this->service->getCurrentStockLevel($this->drinkType));
}
public function testGetAllDrinkTypesWithStockLevels(): void
{
// Create another drink type
$anotherDrinkType = new DrinkType('Fanta', 'Orange soda', 5);
$this->drinkTypeRepository->save($anotherDrinkType);
// Create inventory records
$record1 = new InventoryRecord($this->drinkType, 15, new DateTimeImmutable('2023-01-01'));
$record2 = new InventoryRecord($anotherDrinkType, 3, new DateTimeImmutable('2023-01-01'));
$this->inventoryRecordRepository->save($record1);
$this->inventoryRecordRepository->save($record2);
// Get all drink types with stock levels
$result = $this->service->getAllDrinkTypesWithStockLevels();
$this->assertCount(2, $result);
// Check the first drink type
$this->assertEquals($this->drinkType->getId(), $result[0]['drinkType']->getId());
$this->assertEquals(15, $result[0]['currentStock']);
$this->assertEquals(10, $result[0]['desiredStock']);
$this->assertEquals(5, $result[0]['difference']);
// Check the second drink type
$this->assertEquals($anotherDrinkType->getId(), $result[1]['drinkType']->getId());
$this->assertEquals(3, $result[1]['currentStock']);
$this->assertEquals(5, $result[1]['desiredStock']);
$this->assertEquals(-2, $result[1]['difference']);
}
public function testGetLowStockDrinkTypes(): void
{
// Set the low stock threshold to 70% so that 3/5 (60%) is considered low stock
$this->configService->setConfigValue(SystemSettingKey::LOW_STOCK_THRESHOLD->value, '70');
// Create another drink type
$anotherDrinkType = new DrinkType('Fanta', 'Orange soda', 5);
$this->drinkTypeRepository->save($anotherDrinkType);
// Create inventory records
$record1 = new InventoryRecord($this->drinkType, 15, new DateTimeImmutable('2023-01-01'));
$record2 = new InventoryRecord($anotherDrinkType, 3, new DateTimeImmutable('2023-01-01'));
$this->inventoryRecordRepository->save($record1);
$this->inventoryRecordRepository->save($record2);
// Get low stock drink types
$result = $this->service->getLowStockDrinkTypes();
// Only the second drink type has low stock
$this->assertCount(1, $result);
$this->assertEquals($anotherDrinkType->getId(), $result[0]['drinkType']->getId());
$this->assertEquals(3, $result[0]['currentStock']);
$this->assertEquals(5, $result[0]['desiredStock']);
$this->assertEquals(2, $result[0]['shortage']);
}
}