From c0daf8c2ff4194b60d7228a2c61381b2192336a7 Mon Sep 17 00:00:00 2001 From: Henrique Leite Date: Sun, 26 Nov 2023 20:33:22 -0300 Subject: [PATCH] Add route to create bank account --- prisma/schema.prisma | 1 + src/delivery/bank.controller.ts | 21 ++++++- src/delivery/dtos/bank.ts | 35 ++++++++++++ src/delivery/dtos/category.ts | 10 ++++ src/models/bank.ts | 25 +++++++-- .../postgres/bank/bank-repository.module.ts | 5 +- .../postgres/bank/bank-repository.service.ts | 56 ++++++++++++++++++- .../terms-and-policies-repository.service.ts | 21 +++++-- src/usecases/bank/bank.service.ts | 6 +- .../terms-and-policies.service.ts | 23 ++------ tsconfig.build.json | 4 +- tsconfig.json | 2 +- 12 files changed, 169 insertions(+), 40 deletions(-) create mode 100644 src/delivery/dtos/bank.ts diff --git a/prisma/schema.prisma b/prisma/schema.prisma index a66263e..1e68682 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -252,6 +252,7 @@ model BankAccount { recurrentTransactionFroms RecurrentTransaction[] @relation(name: "RecurrentTransactionBankAccountFrom") recurrentTransactionTos RecurrentTransaction[] @relation(name: "RecurrentTransactionBankAccountTo") + @@unique([accountId, bankProviderId, accountNumber]) @@map("bank_accounts") } diff --git a/src/delivery/bank.controller.ts b/src/delivery/bank.controller.ts index 66e710a..a358071 100644 --- a/src/delivery/bank.controller.ts +++ b/src/delivery/bank.controller.ts @@ -1,7 +1,9 @@ -import { Controller, Get, Query, UseGuards } from '@nestjs/common'; +import { Body, Controller, Get, Post, Query, UseGuards } from '@nestjs/common'; import { AuthGuard } from './guards/auth.guard'; -import { PaginatedDto } from './dtos'; +import { PaginatedDto, UserDataDto } from './dtos'; import { BankService } from 'src/usecases/bank/bank.service'; +import { UserData } from './decorators/user-data'; +import { CreateDto } from './dtos/bank'; @Controller('banks') @UseGuards(AuthGuard()) @@ -9,10 +11,23 @@ export class BankController { constructor(private readonly bankService: BankService) {} @Get('/providers') - async getDefault( + getDefault( @Query() pagination: PaginatedDto, ) { return this.bankService.getProviders(pagination); } + + @Post('accounts') + create( + @UserData() + userData: UserDataDto, + @Body() + body: CreateDto, + ) { + return this.bankService.create({ + ...body, + accountId: userData.accountId, + }); + } } diff --git a/src/delivery/dtos/bank.ts b/src/delivery/dtos/bank.ts new file mode 100644 index 0000000..60e108d --- /dev/null +++ b/src/delivery/dtos/bank.ts @@ -0,0 +1,35 @@ +import { + IsInt, + IsNumberString, + IsString, + Max, + MaxLength, + Min, + MinLength, +} from 'class-validator'; +import { IsID } from '../validators/internal'; + +export class CreateDto { + @IsString() + @MinLength(1) + @MaxLength(20) + name: string; + + @IsID() + bankProviderId: string; + + @IsNumberString() + @MinLength(6) + @MaxLength(6) + accountNumber: string; + + @IsNumberString() + @MinLength(3) + @MaxLength(3) + branch: string; + + @IsInt() + @Min(0) + @Max(999_999_999_99) + balance: number; +} diff --git a/src/delivery/dtos/category.ts b/src/delivery/dtos/category.ts index 8661354..ac99da8 100644 --- a/src/delivery/dtos/category.ts +++ b/src/delivery/dtos/category.ts @@ -1,10 +1,15 @@ import { IconEnum } from '@prisma/client'; +import { Type } from 'class-transformer'; import { + ArrayMaxSize, + ArrayMinSize, + IsArray, IsEnum, IsHexColor, IsString, MaxLength, MinLength, + ValidateNested, } from 'class-validator'; class CreateCategoryDto { @@ -25,5 +30,10 @@ class CreateCategoryDto { } export class CreateManyDto { + @IsArray() + @ValidateNested({ each: true }) + @ArrayMinSize(1) + @ArrayMaxSize(50) + @Type(() => CreateCategoryDto) categories: Array; } diff --git a/src/models/bank.ts b/src/models/bank.ts index a575351..43ae920 100644 --- a/src/models/bank.ts +++ b/src/models/bank.ts @@ -1,3 +1,10 @@ +import { BankAccount, BankProvider } from '@prisma/client'; +import { + Paginated, + PaginatedItems, + PaginatedRepository, +} from 'src/types/paginated-items'; + /** * * @@ -6,15 +13,19 @@ * */ -import { BankProvider } from '@prisma/client'; -import { - Paginated, - PaginatedItems, - PaginatedRepository, -} from 'src/types/paginated-items'; +export interface CreateInput { + accountId: string; + bankProviderId: string; + name: string; + accountNumber: string; + branch: string; + balance: number; +} export abstract class BankRepository { abstract getProviders(i: PaginatedRepository): Promise>; + + abstract create(i: CreateInput): Promise; } /** @@ -27,4 +38,6 @@ export abstract class BankRepository { export abstract class BankUseCase { abstract getProviders(i: Paginated): Promise>; + + abstract create(i: CreateInput): Promise; } diff --git a/src/repositories/postgres/bank/bank-repository.module.ts b/src/repositories/postgres/bank/bank-repository.module.ts index 074722d..dc34956 100644 --- a/src/repositories/postgres/bank/bank-repository.module.ts +++ b/src/repositories/postgres/bank/bank-repository.module.ts @@ -1,10 +1,11 @@ import { Module } from '@nestjs/common'; import { PostgresModule } from '..'; import { BankRepositoryService } from './bank-repository.service'; +import { UIDAdapter } from 'src/adapters/implementations/uid.service'; @Module({ - imports: [PostgresModule.forFeature(['bankProvider'])], - providers: [BankRepositoryService], + imports: [PostgresModule.forFeature(['bankProvider', 'bankAccount'])], + providers: [BankRepositoryService, UIDAdapter], exports: [BankRepositoryService], }) export class BankRepositoryModule {} diff --git a/src/repositories/postgres/bank/bank-repository.service.ts b/src/repositories/postgres/bank/bank-repository.service.ts index ef7ce8f..7dfcfb6 100644 --- a/src/repositories/postgres/bank/bank-repository.service.ts +++ b/src/repositories/postgres/bank/bank-repository.service.ts @@ -1,14 +1,24 @@ -import { Injectable } from '@nestjs/common'; +import { + ConflictException, + Injectable, + InternalServerErrorException, + NotFoundException, +} from '@nestjs/common'; import { InjectRepository, Repository } from '..'; -import { BankProvider } from '@prisma/client'; +import { BankAccount, BankProvider } from '@prisma/client'; import { PaginatedRepository } from 'src/types/paginated-items'; -import { BankRepository } from 'src/models/bank'; +import { BankRepository, CreateInput } from 'src/models/bank'; +import { UIDAdapter } from 'src/adapters/implementations/uid.service'; @Injectable() export class BankRepositoryService extends BankRepository { constructor( @InjectRepository('bankProvider') private readonly bankProviderRepository: Repository<'bankProvider'>, + @InjectRepository('bankAccount') + private readonly bankAccountRepository: Repository<'bankAccount'>, + + private readonly idAdapter: UIDAdapter, ) { super(); } @@ -22,4 +32,44 @@ export class BankRepositoryService extends BankRepository { take: limit, }); } + + async create({ + accountId, + bankProviderId, + name, + accountNumber, + branch, + balance, + }: CreateInput): Promise { + try { + const bankAccount = await this.bankAccountRepository.create({ + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + //@ts-ignore + data: { + id: this.idAdapter.gen(), + accountId, + bankProviderId, + name, + accountNumber, + branch, + balance, + }, + }); + + return bankAccount; + } catch (err) { + // https://www.prisma.io/docs/reference/api-reference/error-reference#p2003 + if (err.code === 'P2003') { + throw new NotFoundException("Bank provider doesn't exists"); + } + // https://www.prisma.io/docs/reference/api-reference/error-reference#p2004 + if (err.code === 'P2004') { + throw new ConflictException('Bank account already exists'); + } + + throw new InternalServerErrorException( + `Fail to create bank account: ${err.message}`, + ); + } + } } diff --git a/src/repositories/postgres/terms-and-policies/terms-and-policies-repository.service.ts b/src/repositories/postgres/terms-and-policies/terms-and-policies-repository.service.ts index 1183393..3dc0b77 100644 --- a/src/repositories/postgres/terms-and-policies/terms-and-policies-repository.service.ts +++ b/src/repositories/postgres/terms-and-policies/terms-and-policies-repository.service.ts @@ -1,4 +1,9 @@ -import { Injectable } from '@nestjs/common'; +import { + ConflictException, + Injectable, + InternalServerErrorException, + NotFoundException, +} from '@nestjs/common'; import { InjectRepository, Repository } from '..'; import { AcceptInput, @@ -29,18 +34,26 @@ export class TermsAndPoliciesRepositoryService extends TermsAndPoliciesRepositor } catch (err) { // https://www.prisma.io/docs/reference/api-reference/error-reference#p2003 if (err.code === 'P2003') { - throw new Error("Version doesn't exists"); + throw new NotFoundException("Version doesn't exists"); } + // https://www.prisma.io/docs/reference/api-reference/error-reference#p2004 if (err.code === 'P2004') { - throw new Error('Version already accepted'); + throw new ConflictException('Version already accepted'); } - throw new Error(`Fail to accept version: ${err.message}`); + throw new InternalServerErrorException( + `Fail to accept version: ${err.message}`, + ); } } getLatest(): Promise { return this.termsAndPoliciesRepository.findFirst({ + where: { + liveAt: { + lte: new Date(), + }, + }, orderBy: { liveAt: 'desc', }, diff --git a/src/usecases/bank/bank.service.ts b/src/usecases/bank/bank.service.ts index 2ebc514..a9f06b5 100644 --- a/src/usecases/bank/bank.service.ts +++ b/src/usecases/bank/bank.service.ts @@ -1,7 +1,7 @@ import { Inject, Injectable } from '@nestjs/common'; import { BankProvider } from '@prisma/client'; import { UtilsAdapter } from 'src/adapters/implementations/utils.service'; -import { BankUseCase } from 'src/models/bank'; +import { BankUseCase, CreateInput } from 'src/models/bank'; import { BankRepositoryService } from 'src/repositories/postgres/bank/bank-repository.service'; import { Paginated, PaginatedItems } from 'src/types/paginated-items'; @@ -27,4 +27,8 @@ export class BankService extends BankUseCase { data, }; } + + async create(i: CreateInput): Promise { + await this.bankRepository.create(i); + } } diff --git a/src/usecases/terms-and-policies/terms-and-policies.service.ts b/src/usecases/terms-and-policies/terms-and-policies.service.ts index f0b0359..a5a9169 100644 --- a/src/usecases/terms-and-policies/terms-and-policies.service.ts +++ b/src/usecases/terms-and-policies/terms-and-policies.service.ts @@ -1,9 +1,4 @@ -import { - BadRequestException, - Inject, - Injectable, - NotFoundException, -} from '@nestjs/common'; +import { BadRequestException, Inject, Injectable } from '@nestjs/common'; import { TermsAndPolicies } from '@prisma/client'; import { @@ -42,18 +37,10 @@ export class TermsAndPoliciesService extends TermsAndPoliciesUseCase { throw new BadRequestException('User already accepted terms'); } - await this.termsAndPoliciesRepository - .accept({ - accountId, - semVer, - }) - .catch((e) => { - if (e.message === "Version doesn't exists") { - throw new NotFoundException(e.message); - } - - throw e; - }); + await this.termsAndPoliciesRepository.accept({ + accountId, + semVer, + }); } async hasAcceptedLatest({ diff --git a/tsconfig.build.json b/tsconfig.build.json index 64f86c6..bd88af6 100644 --- a/tsconfig.build.json +++ b/tsconfig.build.json @@ -1,4 +1,4 @@ { - "extends": "./tsconfig.json", - "exclude": ["node_modules", "test", "dist", "**/*spec.ts"] + "extends": "./tsconfig.json", + "exclude": ["node_modules", "test", "dist", "dist-lint", "**/*spec.ts"] } diff --git a/tsconfig.json b/tsconfig.json index bc44362..d602478 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -19,5 +19,5 @@ "forceConsistentCasingInFileNames": false, "noFallthroughCasesInSwitch": false }, - "exclude": ["dist-lint"] + "exclude": ["dist", "dist-lint"] }