start with items
This commit is contained in:
parent
2b420831ac
commit
3d7671f979
@ -4,8 +4,11 @@ import {
|
||||
Controller,
|
||||
Delete,
|
||||
Get,
|
||||
Param,
|
||||
ParseIntPipe,
|
||||
Patch,
|
||||
Post,
|
||||
Query,
|
||||
UseGuards,
|
||||
UseInterceptors,
|
||||
} from '@nestjs/common';
|
||||
@ -13,6 +16,7 @@ import {
|
||||
ApiBody,
|
||||
ApiOkResponse,
|
||||
ApiOperation,
|
||||
ApiParam,
|
||||
ApiSecurity,
|
||||
ApiTags,
|
||||
} from '@nestjs/swagger';
|
||||
@ -30,6 +34,15 @@ import { RoomGuard } from 'src/shared/guards/room.guard';
|
||||
import { StorageSetGuard } from 'src/shared/guards/storage-set.guard';
|
||||
import { StorageGuard } from 'src/shared/guards/storage.guard';
|
||||
import { AppStorageService } from './app-storage.service';
|
||||
import {
|
||||
StorageAddExistingItemRequestDto,
|
||||
StorageAddItemRequestDto,
|
||||
} from './dto/storage-add-item-request.dto';
|
||||
import { StorageItemRequestQueryDto } from './dto/storage-item-request.dto';
|
||||
import {
|
||||
StorageItemSearchResponseDto,
|
||||
StorageStoredItemResponseDto,
|
||||
} from './dto/storage-item-response.dto';
|
||||
import {
|
||||
StorageCreateRequestDto,
|
||||
StorageUpdateRequestDto,
|
||||
@ -51,28 +64,9 @@ import { StorageSetResponseDto } from './dto/storage-set-response.dto';
|
||||
export class AppStorageController {
|
||||
constructor(private readonly service: AppStorageService) {}
|
||||
|
||||
@Get(':storageId')
|
||||
@ApiOperation({ summary: 'Get storage by ID' })
|
||||
@ApiOkResponse({ type: StorageResponseDto })
|
||||
async getStorage(
|
||||
@CurrentStorage() storage: Storage,
|
||||
): Promise<StorageResponseDto> {
|
||||
return this.service.formatStorageNoItems(storage);
|
||||
}
|
||||
|
||||
@Patch(':storageId')
|
||||
@ApiBody({ type: StorageUpdateRequestDto })
|
||||
@ApiOperation({ summary: 'Update storage by ID' })
|
||||
@ApiOkResponse({ type: StorageResponseDto })
|
||||
async updateStorage(
|
||||
@CurrentStorage() storage: Storage,
|
||||
@Body() body: StorageUpdateRequestDto,
|
||||
): Promise<StorageResponseDto> {
|
||||
return this.service.updateStorage(storage, body);
|
||||
}
|
||||
|
||||
@UseGuards(StorageSetGuard)
|
||||
@Get('set/:storageSetId')
|
||||
@ApiParam({ name: 'storageSetId', description: 'Storage set ID' })
|
||||
@ApiOperation({ summary: 'Get storage set' })
|
||||
@ApiOkResponse({ type: StorageSetResponseDto })
|
||||
async getStorageSet(@CurrentStorageSet() set: StorageSet) {
|
||||
@ -81,6 +75,7 @@ export class AppStorageController {
|
||||
|
||||
@UseGuards(StorageSetGuard)
|
||||
@Patch('set/:storageSetId')
|
||||
@ApiParam({ name: 'storageSetId', description: 'Storage set ID' })
|
||||
@ApiBody({ type: StorageSetUpdateRequestDto })
|
||||
@ApiOperation({ summary: 'Update storage set by ID' })
|
||||
@ApiOkResponse({ type: StorageSetResponseDto })
|
||||
@ -93,6 +88,8 @@ export class AppStorageController {
|
||||
|
||||
@UseGuards(StorageSetGuard)
|
||||
@Post('set/:storageSetId/:storageId')
|
||||
@ApiParam({ name: 'storageSetId', description: 'Storage set ID' })
|
||||
@ApiParam({ name: 'storageId', description: 'Storage ID' })
|
||||
@ApiOperation({ summary: 'Move storage to storage set' })
|
||||
@ApiOkResponse({ type: StorageSetResponseDto })
|
||||
async moveStorage(
|
||||
@ -104,6 +101,8 @@ export class AppStorageController {
|
||||
|
||||
@UseGuards(StorageSetGuard)
|
||||
@Delete('set/:storageSetId/:storageId')
|
||||
@ApiParam({ name: 'storageSetId', description: 'Storage set ID' })
|
||||
@ApiParam({ name: 'storageId', description: 'Storage ID' })
|
||||
@ApiOperation({ summary: 'Remove storage from storage set' })
|
||||
@ApiOkResponse({ type: StorageSetResponseDto })
|
||||
async removeStorageFromSet(
|
||||
@ -114,6 +113,7 @@ export class AppStorageController {
|
||||
}
|
||||
|
||||
@Get('room/:roomId')
|
||||
@ApiParam({ name: 'roomId', description: 'Room ID' })
|
||||
@ApiOperation({ summary: 'Get storages in room' })
|
||||
@ApiOkResponse({ type: StorageResponseDto, isArray: true })
|
||||
async getStorages(@CurrentRoom() room: Room) {
|
||||
@ -121,6 +121,7 @@ export class AppStorageController {
|
||||
}
|
||||
|
||||
@Get('set/room/:roomId')
|
||||
@ApiParam({ name: 'roomId', description: 'Room ID' })
|
||||
@ApiOperation({ summary: 'Get storage sets in room' })
|
||||
@ApiOkResponse({ type: StorageSetResponseDto, isArray: true })
|
||||
async getStorageSets(@CurrentRoom() room: Room) {
|
||||
@ -128,6 +129,7 @@ export class AppStorageController {
|
||||
}
|
||||
|
||||
@Post('set/room/:roomId')
|
||||
@ApiParam({ name: 'roomId', description: 'Room ID' })
|
||||
@ApiBody({ type: StorageCreateRequestDto })
|
||||
@ApiOperation({ summary: 'Create storage sets in room' })
|
||||
@ApiOkResponse({ type: StorageSetResponseDto, isArray: true })
|
||||
@ -140,6 +142,7 @@ export class AppStorageController {
|
||||
}
|
||||
|
||||
@Post('room/:roomId')
|
||||
@ApiParam({ name: 'roomId', description: 'Room ID' })
|
||||
@ApiBody({ type: StorageCreateRequestDto })
|
||||
@ApiOperation({ summary: 'Add a new storage to room' })
|
||||
@ApiOkResponse({ type: StorageResponseDto })
|
||||
@ -150,4 +153,64 @@ export class AppStorageController {
|
||||
): Promise<StorageResponseDto> {
|
||||
return this.service.createStorage(user, room, body);
|
||||
}
|
||||
|
||||
@Get('item')
|
||||
@ApiOperation({ summary: 'Search for an item' })
|
||||
@ApiOkResponse({ type: StorageItemSearchResponseDto, isArray: true })
|
||||
async searchForItem(
|
||||
@LoggedInUser() user: User,
|
||||
@Query() search: StorageItemRequestQueryDto,
|
||||
) {
|
||||
return this.service.searchForItems(user, search);
|
||||
}
|
||||
|
||||
@Post('item/:storageId')
|
||||
@ApiParam({ name: 'storageId', description: 'Storage ID' })
|
||||
@ApiBody({ type: StorageAddItemRequestDto })
|
||||
@ApiOperation({ summary: 'Add a new item to storage' })
|
||||
@ApiOkResponse({ type: StorageStoredItemResponseDto })
|
||||
async addItemToStorage(
|
||||
@LoggedInUser() user: User,
|
||||
@Body() body: StorageAddItemRequestDto,
|
||||
@CurrentStorage() storage: Storage,
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
@Post('item/:storageId/:itemId')
|
||||
@ApiParam({ name: 'storageId', description: 'Storage ID' })
|
||||
@ApiParam({ name: 'itemId', description: 'Existing item ID' })
|
||||
@ApiBody({ type: StorageAddExistingItemRequestDto })
|
||||
@ApiOperation({ summary: 'Add an instance of an existing item to storage' })
|
||||
@ApiOkResponse({ type: StorageStoredItemResponseDto })
|
||||
async addExistingItemToStorage(
|
||||
@Param('itemId', ParseIntPipe) itemId: number,
|
||||
@LoggedInUser() user: User,
|
||||
@Body() body: StorageAddExistingItemRequestDto,
|
||||
@CurrentStorage() storage: Storage,
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
@Get(':storageId')
|
||||
@ApiParam({ name: 'storageId', description: 'Storage ID' })
|
||||
@ApiOperation({ summary: 'Get storage by ID' })
|
||||
@ApiOkResponse({ type: StorageResponseDto })
|
||||
async getStorage(
|
||||
@CurrentStorage() storage: Storage,
|
||||
): Promise<StorageResponseDto> {
|
||||
return this.service.formatStorageNoItems(storage);
|
||||
}
|
||||
|
||||
@Patch(':storageId')
|
||||
@ApiParam({ name: 'storageId', description: 'Storage ID' })
|
||||
@ApiBody({ type: StorageUpdateRequestDto })
|
||||
@ApiOperation({ summary: 'Update storage by ID' })
|
||||
@ApiOkResponse({ type: StorageResponseDto })
|
||||
async updateStorage(
|
||||
@CurrentStorage() storage: Storage,
|
||||
@Body() body: StorageUpdateRequestDto,
|
||||
): Promise<StorageResponseDto> {
|
||||
return this.service.updateStorage(storage, body);
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,8 @@ import { StorageSet } from 'src/objects/storage/entities/storage-set.entity';
|
||||
import { Storage } from 'src/objects/storage/entities/storage.entity';
|
||||
import { StorageService } from 'src/objects/storage/storage.service';
|
||||
import { User } from 'src/objects/user/user.entity';
|
||||
import { StorageItemRequestQueryDto } from './dto/storage-item-request.dto';
|
||||
import { StorageItemSearchResponseDto } from './dto/storage-item-response.dto';
|
||||
import {
|
||||
StorageCreateRequestDto,
|
||||
StorageUpdateRequestDto,
|
||||
@ -98,6 +100,22 @@ export class AppStorageService {
|
||||
return this.formatStorageSetNoItems(set);
|
||||
}
|
||||
|
||||
async searchForItems(user: User, query: StorageItemRequestQueryDto) {
|
||||
let responses: StorageItemSearchResponseDto[];
|
||||
if (query.searchTerm) {
|
||||
responses = await this.storageService.searchForItem(
|
||||
query.searchTerm,
|
||||
user.sub,
|
||||
);
|
||||
} else {
|
||||
responses = await this.storageService.searchForItemByBarcode(
|
||||
query.barcode,
|
||||
user.sub,
|
||||
);
|
||||
}
|
||||
return responses;
|
||||
}
|
||||
|
||||
formatActor(input: User): StorageActorResponse {
|
||||
return pick(input, ['name', 'sub', 'color']);
|
||||
}
|
||||
|
143
src/app-storage/dto/storage-add-item-request.dto.ts
Normal file
143
src/app-storage/dto/storage-add-item-request.dto.ts
Normal file
@ -0,0 +1,143 @@
|
||||
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
|
||||
import { Type } from 'class-transformer';
|
||||
import {
|
||||
IsBoolean,
|
||||
IsDate,
|
||||
IsEnum,
|
||||
IsNumber,
|
||||
IsObject,
|
||||
IsOptional,
|
||||
IsString,
|
||||
MaxLength,
|
||||
MinLength,
|
||||
ValidateNested,
|
||||
} from 'class-validator';
|
||||
import { ItemType } from 'src/objects/storage/enums/item-type.enum';
|
||||
import { TransactionType } from 'src/objects/storage/enums/transaction-type.enum';
|
||||
|
||||
export class StorageItemRequestDto {
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
@MinLength(3)
|
||||
@MaxLength(32)
|
||||
displayName: string;
|
||||
|
||||
@ApiProperty({ type: String, enum: ItemType })
|
||||
@IsEnum(ItemType)
|
||||
type: ItemType;
|
||||
|
||||
@ApiPropertyOptional()
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
barcode?: string;
|
||||
|
||||
@ApiPropertyOptional()
|
||||
@IsBoolean()
|
||||
@IsOptional()
|
||||
consumable?: boolean;
|
||||
|
||||
@ApiPropertyOptional()
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
image?: string;
|
||||
|
||||
@ApiPropertyOptional()
|
||||
@IsNumber()
|
||||
@IsOptional()
|
||||
weight?: number;
|
||||
|
||||
@ApiPropertyOptional()
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
url?: string;
|
||||
|
||||
@ApiPropertyOptional()
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
notes?: string;
|
||||
|
||||
@ApiPropertyOptional()
|
||||
@IsBoolean()
|
||||
@IsOptional()
|
||||
public?: boolean;
|
||||
}
|
||||
|
||||
export class StorageStoredItemRequestDto {
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
notes?: string;
|
||||
|
||||
@ApiPropertyOptional()
|
||||
@IsDate()
|
||||
@IsOptional()
|
||||
expiresAt?: Date;
|
||||
|
||||
@ApiPropertyOptional()
|
||||
@IsDate()
|
||||
@IsOptional()
|
||||
acquiredAt?: Date;
|
||||
|
||||
@ApiPropertyOptional()
|
||||
@IsDate()
|
||||
@IsOptional()
|
||||
consumedAt?: Date;
|
||||
}
|
||||
|
||||
export class StorageStoredItemTransactionRequestDto {
|
||||
@ApiProperty({ type: String, enum: TransactionType })
|
||||
@IsEnum(TransactionType)
|
||||
type: TransactionType;
|
||||
|
||||
@ApiPropertyOptional()
|
||||
@IsNumber()
|
||||
@IsOptional()
|
||||
price?: number;
|
||||
|
||||
@ApiPropertyOptional()
|
||||
@IsString()
|
||||
@MaxLength(3)
|
||||
@MinLength(3)
|
||||
@IsOptional()
|
||||
currency?: string;
|
||||
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
notes?: string;
|
||||
|
||||
@ApiPropertyOptional()
|
||||
@IsDate()
|
||||
@IsOptional()
|
||||
actionAt?: Date;
|
||||
}
|
||||
|
||||
export class StorageAddExistingItemRequestDto {
|
||||
@ApiPropertyOptional({ type: StorageStoredItemRequestDto })
|
||||
@Type(() => StorageStoredItemRequestDto)
|
||||
@IsObject()
|
||||
@IsOptional()
|
||||
@ValidateNested()
|
||||
additionalInfo: StorageStoredItemRequestDto;
|
||||
|
||||
@ApiProperty({ type: StorageStoredItemTransactionRequestDto })
|
||||
@Type(() => StorageStoredItemTransactionRequestDto)
|
||||
@IsObject()
|
||||
@ValidateNested()
|
||||
transactionInfo: StorageStoredItemTransactionRequestDto;
|
||||
}
|
||||
|
||||
export class StorageAddItemRequestDto extends StorageItemRequestDto {
|
||||
@ApiPropertyOptional({ type: StorageStoredItemRequestDto })
|
||||
@Type(() => StorageStoredItemRequestDto)
|
||||
@IsObject()
|
||||
@IsOptional()
|
||||
@ValidateNested()
|
||||
additionalInfo: StorageStoredItemRequestDto;
|
||||
|
||||
@ApiProperty({ type: StorageStoredItemTransactionRequestDto })
|
||||
@Type(() => StorageStoredItemTransactionRequestDto)
|
||||
@IsObject()
|
||||
@ValidateNested()
|
||||
transactionInfo: StorageStoredItemTransactionRequestDto;
|
||||
}
|
14
src/app-storage/dto/storage-item-request.dto.ts
Normal file
14
src/app-storage/dto/storage-item-request.dto.ts
Normal file
@ -0,0 +1,14 @@
|
||||
import { ApiPropertyOptional } from '@nestjs/swagger';
|
||||
import { IsString, ValidateIf } from 'class-validator';
|
||||
|
||||
export class StorageItemRequestQueryDto {
|
||||
@ApiPropertyOptional()
|
||||
@IsString()
|
||||
@ValidateIf((obj) => !obj.barcode)
|
||||
searchTerm?: string;
|
||||
|
||||
@ApiPropertyOptional()
|
||||
@IsString()
|
||||
@ValidateIf((obj) => !obj.searchTerm)
|
||||
barcode?: string;
|
||||
}
|
42
src/app-storage/dto/storage-item-response.dto.ts
Normal file
42
src/app-storage/dto/storage-item-response.dto.ts
Normal file
@ -0,0 +1,42 @@
|
||||
import { ApiProperty, OmitType, PickType } from '@nestjs/swagger';
|
||||
import { Type } from 'class-transformer';
|
||||
import { StoredItemTransaction } from 'src/objects/storage/entities/item-transaction.entity';
|
||||
import { Item } from 'src/objects/storage/entities/item.entity';
|
||||
import { StoredItem } from 'src/objects/storage/entities/stored-item.entity';
|
||||
import { StorageActorResponse } from './storage-response.dto';
|
||||
|
||||
export class StorageItemResponseDto extends OmitType(Item, [
|
||||
'instances',
|
||||
'addedBy',
|
||||
]) {
|
||||
@ApiProperty({ type: StorageActorResponse })
|
||||
addedBy: StorageActorResponse;
|
||||
}
|
||||
|
||||
export class StorageItemSearchResponseDto extends PickType(Item, [
|
||||
'id',
|
||||
'displayName',
|
||||
'type',
|
||||
'barcode',
|
||||
'image',
|
||||
'createdAt',
|
||||
]) {}
|
||||
|
||||
export class StorageStoredItemResponseDto extends OmitType(StoredItem, [
|
||||
'transactions',
|
||||
'storage',
|
||||
'item',
|
||||
]) {
|
||||
@ApiProperty({ type: StorageItemResponseDto })
|
||||
@Type(() => StorageItemResponseDto)
|
||||
item: StorageItemResponseDto;
|
||||
}
|
||||
|
||||
export class StorageStoredItemTransactionDto extends OmitType(
|
||||
StoredItemTransaction,
|
||||
['storedItem'],
|
||||
) {
|
||||
@ApiProperty({ type: StorageStoredItemResponseDto })
|
||||
@Type(() => StorageStoredItemResponseDto)
|
||||
storedItem: StorageStoredItemResponseDto;
|
||||
}
|
@ -19,10 +19,6 @@ export class StoredItem {
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
|
||||
@ApiProperty()
|
||||
@Column()
|
||||
displayName: string;
|
||||
|
||||
@ApiProperty({ type: () => Item })
|
||||
@ManyToOne(() => Item, {
|
||||
onDelete: 'CASCADE',
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { Repository } from 'typeorm';
|
||||
import { ILike, Repository } from 'typeorm';
|
||||
import { BuildingService } from '../building/building.service';
|
||||
import { GroupService } from '../group/group.service';
|
||||
import { UserService } from '../user/user.service';
|
||||
@ -157,6 +157,65 @@ export class StorageService {
|
||||
});
|
||||
}
|
||||
|
||||
async searchForItem(searchTerm: string, sub: string) {
|
||||
const displayName = ILike(`%${searchTerm}%`);
|
||||
return this.itemRepository.find({
|
||||
where: [
|
||||
{
|
||||
displayName,
|
||||
addedBy: {
|
||||
sub,
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName,
|
||||
public: true,
|
||||
},
|
||||
{
|
||||
displayName,
|
||||
addedBy: {
|
||||
groups: {
|
||||
members: {
|
||||
sub,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
take: 10,
|
||||
select: ['id', 'displayName', 'type', 'barcode', 'image', 'createdAt'],
|
||||
});
|
||||
}
|
||||
|
||||
async searchForItemByBarcode(barcode: string, sub: string) {
|
||||
return this.itemRepository.find({
|
||||
where: [
|
||||
{
|
||||
barcode,
|
||||
addedBy: {
|
||||
sub,
|
||||
},
|
||||
},
|
||||
{
|
||||
barcode,
|
||||
public: true,
|
||||
},
|
||||
{
|
||||
barcode,
|
||||
addedBy: {
|
||||
groups: {
|
||||
members: {
|
||||
sub,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
take: 10,
|
||||
select: ['id', 'displayName', 'type', 'barcode', 'image', 'createdAt'],
|
||||
});
|
||||
}
|
||||
|
||||
async saveStorage(data: Partial<Storage>) {
|
||||
const newStorage = new Storage();
|
||||
Object.assign(newStorage, data);
|
||||
|
Loading…
Reference in New Issue
Block a user