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에 대한 데이터를 남겨준다.