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")
|
createdAt DateTime @default(now()) @map("created_at")
|
||||||
updatedAt DateTime @updatedAt @map("updated_at")
|
updatedAt DateTime @updatedAt @map("updated_at")
|
||||||
expensesLists ExpenseList[]
|
expensesLists ExpenseList[]
|
||||||
BankCard BankCard[]
|
bankCard BankCard[]
|
||||||
|
cash Cash[]
|
||||||
|
|
||||||
@@map("users")
|
@@map("users")
|
||||||
}
|
}
|
||||||
@ -81,3 +82,15 @@ model BankCard {
|
|||||||
|
|
||||||
@@map("bank_cards")
|
@@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 { AuthModule } from './auth/auth.module';
|
||||||
import { BankAccountModule } from './bank-account/bank-account.module';
|
import { BankAccountModule } from './bank-account/bank-account.module';
|
||||||
import { BankCardModule } from './bank-card/bank-card.module';
|
import { BankCardModule } from './bank-card/bank-card.module';
|
||||||
|
import { CashModule } from './cash/cash.module';
|
||||||
import { ExpensesModule } from './expenses/expenses.module';
|
import { ExpensesModule } from './expenses/expenses.module';
|
||||||
import { PrismaModule } from './prisma/prisma.module';
|
import { PrismaModule } from './prisma/prisma.module';
|
||||||
|
|
||||||
@ -17,6 +18,7 @@ import { PrismaModule } from './prisma/prisma.module';
|
|||||||
ExpensesModule,
|
ExpensesModule,
|
||||||
BankAccountModule,
|
BankAccountModule,
|
||||||
BankCardModule,
|
BankCardModule,
|
||||||
|
CashModule,
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
export class AppModule {}
|
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