251 lines
11 KiB
PHP
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']);
|
|
}
|
|
}
|