53b3fd945a
Database Portability Tests / Integration (mysql) (push) Has been skipped
Database Portability Tests / Integration (postgres) (push) Has been skipped
Database Portability Tests / Integration (sqlite) (push) Has been skipped
Database Portability Tests / Verify no MySQL-specific SQL (push) Successful in 5s
Database Portability Tests / Unit Tests (PlatformHelper) (push) Failing after 43s
Inventory: - General material, stock items, and sales CRUD - Category management with CategoryPicker component - Inventory reports service - Database migrations and mappers Frontend: - Inventory view with tabs (Allgemeinmaterial, Verkaufsmaterial, Verkäufe) - Forms for general material, stock items, and sales - Search bar fix: flexbox wrapper with inline icon replaces broken NcTextField icon slot Tests: - All 1,491 tests pass (zero errors, warnings, deprecations) - BundleImportServiceTest: fixed ZipArchive empty-file deprecation - BundleImportService: null-coalescing for targetFields - PHPUnit test infra: make test target via container CLAUDE.md: - Added Testing section as PR gating criterion
161 lines
6.5 KiB
PHP
161 lines
6.5 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace OCA\Mitgliederverwaltung\Tests\Service;
|
|
|
|
use OCA\Mitgliederverwaltung\Db\GeneralMaterial;
|
|
use OCA\Mitgliederverwaltung\Db\GeneralMaterialMapper;
|
|
use OCA\Mitgliederverwaltung\Db\InventoryCategory;
|
|
use OCA\Mitgliederverwaltung\Db\InventoryCategoryMapper;
|
|
use OCA\Mitgliederverwaltung\Db\InventoryItemCategory;
|
|
use OCA\Mitgliederverwaltung\Db\InventoryItemCategoryMapper;
|
|
use OCA\Mitgliederverwaltung\Db\StockItem;
|
|
use OCA\Mitgliederverwaltung\Db\StockItemMapper;
|
|
use OCA\Mitgliederverwaltung\Service\AuditService;
|
|
use OCA\Mitgliederverwaltung\Service\InventoryService;
|
|
use OCP\AppFramework\Db\DoesNotExistException;
|
|
use PHPUnit\Framework\MockObject\MockObject;
|
|
use PHPUnit\Framework\TestCase;
|
|
use Psr\Log\LoggerInterface;
|
|
|
|
class InventoryServiceTest extends TestCase {
|
|
|
|
private InventoryService $service;
|
|
private InventoryCategoryMapper&MockObject $categoryMapper;
|
|
private InventoryItemCategoryMapper&MockObject $itemCategoryMapper;
|
|
private GeneralMaterialMapper&MockObject $generalMaterialMapper;
|
|
private StockItemMapper&MockObject $stockItemMapper;
|
|
private MockObject $stockVariantMapper;
|
|
private AuditService&MockObject $auditService;
|
|
private LoggerInterface&MockObject $logger;
|
|
|
|
protected function setUp(): void {
|
|
parent::setUp();
|
|
|
|
$this->categoryMapper = $this->createMock(InventoryCategoryMapper::class);
|
|
$this->itemCategoryMapper = $this->createMock(InventoryItemCategoryMapper::class);
|
|
$this->generalMaterialMapper = $this->createMock(GeneralMaterialMapper::class);
|
|
$this->stockItemMapper = $this->createMock(StockItemMapper::class);
|
|
$this->stockVariantMapper = $this->getMockBuilder(\OCA\Mitgliederverwaltung\Db\StockVariantMapper::class)
|
|
->disableOriginalConstructor()
|
|
->onlyMethods(['findByStockItemId', 'findById', 'insert', 'update', 'delete'])
|
|
->getMock();
|
|
$this->auditService = $this->createMock(AuditService::class);
|
|
$this->logger = $this->createMock(LoggerInterface::class);
|
|
|
|
$this->service = new InventoryService(
|
|
$this->categoryMapper,
|
|
$this->itemCategoryMapper,
|
|
$this->generalMaterialMapper,
|
|
$this->stockItemMapper,
|
|
$this->stockVariantMapper,
|
|
$this->auditService,
|
|
$this->logger
|
|
);
|
|
}
|
|
|
|
private function generalMaterialEntity(int $id = 1, string $name = 'Zelt A', ?int $condition = 3): GeneralMaterial {
|
|
$entity = new GeneralMaterial();
|
|
$entity->setId($id);
|
|
$entity->setName($name);
|
|
$entity->setCondition($condition);
|
|
$entity->setNotes(null);
|
|
$entity->setCreatedAt('2026-04-21 00:00:00');
|
|
$entity->setUpdatedAt('2026-04-21 00:00:00');
|
|
return $entity;
|
|
}
|
|
|
|
private function categoryEntity(int $id = 1, string $name = 'Zelte'): InventoryCategory {
|
|
$entity = new InventoryCategory();
|
|
$entity->setId($id);
|
|
$entity->setName($name);
|
|
$entity->setCreatedAt('2026-04-21 00:00:00');
|
|
return $entity;
|
|
}
|
|
|
|
private function itemCategoryEntity(int $itemId = 1, int $categoryId = 1): InventoryItemCategory {
|
|
$entity = new InventoryItemCategory();
|
|
$entity->setItemId($itemId);
|
|
$entity->setCategoryId($categoryId);
|
|
return $entity;
|
|
}
|
|
|
|
public function testCreateGeneralMaterial_auditLogged(): void {
|
|
$gm = $this->generalMaterialEntity(1, 'Zelt A', 4);
|
|
$this->generalMaterialMapper->method('insert')->willReturnCallback(function ($entity) use ($gm) {
|
|
$entity->setId($gm->getId());
|
|
});
|
|
$this->categoryMapper->method('findById')->willReturn($this->categoryEntity(1, 'Zelte'));
|
|
$this->itemCategoryMapper->method('findByItemId')->willReturn([$this->itemCategoryEntity(1, 1)]);
|
|
|
|
$this->auditService->method('logCreate')->willReturnCallback(function(array $data, string $type, int $id) {
|
|
$this->assertSame('Zelt A', $data['name']);
|
|
$this->assertSame(4, $data['condition']);
|
|
$this->assertSame('inventory_general_material', $type);
|
|
$this->assertSame(1, $id);
|
|
});
|
|
|
|
$result = $this->service->createGeneralMaterial([
|
|
'name' => 'Zelt A',
|
|
'condition' => 4,
|
|
'notes' => null,
|
|
'categories' => [1],
|
|
]);
|
|
|
|
$this->assertSame('Zelt A', $result->getName());
|
|
}
|
|
|
|
public function testCreateStockItem_auditLogged(): void {
|
|
$this->stockItemMapper->method('insert')->willReturnCallback(function ($entity) {
|
|
$entity->setId(1);
|
|
$entity->setName('Pfadfinderhemd');
|
|
});
|
|
$this->itemCategoryMapper->method('findByItemId')->willReturn([]);
|
|
|
|
$this->auditService->method('logCreate')->willReturnCallback(function(array $data, string $type, int $id) {
|
|
$this->assertSame('Pfadfinderhemd', $data['name']);
|
|
$this->assertSame('inventory_stock_item', $type);
|
|
$this->assertSame(1, $id);
|
|
});
|
|
|
|
$result = $this->service->createStockItem([
|
|
'name' => 'Pfadfinderhemd',
|
|
'categories' => null,
|
|
]);
|
|
|
|
$this->assertSame('Pfadfinderhemd', $result->getName());
|
|
}
|
|
|
|
public function testDelete_auditLogged(): void {
|
|
$gm = $this->generalMaterialEntity(1, 'Zelt A');
|
|
$this->generalMaterialMapper->method('findById')->willReturn($gm);
|
|
|
|
$this->auditService->method('logDelete')->willReturnCallback(function(string $type, int $id) {
|
|
$this->assertSame('inventory_general_material', $type);
|
|
$this->assertSame(1, $id);
|
|
});
|
|
|
|
$this->service->deleteGeneralMaterial(1);
|
|
|
|
$this->assertTrue(true);
|
|
}
|
|
|
|
public function testConditionAlerts_correctThreshold(): void {
|
|
$this->assertFalse($this->service->needsRepair(3));
|
|
$this->assertFalse($this->service->needsRepair(4));
|
|
$this->assertFalse($this->service->needsRepair(5));
|
|
$this->assertTrue($this->service->needsRepair(2));
|
|
$this->assertTrue($this->service->needsRepair(1));
|
|
$this->assertTrue($this->service->needsRepair(0));
|
|
$this->assertTrue($this->service->needsRepair(null));
|
|
}
|
|
|
|
public function testGetConditionLabel(): void {
|
|
$this->assertSame('Nicht bewertet', $this->service->getConditionLabel(null));
|
|
$this->assertSame('1/5', $this->service->getConditionLabel(1));
|
|
$this->assertSame('3/5', $this->service->getConditionLabel(3));
|
|
$this->assertSame('5/5', $this->service->getConditionLabel(5));
|
|
}
|
|
}
|