Project
[Toss] 잔액 사용 실패(1)
sangyunpark
2023. 8. 24. 20:35
POST /transaction/cancel
파라미터 : 거래 아이디, 계좌번호, 취소 요청 금액
실패 응답 : 거래 아이디에 해당하는 거래가 없는 경우, 거래금액과 거래 취소 금액이 다른경우(부분 취소 불가능), 1년 넘은 거래는 사용 취소 불가능, 해당 계좌에서 거래(사용, 사용 취소)가 진행 중일 때 다른 거래 요청이 오는 경우 해당 거래가 동시에 잘못 처리되는 것을 방지해야 한다.
성공 응답 : 계좌번호, 거래 결과 코드(성공/실패), 거래 아이디, 거래 금액, 거래일
요청
{
"transactionId" : "cxzu1823012380xcvcxvcx",
"accountNumber" : "100000000",
"amount" : 1000
}
응답
{
"accountNumber" : "1000000000",
"transactionResult" : "S",
"transactionId" : "dasjfla123ji2j490ee",
"amount":1000,
"transactionAt":"2022-02-01T23:33:14.2323"
}
Controller
@PostMapping("/transaction/cancel")
public CancelBalance.Response cacelBalacne(@Valid @RequestBody CancelBalance.Request request){
try{
return CancelBalance.Response.from(
transactionService.cancelBalance(request.getTransactionId(), request.getAccountNumber(), request.getAmount())
);
}catch(AccountException e){
log.error("Failed to cancel balance");
transactionService.saveFailedUseTransaction(request.getAccountNumber(), request.getAmount());
throw e;
}
}
Service
@Transactional
public TransactionDto cancelBalance(String transactionId, String accountNumber, Long amount) {
Account account = accountRepository.findByAccountNumber(accountNumber)
.orElseThrow(() -> new AccountException(ErrorCode.ACCOUNT_NOT_FOUND));
Transaction transaction = transactionRepository.findByTransactionId(transactionId)
.orElseThrow(() -> new AccountException(ErrorCode.TRANSACTION_NOT_FOUND));
validationCancelBalance(transaction, account, amount);
account.cancelBalance(amount);
return TransactionDto.fromEntity(
saveAndGetTransaction(CANCEL,SUCCESS,account,amount)
);
}
ValidationCancelBalance - 잔액 사용 요청을 취소하기 위한 조건
public void validationCancelBalance(Transaction transaction, Account account, Long amount) {
// 거래 금액과 취소 금액이 다른 경우
if(!Objects.equals(transaction.getAmount(), amount)){
throw new AccountException(ErrorCode.CANCEL_MUST_FULLY);
}
// id가 일치하지 않는다.
if(transaction.getId().equals(account.getId())){
throw new AccountException(ErrorCode.TRANSACTION_ACCOUNT_UN_MATCH);
}
// 1년 넘은 거래
if(transaction.getTransactedAt().isBefore(LocalDateTime.now().minusYears(1))){
throw new AccountException(ErrorCode.TOO_OLD_ORDER_TO_CANCEL);
}
}
잔액 사용 취소처리에 대해 오류가 발생할경우
@Transactional
public void saveFailedCancelTransaction(String accountNumber, Long amount) {
Account account = accountRepository.findByAccountNumber(accountNumber)
.orElseThrow(() -> new AccountException(ErrorCode.ACCOUNT_NOT_FOUND));
saveAndGetTransaction(CANCEL,FAIL, account, amount);
}
FAIL에 대한 데이터를 남겨준다.