Skip to content

Commit

Permalink
Merge pull request #56 from plus-tdd/feature/alarm
Browse files Browse the repository at this point in the history
Feature/alarm
  • Loading branch information
codesejin authored Jul 26, 2023
2 parents 515800d + 8a92a7a commit 30e28ba
Show file tree
Hide file tree
Showing 5 changed files with 159 additions and 67 deletions.
3 changes: 2 additions & 1 deletion src/logger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ export default class Logger {

public info(msg: string, metadata = '') {
this.now = moment().format('YYYY-MM-DD HH:mm:ss');
this.logger.info(msg + '-' + metadata);
this.logger.info(msg + ' - ' + metadata);
if (this.is_production) {
const info = {
timestamp: this.now,
Expand All @@ -79,6 +79,7 @@ export default class Logger {
this.sendToCloudWatch(info);
}
}

public error(errMsg: Error | string, metadata = '') {
this.now = moment().format('YYYY-MM-DD HH:mm:ss');
if (errMsg instanceof Error) {
Expand Down
86 changes: 48 additions & 38 deletions src/module/payment/api/payment.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,45 +6,55 @@ import { PaymentRequestDto } from './payment.save.request.dto';
import { RefundPaymentRequestDto } from './payment.refund.request.dto';
import { Payment } from '../domain/payment.model';
import { RefundPaymentInfo } from '../domain/payment.model';
import { JwtAuthGuard } from '../../auth/auth.jwtAuthGuard';

import { JwtAuthGuard } from "../../auth/auth.jwtAuthGuard";
import Logger from 'src/logger';
//@UseGuards(AuthGuard)
@Controller('/payment')
export class PaymentController {
constructor(private readonly paymentService: PaymentService) {}

@UseGuards(JwtAuthGuard)
@ApiOperation({ summary: '결제하기' })
@Post()
makePayment(@Body() paymentData: PaymentRequestDto): Promise<Payment> {
const { userId, cardNum, endDate, cvc, cardCompany, price } = paymentData;

// dto - > model
const paymentInfo: PaymentInfo = {
userId: userId,
cardNum: cardNum,
endDate: endDate,
cvc: cvc,
cardCompany: cardCompany,
price: price,
};

return this.paymentService.makePayment(paymentInfo);
}

@UseGuards(JwtAuthGuard)
@ApiOperation({ summary: '결제 취소하기' })
@Post('/refund')
refundPayment(
@Body() refundData: RefundPaymentRequestDto,
): Promise<PaymentInfoForRefund> {
const { paymentId, userId } = refundData;

// dto - > model
const refundInfo: RefundPaymentInfo = {
paymentId: paymentId,
userId: userId,
};
return this.paymentService.refundPayment(refundInfo);
}

private logger;

constructor(private readonly paymentService: PaymentService) {
this.logger = new Logger('PaymentController')
}

@UseGuards(JwtAuthGuard)
@ApiOperation({summary : '결제하기'})
@Post()
async makePayment(@Body() paymentData: PaymentRequestDto): Promise<Payment> {
const { userId, cardNum, endDate, cvc, cardCompany, price } = paymentData;

// dto - > model
const paymentInfo: PaymentInfo = {
userId: userId,
cardNum: cardNum,
endDate: endDate,
cvc: cvc,
cardCompany: cardCompany,
price: price
}

this.logger.info('request userId', paymentData.userId)
this.logger.info('request cardCompany',paymentData.cardCompany)
this.logger.info('request cardNum',paymentData.cardNum)
this.logger.info('request endDate',paymentData.endDate)
this.logger.info('request cvc',paymentData.cvc)
this.logger.info('request price',paymentData.price)

return await this.paymentService.makePayment(paymentInfo)
}

@UseGuards(JwtAuthGuard)
@ApiOperation({summary : '결제 취소하기'})
@Post('/refund')
refundPayment(@Body() refundData: RefundPaymentRequestDto): Promise<PaymentInfoForRefund> {
const { paymentId, userId} = refundData;

// dto - > model
const refundInfo: RefundPaymentInfo = {
paymentId: paymentId,
userId: userId
}
return this.paymentService.refundPayment(refundInfo)
}
}
95 changes: 78 additions & 17 deletions src/module/payment/data/payment.db.ts
Original file line number Diff line number Diff line change
@@ -1,38 +1,93 @@
import { Injectable } from '@nestjs/common';
import { PaymentRepository } from '../domain/payment.repository';
import {
CardCompany,
RefundPaymentInfo,
PaymentInfoForRefund,
} from '../domain/payment.model';
import { PaymentInfo, Payment } from '../domain/payment.model';
import { PaymentEntity } from './payment.entity';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { InvalidPaymentInfoError } from '../payment.error';
import { PaymentRepository } from "../domain/payment.repository";
import { CardCompany, RefundPaymentInfo, PaymentInfoForRefund } from "../domain/payment.model";
import { PaymentInfo, Payment } from "../domain/payment.model";
import { PaymentEntity } from "./payment.entity";
import { InjectRepository } from "@nestjs/typeorm";
import { Repository } from "typeorm";
import { InvalidPaymentInfoException } from '../payment.error';
import { UserEntity } from 'src/module/user/data/user.entity';
import Logger from 'src/logger';

// 실제 DB
@Injectable()
export class PaymentRepositoryImpl implements PaymentRepository {

private logger;

constructor(
// DB 주입
@InjectRepository(PaymentEntity)
private PaymentDB: Repository<PaymentEntity>,
@InjectRepository(UserEntity)
private UserDB: Repository<UserEntity>
){}
){
this.logger = new Logger('PaymentRepositoryImpl')
}

async savePayment(paymentInfo: PaymentInfo): Promise<Payment> {

console.log("paymentInfo : " + paymentInfo);
try {
// user가 db에 존재하는지??
const user = await this.UserDB.findOne({
where: { id: paymentInfo.userId },
});
if (user === null) {
this.logger.error('savePayment', `유저를 찾을 수 없습니다. savePayment request's userId: ${paymentInfo.userId}`);
throw new InvalidPaymentInfoException('유저');
}

// model -> entitiy
const entity = this.PaymentDB.create({
User: user,
cardNum: paymentInfo.cardNum,
endDate: paymentInfo.endDate,
cvc: paymentInfo.cvc,
cardCompany: paymentInfo.cardCompany,
price: paymentInfo.price,
});

try {
await this.PaymentDB.save(entity);

// 로그 추가
this.logger.info('savePayment', `새로운 결제 정보가 저장되었습니다. PAYMENT_ID: ${entity.id}, ACCOUNT: ${entity.User.account}`);

// 반환값
return {
paymentId: entity.id,
userId: entity.User.id,
cardNum: entity.cardNum,
endDate: entity.endDate,
cvc: entity.cvc,
cardCompany: paymentInfo.cardCompany,
price: entity.price,
};
} catch (error) {
this.logger.error('savePayment', `결제 정보 저장 중 오류가 발생하였습니다: ${error.message}`);
throw error; // 예외를 다시 던져서 호출한 쪽에서 처리할 수 있도록 함
}

} catch (error) {
// UserDB에서 예외 처리
this.logger.error('savePayment', `유저 정보 조회 중 오류가 발생하였습니다: ${error.message}`);
throw error; // 예외를 다시 던져서 호출한 쪽에서 처리할 수 있도록 함
}
}


async refundPayment(refundInfo: RefundPaymentInfo): Promise<PaymentInfoForRefund> {

// 요청에 들어온 paymentId가 db에 존재하는지?
const payment = await this.PaymentDB.findOne({
where: { id: refundInfo.paymentId}
});
if (payment === null) throw new InvalidPaymentInfoException('결제 PK');

// user가 db에 존재하는지??
const user = await this.UserDB.findOne({
where: { id: paymentInfo.userId },
});
if (user === null) throw new InvalidPaymentInfoError('유저');
if (user === null) throw new InvalidPaymentInfoException('유저');

// model -> entitiy
const entity = this.PaymentDB.create({
Expand Down Expand Up @@ -80,7 +135,7 @@ export class PaymentRepositoryImpl implements PaymentRepository {

// entitiy -> domain
const refundPaymentDomain: PaymentInfoForRefund = {
userId: user.id,
userId: payment.User.id,
cardNum: payment.cardNum,
endDate: payment.endDate,
cvc: payment.cvc,
Expand All @@ -97,7 +152,13 @@ export class PaymentRepositoryImpl implements PaymentRepository {
where: { id: userId },
});

if (user === null) throw new InvalidPaymentInfoError('유저');
async findUserPhoneNumber(userId: number): Promise<string> {
// user가 db에 존재하는지??
const user = await this.UserDB.findOne({
where: { id: userId },
});

if (user === null) throw new InvalidPaymentInfoException('유저');

return user.phoneNumber;
}
Expand Down
27 changes: 21 additions & 6 deletions src/module/payment/domain/payment.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,24 +9,30 @@ import {
} from './payment.model';
import { PaymentRepository } from './payment.repository';
import { AlarmData } from 'src/module/alarm/alarm.service';
import Logger from 'src/logger';
import { InvalidPaymentInfoException } from '../payment.error';

@Injectable() // 비즈니스 로직으로 분리
export class PaymentService {

private logger;

constructor(
@Inject('PaymentRepository')
private readonly repository: PaymentRepository,
@Inject('AlarmService')
private readonly alarmService: AlarmService,
) {}
) {
this.logger = new Logger('PaymentService')
}

public async makePayment(paymentInfo: PaymentInfo): Promise<Payment> {
this.validatePaymentInfo(paymentInfo);
// DB작업 - 결제 정보 저장
const savePaymentInfo = this.repository.savePayment(paymentInfo);
const savePaymentInfo = await this.repository.savePayment(paymentInfo);

// 결제 SDK 기능
this.paymentToSdk(paymentInfo);
await this.paymentToSdk(paymentInfo);

// 결제 완료 알람 붙여야함

Expand Down Expand Up @@ -74,14 +80,21 @@ export class PaymentService {
public async validatePaymentInfo(requestInfo: PaymentInfo): Promise<boolean> {
const { userId, cardNum, endDate, cvc, cardCompany, price } = requestInfo;

try {
if (cardNum !== undefined) {
if (!this.validateCardNum(cardNum)) {
return false;
this.logger.error('validateCardNum', `cardNum을 확인하세요 ${cardNum}`)
throw new InvalidPaymentInfoException('카드번호');
}
}
} catch (error) {
this.logger.error('validateCardNum', `카드번호 검증 중 오류가 발생하였습니다: ${error.message}`);
throw error; // 예외를 다시 던져서 호출한 쪽에서 처리할 수 있도록 함
}

if (!this.validateInfoIsEmpty(requestInfo)) {
return false;
this.logger.error('validateInfoIsEmpty', `requestInfo를 확인하세요 ${requestInfo}`)
throw new InvalidPaymentInfoException('요청겂');
}

return true;
Expand Down Expand Up @@ -116,7 +129,8 @@ export class PaymentService {
const cardNumString = cardNum.toString();

// 카드가 음수이거나, 길이가 16자를 초과하는 경우 실패로 처리 (정책 상 16자리까지만 있음)
if (cardNum < 0 || cardNumString.length > 16) {
if (cardNum < 0 || cardNumString.length > 16 ||cardNumString.length < 16 ) {
this.logger.error('validateCardNum', `cardNum이 0보다 작거나 16보다 길고, 짧으면 안됩니다 ${cardNum}`)
return false;
}
return true;
Expand All @@ -126,6 +140,7 @@ export class PaymentService {
private validateInfoIsEmpty(requestInfo: PaymentInfo): boolean {
const { cardNum, endDate, cvc, cardCompany } = requestInfo;
if (cardNum === undefined || endDate === undefined || cvc === undefined) {
this.logger.error('validateInfoIsEmpty', `requestInfo 중 빈 값이 존재하면 안됩니다. ${requestInfo}`)
return false;
}
return true;
Expand Down
15 changes: 10 additions & 5 deletions src/module/payment/payment.error.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
export class InvalidPaymentInfoError extends Error {
constructor(field: string) {
super('잘못된 ' + field + '입니다.');
this.name = 'InvalidCounselingInfo';
}


import { HttpException, HttpStatus } from '@nestjs/common';


export class InvalidPaymentInfoException extends HttpException {
constructor(field: string) {
super(`잘못된 ${field}입니다.`, HttpStatus.BAD_REQUEST); // 400 에러로 설정
}
}

0 comments on commit 30e28ba

Please sign in to comment.