feat: Add functionality to move inventory items to pantry and enhance pantry management
Test Suite / test (24.15.0) (push) Has been cancelled

- Implemented moveInventoryItemToPantry method in InventoryRepository to facilitate moving items from inventory to pantry.
- Enhanced InventoryScreen with a new header section providing context about the inventory.
- Added a button in SwipeableInventoryTile to move items to pantry with appropriate error handling.
- Introduced movePantryItemToInventory method in PantryRepository to support moving items back to inventory.
- Refactored PantryScreen to rename _addToInventory to _moveToInventory for clarity and updated UI to reflect changes.
- Added AdminPantryItem model to represent pantry items in the admin panel.
- Created AdminPantryPanel for managing pantry items, including moving items to inventory and listing users.
- Developed AdminPrivateProductsPanel for managing private products, allowing promotion to global products.
This commit is contained in:
Nils-Johan Gynther
2026-05-11 09:06:30 +02:00
parent edf9c74e75
commit 84ccabe2fe
27 changed files with 1851 additions and 376 deletions
+34 -1
View File
@@ -1,4 +1,5 @@
import {
BadRequestException,
Body,
Controller,
Delete,
@@ -25,15 +26,33 @@ export class InventoryController {
@Roles('admin')
@Get('admin')
findAllAdmin(
@Query('userId', new ParseIntPipe({ optional: true })) userId?: number,
@Query('userId') userIdRaw?: string,
@Query('sort') sort?: string,
) {
const userId = this.parseOptionalIntQuery(userIdRaw);
return this.inventoryService.findAllAdmin({
userId,
sort,
});
}
private parseOptionalIntQuery(value: string | undefined): number | undefined {
if (value === undefined || value === null) {
return undefined;
}
const trimmed = value.trim();
if (trimmed.length === 0) {
return undefined;
}
if (!/^\d+$/.test(trimmed)) {
throw new BadRequestException('Validation failed (numeric string is expected)');
}
return Number(trimmed);
}
@Roles('admin')
@Post('admin')
createAdmin(
@@ -134,4 +153,18 @@ findConsumptionHistory(
) {
return this.inventoryService.remove(id, user.userId);
}
@Post(':id/move-to-pantry')
moveToPantry(
@CurrentUser() user: { userId: number },
@Param('id', ParseIntPipe) id: number,
) {
return this.inventoryService.moveToPantry(id, user.userId);
}
@Roles('admin')
@Post('admin/:id/move-to-pantry')
moveToPantryAdmin(@Param('id', ParseIntPipe) id: number) {
return this.inventoryService.moveToPantryAdmin(id);
}
}
@@ -348,6 +348,51 @@ export class InventoryService {
return this.prisma.inventoryItem.delete({ where: { id } });
}
private async moveInventoryItemToPantryCore(item: {
id: number;
userId: number;
productId: number;
location: string | null;
}) {
const existingPantryItem = await this.prisma.pantryItem.findUnique({
where: {
userId_productId: {
userId: item.userId,
productId: item.productId,
},
},
});
if (existingPantryItem) {
throw new BadRequestException('Produkten finns redan i baslagret');
}
return this.prisma.$transaction(async (tx) => {
const pantryItem = await tx.pantryItem.create({
data: {
userId: item.userId,
productId: item.productId,
location: item.location?.trim() || null,
},
include: { product: true },
});
await tx.inventoryItem.delete({ where: { id: item.id } });
return pantryItem;
});
}
async moveToPantry(id: number, userId: number) {
const item = await this.findInventoryItemByIdOrThrow(id, userId);
return this.moveInventoryItemToPantryCore(item);
}
async moveToPantryAdmin(id: number) {
const item = await this.findInventoryItemAnyByIdOrThrow(id);
return this.moveInventoryItemToPantryCore(item);
}
async updateAdmin(id: number, data: UpdateInventoryDto) {
await this.findInventoryItemAnyByIdOrThrow(id);