364 lines
13 KiB
PHP
364 lines
13 KiB
PHP
<?php
|
|
|
|
use App\Entity\DrinkType;
|
|
use App\Entity\InventoryRecord;
|
|
use App\Enum\StockState;
|
|
use App\Enum\SystemSettingKey;
|
|
use App\Repository\DrinkTypeRepository;
|
|
use App\Repository\InventoryRecordRepository;
|
|
use App\Service\ConfigurationService;
|
|
use App\Service\InventoryService;
|
|
use App\ValueObject\DrinkStock;
|
|
use Doctrine\ORM\EntityManagerInterface;
|
|
|
|
test('getAllInventoryRecords returns all inventory records', function () {
|
|
// Arrange
|
|
$inventoryService = $this->getContainer()->get(InventoryService::class);
|
|
|
|
// Act
|
|
$records = $inventoryService->getAllInventoryRecords();
|
|
|
|
// Assert
|
|
expect($records)->toBeArray();
|
|
});
|
|
|
|
test('getInventoryRecordsByDrinkType returns records for specific drink type', function () {
|
|
// Arrange
|
|
$inventoryService = $this->getContainer()->get(InventoryService::class);
|
|
$em = $this->getContainer()->get(EntityManagerInterface::class);
|
|
|
|
// Create a drink type
|
|
$drinkType = new DrinkType();
|
|
$drinkType->setName('Test Drink Type for Inventory');
|
|
$drinkType->setDesiredStock(10);
|
|
$em->persist($drinkType);
|
|
$em->flush();
|
|
|
|
// Create inventory records
|
|
$record1 = new InventoryRecord();
|
|
$record1->setDrinkType($drinkType);
|
|
$record1->setQuantity(5);
|
|
$em->persist($record1);
|
|
|
|
$record2 = new InventoryRecord();
|
|
$record2->setDrinkType($drinkType);
|
|
$record2->setQuantity(8);
|
|
$em->persist($record2);
|
|
$em->flush();
|
|
|
|
// Act
|
|
$records = $inventoryService->getInventoryRecordsByDrinkType($drinkType);
|
|
|
|
// Assert
|
|
expect($records)->toBeArray();
|
|
expect(count($records))->toBeGreaterThanOrEqual(2);
|
|
expect($records[0])->toBeInstanceOf(InventoryRecord::class);
|
|
expect($records[0]->getDrinkType()->getId())->toBe($drinkType->getId());
|
|
});
|
|
|
|
test('getLatestInventoryRecord returns latest record for drink type', function () {
|
|
// Arrange
|
|
$inventoryService = $this->getContainer()->get(InventoryService::class);
|
|
$em = $this->getContainer()->get(EntityManagerInterface::class);
|
|
|
|
// Create a drink type
|
|
$drinkType = new DrinkType();
|
|
$drinkType->setName('Test Drink Type for Latest Record');
|
|
$drinkType->setDesiredStock(10);
|
|
$em->persist($drinkType);
|
|
$em->flush();
|
|
|
|
// Create inventory records with different timestamps
|
|
$record1 = new InventoryRecord();
|
|
$record1->setDrinkType($drinkType);
|
|
$record1->setQuantity(5);
|
|
$record1->setTimestamp(new DateTimeImmutable('-2 days'));
|
|
$em->persist($record1);
|
|
|
|
$record2 = new InventoryRecord();
|
|
$record2->setDrinkType($drinkType);
|
|
$record2->setQuantity(8);
|
|
$record2->setTimestamp(new DateTimeImmutable('-1 day'));
|
|
$em->persist($record2);
|
|
|
|
$record3 = new InventoryRecord();
|
|
$record3->setDrinkType($drinkType);
|
|
$record3->setQuantity(12);
|
|
$record3->setTimestamp(new DateTimeImmutable());
|
|
$em->persist($record3);
|
|
$em->flush();
|
|
|
|
// Act
|
|
$latestRecord = $inventoryService->getLatestInventoryRecord($drinkType);
|
|
|
|
// Assert
|
|
expect($latestRecord)->toBeInstanceOf(InventoryRecord::class);
|
|
expect($latestRecord->getDrinkType()->getId())->toBe($drinkType->getId());
|
|
expect($latestRecord->getQuantity())->toBe(12);
|
|
});
|
|
|
|
test('getLatestInventoryRecord creates new record if none exists', function () {
|
|
// Arrange
|
|
$inventoryService = $this->getContainer()->get(InventoryService::class);
|
|
$em = $this->getContainer()->get(EntityManagerInterface::class);
|
|
$repository = $this->getContainer()->get(InventoryRecordRepository::class);
|
|
|
|
// Create a drink type with no inventory records
|
|
$drinkType = new DrinkType();
|
|
$drinkType->setName('Test Drink Type with No Records');
|
|
$drinkType->setDesiredStock(10);
|
|
$em->persist($drinkType);
|
|
$em->flush();
|
|
|
|
// Delete any existing records for this drink type
|
|
foreach ($repository->findByDrinkType($drinkType) as $record) {
|
|
$em->remove($record);
|
|
}
|
|
$em->flush();
|
|
|
|
// Act
|
|
$latestRecord = $inventoryService->getLatestInventoryRecord($drinkType);
|
|
|
|
// Assert
|
|
expect($latestRecord)->toBeInstanceOf(InventoryRecord::class);
|
|
expect($latestRecord->getDrinkType()->getId())->toBe($drinkType->getId());
|
|
expect($latestRecord->getQuantity())->toBe(0);
|
|
});
|
|
|
|
test('getCurrentStockLevel returns correct stock level', function () {
|
|
// Arrange
|
|
$inventoryService = $this->getContainer()->get(InventoryService::class);
|
|
$em = $this->getContainer()->get(EntityManagerInterface::class);
|
|
|
|
// Create a drink type
|
|
$drinkType = new DrinkType();
|
|
$drinkType->setName('Test Drink Type for Stock Level');
|
|
$drinkType->setDesiredStock(10);
|
|
$em->persist($drinkType);
|
|
$em->flush();
|
|
|
|
// Create inventory record
|
|
$record = new InventoryRecord();
|
|
$record->setDrinkType($drinkType);
|
|
$record->setQuantity(15);
|
|
$em->persist($record);
|
|
$em->flush();
|
|
|
|
// Act
|
|
$stockLevel = $inventoryService->getCurrentStockLevel($drinkType);
|
|
|
|
// Assert
|
|
expect($stockLevel)->toBe(15);
|
|
});
|
|
|
|
test('updateStockLevel creates new inventory record', function () {
|
|
// Arrange
|
|
$inventoryService = $this->getContainer()->get(InventoryService::class);
|
|
$em = $this->getContainer()->get(EntityManagerInterface::class);
|
|
|
|
// Create a drink type
|
|
$drinkType = new DrinkType();
|
|
$drinkType->setName('Test Drink Type for Update');
|
|
$drinkType->setDesiredStock(10);
|
|
$em->persist($drinkType);
|
|
$em->flush();
|
|
|
|
$newQuantity = 25;
|
|
$timestamp = new DateTimeImmutable();
|
|
|
|
// Act
|
|
$record = $inventoryService->updateStockLevel($drinkType, $newQuantity, $timestamp);
|
|
|
|
// Assert
|
|
expect($record)->toBeInstanceOf(InventoryRecord::class);
|
|
expect($record->getDrinkType()->getId())->toBe($drinkType->getId());
|
|
expect($record->getQuantity())->toBe($newQuantity);
|
|
expect($record->getTimestamp()->getTimestamp())->toBe($timestamp->getTimestamp());
|
|
|
|
// Verify the stock level was updated
|
|
$currentLevel = $inventoryService->getCurrentStockLevel($drinkType);
|
|
expect($currentLevel)->toBe($newQuantity);
|
|
});
|
|
|
|
test('getAllDrinkTypesWithStockLevels returns all drink types with stock', function () {
|
|
// Arrange
|
|
$inventoryService = $this->getContainer()->get(InventoryService::class);
|
|
$em = $this->getContainer()->get(EntityManagerInterface::class);
|
|
$drinkTypeRepo = $this->getContainer()->get(DrinkTypeRepository::class);
|
|
|
|
// Create drink types and inventory records
|
|
$drinkType1 = new DrinkType();
|
|
$drinkType1->setName('Drink Type 1 for Stock Levels');
|
|
$drinkType1->setDesiredStock(10);
|
|
$em->persist($drinkType1);
|
|
|
|
$drinkType2 = new DrinkType();
|
|
$drinkType2->setName('Drink Type 2 for Stock Levels');
|
|
$drinkType2->setDesiredStock(0); // Zero desired stock
|
|
$em->persist($drinkType2);
|
|
$em->flush();
|
|
|
|
// Create inventory records
|
|
$record1 = new InventoryRecord();
|
|
$record1->setDrinkType($drinkType1);
|
|
$record1->setQuantity(5);
|
|
$em->persist($record1);
|
|
|
|
$record2 = new InventoryRecord();
|
|
$record2->setDrinkType($drinkType2);
|
|
$record2->setQuantity(8);
|
|
$em->persist($record2);
|
|
$em->flush();
|
|
|
|
// Act - without zero desired stock
|
|
$stockLevels1 = $inventoryService->getAllDrinkTypesWithStockLevels(false);
|
|
|
|
// Act - with zero desired stock
|
|
$stockLevels2 = $inventoryService->getAllDrinkTypesWithStockLevels(true);
|
|
|
|
// Assert
|
|
expect($stockLevels1)->toBeArray();
|
|
expect($stockLevels2)->toBeArray();
|
|
expect(count($stockLevels2))->toBeGreaterThanOrEqual(count($stockLevels1));
|
|
|
|
foreach ($stockLevels2 as $stockLevel) {
|
|
expect($stockLevel)->toBeInstanceOf(DrinkStock::class);
|
|
expect($stockLevel->record)->toBeInstanceOf(InventoryRecord::class);
|
|
}
|
|
});
|
|
|
|
test('getDrinkStock returns correct DrinkStock object with CRITICAL state', function () {
|
|
// Arrange
|
|
$inventoryService = $this->getContainer()->get(InventoryService::class);
|
|
$configService = $this->getContainer()->get(ConfigurationService::class);
|
|
$em = $this->getContainer()->get(EntityManagerInterface::class);
|
|
|
|
// Set low stock multiplier
|
|
$configService->setConfigValue(SystemSettingKey::STOCK_LOW_MULTIPLIER, '0.3');
|
|
|
|
// Create a drink type with zero quantity (CRITICAL)
|
|
$drinkType = new DrinkType();
|
|
$drinkType->setName('Critical Stock Drink Type');
|
|
$drinkType->setDesiredStock(10);
|
|
$em->persist($drinkType);
|
|
$em->flush();
|
|
|
|
// Create inventory record with zero quantity
|
|
$record = new InventoryRecord();
|
|
$record->setDrinkType($drinkType);
|
|
$record->setQuantity(0);
|
|
$em->persist($record);
|
|
$em->flush();
|
|
|
|
// Act
|
|
$drinkStock = $inventoryService->getDrinkStock($drinkType);
|
|
|
|
// Assert
|
|
expect($drinkStock)->toBeInstanceOf(DrinkStock::class);
|
|
expect($drinkStock->record->getDrinkType()->getId())->toBe($drinkType->getId());
|
|
expect($drinkStock->stock)->toBe(StockState::CRITICAL);
|
|
});
|
|
|
|
test('getDrinkStock returns correct DrinkStock object with LOW state', function () {
|
|
// Arrange
|
|
$inventoryService = $this->getContainer()->get(InventoryService::class);
|
|
$configService = $this->getContainer()->get(ConfigurationService::class);
|
|
$em = $this->getContainer()->get(EntityManagerInterface::class);
|
|
|
|
// Set low stock multiplier
|
|
$lowStockMultiplier = 0.3;
|
|
$configService->setConfigValue(SystemSettingKey::STOCK_LOW_MULTIPLIER, (string)$lowStockMultiplier);
|
|
|
|
// Create a drink type with low quantity
|
|
$desiredStock = 10;
|
|
$drinkType = new DrinkType();
|
|
$drinkType->setName('Low Stock Drink Type');
|
|
$drinkType->setDesiredStock($desiredStock);
|
|
$em->persist($drinkType);
|
|
$em->flush();
|
|
|
|
// Create inventory record with low quantity (between 0 and lowStockMultiplier * desiredStock)
|
|
$lowQuantity = (int)($desiredStock * $lowStockMultiplier) - 1;
|
|
$record = new InventoryRecord();
|
|
$record->setDrinkType($drinkType);
|
|
$record->setQuantity($lowQuantity);
|
|
$em->persist($record);
|
|
$em->flush();
|
|
|
|
// Act
|
|
$drinkStock = $inventoryService->getDrinkStock($drinkType);
|
|
|
|
// Assert
|
|
expect($drinkStock)->toBeInstanceOf(DrinkStock::class);
|
|
expect($drinkStock->record->getDrinkType()->getId())->toBe($drinkType->getId());
|
|
expect($drinkStock->stock)->toBe(StockState::LOW);
|
|
});
|
|
|
|
test('getDrinkStock returns correct DrinkStock object with NORMAL state', function () {
|
|
// Arrange
|
|
$inventoryService = $this->getContainer()->get(InventoryService::class);
|
|
$configService = $this->getContainer()->get(ConfigurationService::class);
|
|
$em = $this->getContainer()->get(EntityManagerInterface::class);
|
|
|
|
// Set low stock multiplier
|
|
$lowStockMultiplier = 0.3;
|
|
$configService->setConfigValue(SystemSettingKey::STOCK_LOW_MULTIPLIER, (string)$lowStockMultiplier);
|
|
|
|
// Create a drink type with normal quantity
|
|
$desiredStock = 10;
|
|
$drinkType = new DrinkType();
|
|
$drinkType->setName('Normal Stock Drink Type');
|
|
$drinkType->setDesiredStock($desiredStock);
|
|
$em->persist($drinkType);
|
|
$em->flush();
|
|
|
|
// Create inventory record with normal quantity (between lowStockMultiplier * desiredStock and desiredStock)
|
|
$normalQuantity = (int)($desiredStock * $lowStockMultiplier) + 1;
|
|
$record = new InventoryRecord();
|
|
$record->setDrinkType($drinkType);
|
|
$record->setQuantity($normalQuantity);
|
|
$em->persist($record);
|
|
$em->flush();
|
|
|
|
// Act
|
|
$drinkStock = $inventoryService->getDrinkStock($drinkType);
|
|
|
|
// Assert
|
|
expect($drinkStock)->toBeInstanceOf(DrinkStock::class);
|
|
expect($drinkStock->record->getDrinkType()->getId())->toBe($drinkType->getId());
|
|
expect($drinkStock->stock)->toBe(StockState::NORMAL);
|
|
});
|
|
|
|
test('getDrinkStock returns correct DrinkStock object with HIGH state', function () {
|
|
// Arrange
|
|
$inventoryService = $this->getContainer()->get(InventoryService::class);
|
|
$configService = $this->getContainer()->get(ConfigurationService::class);
|
|
$em = $this->getContainer()->get(EntityManagerInterface::class);
|
|
|
|
// Set low stock multiplier
|
|
$configService->setConfigValue(SystemSettingKey::STOCK_LOW_MULTIPLIER, '0.3');
|
|
|
|
// Create a drink type with high quantity
|
|
$desiredStock = 10;
|
|
$drinkType = new DrinkType();
|
|
$drinkType->setName('High Stock Drink Type');
|
|
$drinkType->setDesiredStock($desiredStock);
|
|
$em->persist($drinkType);
|
|
$em->flush();
|
|
|
|
// Create inventory record with high quantity (greater than desiredStock)
|
|
$highQuantity = $desiredStock + 1;
|
|
$record = new InventoryRecord();
|
|
$record->setDrinkType($drinkType);
|
|
$record->setQuantity($highQuantity);
|
|
$em->persist($record);
|
|
$em->flush();
|
|
|
|
// Act
|
|
$drinkStock = $inventoryService->getDrinkStock($drinkType);
|
|
|
|
// Assert
|
|
expect($drinkStock)->toBeInstanceOf(DrinkStock::class);
|
|
expect($drinkStock->record->getDrinkType()->getId())->toBe($drinkType->getId());
|
|
expect($drinkStock->stock)->toBe(StockState::HIGH);
|
|
});
|