feat(server): add cash
This commit is contained in:
parent
4b2e05fa65
commit
e7c0a48ed1
@ -26,7 +26,8 @@ model User {
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
updatedAt DateTime @updatedAt @map("updated_at")
|
||||
expensesLists ExpenseList[]
|
||||
BankCard BankCard[]
|
||||
bankCard BankCard[]
|
||||
cash Cash[]
|
||||
|
||||
@@map("users")
|
||||
}
|
||||
@ -81,3 +82,15 @@ model BankCard {
|
||||
|
||||
@@map("bank_cards")
|
||||
}
|
||||
|
||||
model Cash {
|
||||
id String @id @default(uuid())
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
userId String
|
||||
name String
|
||||
balance Float @default(0)
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
updatedAt DateTime @updatedAt @map("updated_at")
|
||||
|
||||
@@map("cash")
|
||||
}
|
||||
|
||||
@ -4,6 +4,7 @@ import { ConfigModule } from '@nestjs/config';
|
||||
import { AuthModule } from './auth/auth.module';
|
||||
import { BankAccountModule } from './bank-account/bank-account.module';
|
||||
import { BankCardModule } from './bank-card/bank-card.module';
|
||||
import { CashModule } from './cash/cash.module';
|
||||
import { ExpensesModule } from './expenses/expenses.module';
|
||||
import { PrismaModule } from './prisma/prisma.module';
|
||||
|
||||
@ -17,6 +18,7 @@ import { PrismaModule } from './prisma/prisma.module';
|
||||
ExpensesModule,
|
||||
BankAccountModule,
|
||||
BankCardModule,
|
||||
CashModule,
|
||||
],
|
||||
})
|
||||
export class AppModule {}
|
||||
|
||||
70
server/src/modules/cash/cash.controller.ts
Normal file
70
server/src/modules/cash/cash.controller.ts
Normal file
@ -0,0 +1,70 @@
|
||||
import {
|
||||
Body,
|
||||
Controller,
|
||||
Delete,
|
||||
Get,
|
||||
Param,
|
||||
Patch,
|
||||
Post,
|
||||
} from '@nestjs/common';
|
||||
import { Cash, User } from '@prisma/client';
|
||||
|
||||
import { Authorized } from '@/shared/decorators';
|
||||
|
||||
import { CashService } from './cash.service';
|
||||
import {
|
||||
CreateCash,
|
||||
DeleteCash,
|
||||
EditCash,
|
||||
GetAllCash,
|
||||
GetCash,
|
||||
} from './decorators';
|
||||
import { CreateCashDto, EditCashDto } from './dto';
|
||||
|
||||
@Controller('cash')
|
||||
export class CashController {
|
||||
constructor(private readonly cashService: CashService) {}
|
||||
|
||||
@CreateCash()
|
||||
@Post()
|
||||
async createCash(
|
||||
@Authorized('userId') userId: User['id'],
|
||||
@Body() dto: CreateCashDto,
|
||||
) {
|
||||
return this.cashService.createCash(userId, dto);
|
||||
}
|
||||
|
||||
@GetCash()
|
||||
@Get(':id')
|
||||
async getCashById(
|
||||
@Authorized('userId') userId: User['id'],
|
||||
@Param('id') id: Cash['id'],
|
||||
) {
|
||||
return this.cashService.getCashById(userId, id);
|
||||
}
|
||||
|
||||
@GetAllCash()
|
||||
@Get()
|
||||
async getAllCashByUserId(@Authorized('userId') userId: User['id']) {
|
||||
return this.cashService.getAllCashByUserId(userId);
|
||||
}
|
||||
|
||||
@EditCash()
|
||||
@Patch(':id')
|
||||
async editCash(
|
||||
@Authorized('userId') userId: User['id'],
|
||||
@Param('id') id: Cash['id'],
|
||||
@Body() dto: EditCashDto,
|
||||
) {
|
||||
return this.cashService.editCash(userId, id, dto);
|
||||
}
|
||||
|
||||
@DeleteCash()
|
||||
@Delete(':id')
|
||||
async deleteCash(
|
||||
@Authorized('userId') userId: User['id'],
|
||||
@Param('id') id: Cash['id'],
|
||||
) {
|
||||
return this.cashService.deleteCash(userId, id);
|
||||
}
|
||||
}
|
||||
10
server/src/modules/cash/cash.module.ts
Normal file
10
server/src/modules/cash/cash.module.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
|
||||
import { CashController } from './cash.controller';
|
||||
import { CashService } from './cash.service';
|
||||
|
||||
@Module({
|
||||
controllers: [CashController],
|
||||
providers: [CashService],
|
||||
})
|
||||
export class CashModule {}
|
||||
69
server/src/modules/cash/cash.service.ts
Normal file
69
server/src/modules/cash/cash.service.ts
Normal file
@ -0,0 +1,69 @@
|
||||
import { Injectable, NotFoundException } from '@nestjs/common';
|
||||
import { Cash, User } from '@prisma/client';
|
||||
|
||||
import { PrismaService } from '@/modules/prisma/prisma.service';
|
||||
|
||||
import { CashDto, CreateCashDto, EditCashDto } from './dto';
|
||||
|
||||
@Injectable()
|
||||
export class CashService {
|
||||
constructor(private readonly prismaService: PrismaService) {}
|
||||
|
||||
async createCash(userId: User['id'], dto: CreateCashDto): Promise<CashDto> {
|
||||
const { balance, name } = dto;
|
||||
|
||||
return this.prismaService.cash.create({
|
||||
data: {
|
||||
name,
|
||||
balance,
|
||||
user: {
|
||||
connect: { id: userId },
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async getCashById(userId: User['id'], cashId: Cash['id']): Promise<CashDto> {
|
||||
const cash = await this.prismaService.cash.findUnique({
|
||||
where: {
|
||||
id: cashId,
|
||||
userId,
|
||||
},
|
||||
});
|
||||
|
||||
if (!cash) {
|
||||
throw new NotFoundException('Кэш не найден');
|
||||
}
|
||||
|
||||
return cash;
|
||||
}
|
||||
|
||||
async getAllCashByUserId(userId: User['id']): Promise<CashDto[]> {
|
||||
return this.prismaService.cash.findMany({
|
||||
where: { userId },
|
||||
orderBy: { createdAt: 'asc' },
|
||||
});
|
||||
}
|
||||
|
||||
async editCash(userId: User['id'], cashId: Cash['id'], dto: EditCashDto): Promise<CashDto> {
|
||||
const { balance, name } = dto;
|
||||
|
||||
const cash = await this.getCashById(userId, cashId);
|
||||
|
||||
return this.prismaService.cash.update({
|
||||
where: { id: cashId },
|
||||
data: {
|
||||
name: name ?? cash.name,
|
||||
balance: balance ?? cash.balance,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async deleteCash(userId: User['id'], cashId: Cash['id']): Promise<CashDto> {
|
||||
const cash = await this.getCashById(userId, cashId);
|
||||
|
||||
return this.prismaService.cash.delete({
|
||||
where: { id: cash.id },
|
||||
});
|
||||
}
|
||||
}
|
||||
24
server/src/modules/cash/decorators/create-cash.decorator.ts
Normal file
24
server/src/modules/cash/decorators/create-cash.decorator.ts
Normal file
@ -0,0 +1,24 @@
|
||||
import { applyDecorators } from '@nestjs/common';
|
||||
import { ApiBearerAuth, ApiOkResponse, ApiOperation } from '@nestjs/swagger';
|
||||
|
||||
import { Authorization } from '@/shared/decorators';
|
||||
|
||||
import { CashDto } from '../dto';
|
||||
|
||||
function Documentation() {
|
||||
return applyDecorators(
|
||||
ApiOperation({
|
||||
summary: 'Создать наличные',
|
||||
description: 'Создать наличные',
|
||||
}),
|
||||
ApiBearerAuth(),
|
||||
ApiOkResponse({ description: 'Успешно созданы наличные', type: CashDto }),
|
||||
);
|
||||
}
|
||||
|
||||
export function CreateCash() {
|
||||
return applyDecorators(
|
||||
Authorization(),
|
||||
Documentation(),
|
||||
);
|
||||
}
|
||||
32
server/src/modules/cash/decorators/delete-cash.decorator.ts
Normal file
32
server/src/modules/cash/decorators/delete-cash.decorator.ts
Normal file
@ -0,0 +1,32 @@
|
||||
import { applyDecorators } from '@nestjs/common';
|
||||
import {
|
||||
ApiBearerAuth,
|
||||
ApiNotFoundResponse,
|
||||
ApiOkResponse,
|
||||
ApiOperation,
|
||||
ApiParam,
|
||||
} from '@nestjs/swagger';
|
||||
|
||||
import { Authorization } from '@/shared/decorators';
|
||||
|
||||
import { CashDto } from '../dto';
|
||||
|
||||
function Documentation() {
|
||||
return applyDecorators(
|
||||
ApiOperation({
|
||||
summary: 'Удалить наличные',
|
||||
description: 'Удалить наличные',
|
||||
}),
|
||||
ApiBearerAuth(),
|
||||
ApiParam({ name: 'id', type: String, description: 'ID наличных' }),
|
||||
ApiNotFoundResponse({ description: 'Кэш не найден' }),
|
||||
ApiOkResponse({ description: 'Успешно удалены наличные', type: CashDto }),
|
||||
);
|
||||
}
|
||||
|
||||
export function DeleteCash() {
|
||||
return applyDecorators(
|
||||
Authorization(),
|
||||
Documentation(),
|
||||
);
|
||||
}
|
||||
32
server/src/modules/cash/decorators/edit-cash.decorator.ts
Normal file
32
server/src/modules/cash/decorators/edit-cash.decorator.ts
Normal file
@ -0,0 +1,32 @@
|
||||
import { applyDecorators } from '@nestjs/common';
|
||||
import {
|
||||
ApiBearerAuth,
|
||||
ApiNotFoundResponse,
|
||||
ApiOkResponse,
|
||||
ApiOperation,
|
||||
ApiParam,
|
||||
} from '@nestjs/swagger';
|
||||
|
||||
import { Authorization } from '@/shared/decorators';
|
||||
|
||||
import { CashDto } from '../dto';
|
||||
|
||||
function Documentation() {
|
||||
return applyDecorators(
|
||||
ApiOperation({
|
||||
summary: 'Редактировать наличные',
|
||||
description: 'Редактировать наличные',
|
||||
}),
|
||||
ApiBearerAuth(),
|
||||
ApiParam({ name: 'id', type: String, description: 'ID наличных' }),
|
||||
ApiNotFoundResponse({ description: 'Кэш не найден' }),
|
||||
ApiOkResponse({ description: 'Успешно отредактированы наличные', type: CashDto }),
|
||||
);
|
||||
}
|
||||
|
||||
export function EditCash() {
|
||||
return applyDecorators(
|
||||
Authorization(),
|
||||
Documentation(),
|
||||
);
|
||||
}
|
||||
24
server/src/modules/cash/decorators/get-all-cash.decorator.ts
Normal file
24
server/src/modules/cash/decorators/get-all-cash.decorator.ts
Normal file
@ -0,0 +1,24 @@
|
||||
import { applyDecorators } from '@nestjs/common';
|
||||
import { ApiBearerAuth, ApiOkResponse, ApiOperation } from '@nestjs/swagger';
|
||||
|
||||
import { Authorization } from '@/shared/decorators';
|
||||
|
||||
import { CashDto } from '../dto';
|
||||
|
||||
function Documentation() {
|
||||
return applyDecorators(
|
||||
ApiOperation({
|
||||
summary: 'Найти все наличные',
|
||||
description: 'Найти все наличные',
|
||||
}),
|
||||
ApiBearerAuth(),
|
||||
ApiOkResponse({ description: 'Успешно найдены наличные', type: [CashDto] }),
|
||||
);
|
||||
}
|
||||
|
||||
export function GetAllCash() {
|
||||
return applyDecorators(
|
||||
Authorization(),
|
||||
Documentation(),
|
||||
);
|
||||
}
|
||||
32
server/src/modules/cash/decorators/get-cash.decorator.ts
Normal file
32
server/src/modules/cash/decorators/get-cash.decorator.ts
Normal file
@ -0,0 +1,32 @@
|
||||
import { applyDecorators } from '@nestjs/common';
|
||||
import {
|
||||
ApiBearerAuth,
|
||||
ApiNotFoundResponse,
|
||||
ApiOkResponse,
|
||||
ApiOperation,
|
||||
ApiParam,
|
||||
} from '@nestjs/swagger';
|
||||
|
||||
import { Authorization } from '@/shared/decorators';
|
||||
|
||||
import { CashDto } from '../dto';
|
||||
|
||||
function Documentation() {
|
||||
return applyDecorators(
|
||||
ApiOperation({
|
||||
summary: 'Найти наличные',
|
||||
description: 'Найти наличные',
|
||||
}),
|
||||
ApiBearerAuth(),
|
||||
ApiParam({ name: 'id', type: String, description: 'ID наличных' }),
|
||||
ApiNotFoundResponse({ description: 'Кэш не найден' }),
|
||||
ApiOkResponse({ description: 'Успешно найдены наличные', type: CashDto }),
|
||||
);
|
||||
}
|
||||
|
||||
export function GetCash() {
|
||||
return applyDecorators(
|
||||
Authorization(),
|
||||
Documentation(),
|
||||
);
|
||||
}
|
||||
5
server/src/modules/cash/decorators/index.ts
Normal file
5
server/src/modules/cash/decorators/index.ts
Normal file
@ -0,0 +1,5 @@
|
||||
export { CreateCash } from './create-cash.decorator';
|
||||
export { DeleteCash } from './delete-cash.decorator';
|
||||
export { EditCash } from './edit-cash.decorator';
|
||||
export { GetAllCash } from './get-all-cash.decorator';
|
||||
export { GetCash } from './get-cash.decorator';
|
||||
35
server/src/modules/cash/dto/cash.dto.ts
Normal file
35
server/src/modules/cash/dto/cash.dto.ts
Normal file
@ -0,0 +1,35 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
|
||||
export class CashDto {
|
||||
@ApiProperty({
|
||||
description: 'ID',
|
||||
type: String,
|
||||
})
|
||||
id: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Название',
|
||||
example: 'Наличные',
|
||||
type: String,
|
||||
})
|
||||
name: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Баланс',
|
||||
example: 10_000.00,
|
||||
type: Number,
|
||||
})
|
||||
balance: number;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Дата создания',
|
||||
type: Date,
|
||||
})
|
||||
createdAt: Date;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Дата обновления',
|
||||
type: Date,
|
||||
})
|
||||
updatedAt: Date;
|
||||
}
|
||||
24
server/src/modules/cash/dto/create-cash.dto.ts
Normal file
24
server/src/modules/cash/dto/create-cash.dto.ts
Normal file
@ -0,0 +1,24 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import {
|
||||
IsNotEmpty, IsNumber, IsOptional, IsString,
|
||||
} from 'class-validator';
|
||||
|
||||
export class CreateCashDto {
|
||||
@ApiProperty({
|
||||
description: 'Название',
|
||||
example: 'Наличные',
|
||||
type: String,
|
||||
})
|
||||
@IsString({ message: 'Название должно быть строкой' })
|
||||
@IsNotEmpty({ message: 'Название обязательно к заполнению' })
|
||||
name: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Баланс',
|
||||
example: 10_000.00,
|
||||
type: Number,
|
||||
})
|
||||
@IsNumber({ maxDecimalPlaces: 2 }, { message: 'Баланс должен быть числом' })
|
||||
@IsOptional()
|
||||
balance?: number;
|
||||
}
|
||||
26
server/src/modules/cash/dto/edit-cash.dto.ts
Normal file
26
server/src/modules/cash/dto/edit-cash.dto.ts
Normal file
@ -0,0 +1,26 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import {
|
||||
IsNumber,
|
||||
IsOptional,
|
||||
IsString,
|
||||
} from 'class-validator';
|
||||
|
||||
export class EditCashDto {
|
||||
@ApiProperty({
|
||||
description: 'Название',
|
||||
example: 'Наличные',
|
||||
type: String,
|
||||
})
|
||||
@IsString({ message: 'Название должно быть строкой' })
|
||||
@IsOptional()
|
||||
name?: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: 'Баланс',
|
||||
example: 10_000.00,
|
||||
type: Number,
|
||||
})
|
||||
@IsNumber({ maxDecimalPlaces: 2 }, { message: 'Баланс должен быть числом' })
|
||||
@IsOptional()
|
||||
balance?: number;
|
||||
}
|
||||
3
server/src/modules/cash/dto/index.ts
Normal file
3
server/src/modules/cash/dto/index.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export { CreateCashDto } from './create-cash.dto';
|
||||
export { CashDto } from './cash.dto';
|
||||
export { EditCashDto } from './edit-cash.dto';
|
||||
Loading…
x
Reference in New Issue
Block a user