-
Notifications
You must be signed in to change notification settings - Fork 26
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feature/opixxx step4 #32
Open
opixxx
wants to merge
28
commits into
base/opixxx
Choose a base branch
from
feature/opixxx_step4
base: base/opixxx
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
28 commits
Select commit
Hold shift + click to select a range
461be44
feat: Transactional(입출금 내역 테이블) 기본 셋팅
opixxx cd342bc
feat: 기존 송금 구조 변경
opixxx c40cd41
feat: 기존 송금 구조 변경
opixxx 243ad91
fix: 틀린 변수 명 수정
opixxx 506c3dc
refactor: 사용안하는 클래스 삭제, 메서드 명 변경
opixxx 5036ef9
feat: 변경된 송금 구조에 따른 테스트 코드 변경
opixxx d8f0cb7
feat: TransactionalRepository 테스크 코드 작성
opixxx 1e6cf0f
feat: 송금 기능 추가 구현
opixxx 2f4f4aa
chore: 클래스명 변경 Transactionl -> Transaction
opixxx d259307
chore: 클래스명 변경 Transactional -> Transaction
opixxx 9ca52d6
chore: 클래스명 변경 Transactional -> Transaction
opixxx 7b55be5
chore: 클래스명 변경 Transactional -> Transaction
opixxx 51cb60c
chore: 클래스명 변경 Transactional -> Transaction
opixxx 06af3cb
feat: 72시간이 지난 송금 내역을 취소하는 기능 구현
opixxx 6abbf27
chore: 패키지명 변경 transactional -> transaction
opixxx f834f34
chore: JavaMail 의존성 및 환경변수 설정
opixxx 6e95840
test: 비즈니스 로직 변경으로 인한 테스트 코드 변경
opixxx e027e21
test: 비즈니스 로직 변경으로 인한 테스트 코드 변경
opixxx 250cb36
test: 송금 취소, 기한 마감으로 인한 송금 취소 메서드 테스트 코드 작성
opixxx 3fe7731
chore: 메서드 설명 주석 추가
opixxx ff68ee6
feat: 송금 마감 알림 전송 기능 구현
opixxx c45c670
chore: 이메일 환경 변수 테스트 용 설정
opixxx 55350fc
chore: 메서드 명 변경
opixxx ca49cd3
test: depositByMember() 테스트 코드 작성
opixxx b1047d3
chore: 메서드 명 변경
opixxx 9326c08
chore: code smell 제거
opixxx f936b3c
chore: code smell 제거
opixxx 4415d67
chore: code smell 제거
opixxx File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
14 changes: 10 additions & 4 deletions
14
src/main/java/org/c4marathon/assignment/account/dto/WithdrawRequest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,14 +1,20 @@ | ||
package org.c4marathon.assignment.account.dto; | ||
|
||
import org.c4marathon.assignment.transaction.domain.TransactionType; | ||
|
||
import jakarta.validation.constraints.NotNull; | ||
import jakarta.validation.constraints.PositiveOrZero; | ||
|
||
public record WithdrawRequest( | ||
|
||
@NotNull | ||
Long receiverAccountId, | ||
@NotNull | ||
Long receiverAccountId, | ||
|
||
@PositiveOrZero | ||
long money, | ||
|
||
@NotNull | ||
TransactionType type | ||
|
||
@PositiveOrZero | ||
long money | ||
) { | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,11 @@ | ||
package org.c4marathon.assignment.account.service; | ||
|
||
import static org.c4marathon.assignment.global.util.Const.*; | ||
import static org.c4marathon.assignment.transaction.domain.TransactionStatus.*; | ||
import static org.c4marathon.assignment.transaction.domain.TransactionStatus.PENDING_DEPOSIT; | ||
import static org.c4marathon.assignment.transaction.domain.TransactionType.*; | ||
|
||
import java.util.UUID; | ||
import java.time.LocalDateTime; | ||
|
||
import org.c4marathon.assignment.account.domain.Account; | ||
import org.c4marathon.assignment.account.domain.SavingAccount; | ||
|
@@ -11,10 +14,15 @@ | |
import org.c4marathon.assignment.account.dto.WithdrawRequest; | ||
import org.c4marathon.assignment.account.exception.DailyChargeLimitExceededException; | ||
import org.c4marathon.assignment.account.exception.NotFoundAccountException; | ||
import org.c4marathon.assignment.global.event.withdraw.WithdrawCompletedEvent; | ||
import org.c4marathon.assignment.global.event.transactional.TransactionCreateEvent; | ||
import org.c4marathon.assignment.member.domain.Member; | ||
import org.c4marathon.assignment.member.domain.repository.MemberRepository; | ||
import org.c4marathon.assignment.member.exception.NotFoundMemberException; | ||
import org.c4marathon.assignment.transaction.domain.Transaction; | ||
import org.c4marathon.assignment.transaction.domain.repository.TransactionRepository; | ||
import org.c4marathon.assignment.transaction.exception.InvalidTransactionStatusException; | ||
import org.c4marathon.assignment.transaction.exception.NotFoundTransactionException; | ||
import org.c4marathon.assignment.transaction.exception.UnauthorizedTransactionException; | ||
import org.springframework.context.ApplicationEventPublisher; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.transaction.annotation.Isolation; | ||
|
@@ -27,7 +35,9 @@ | |
public class AccountService { | ||
private final AccountRepository accountRepository; | ||
private final MemberRepository memberRepository; | ||
private final TransactionRepository transactionRepository; | ||
private final SavingAccountRepository savingAccountRepository; | ||
|
||
private final ApplicationEventPublisher eventPublisher; | ||
|
||
@Transactional | ||
|
@@ -82,7 +92,8 @@ public void sendToSavingAccount(Long accountId, Long savingAccountId, long money | |
} | ||
|
||
/** | ||
* 출금 시 Redis List 에 출금 기록을 저장 | ||
* 송금 시 송금 내역을 저장하는 이벤트 발행 후 커밋 | ||
* | ||
* @param senderAccountId | ||
* @param request | ||
*/ | ||
|
@@ -98,18 +109,71 @@ public void withdraw(Long senderAccountId, WithdrawRequest request) { | |
senderAccount.withdraw(request.money()); | ||
accountRepository.save(senderAccount); | ||
|
||
String transactionId = UUID.randomUUID().toString(); | ||
if (request.type().equals(IMMEDIATE_TRANSFER)) { | ||
eventPublisher.publishEvent( | ||
new TransactionCreateEvent( | ||
senderAccountId, | ||
request.receiverAccountId(), | ||
request.money(), | ||
request.type(), | ||
WITHDRAW, | ||
LocalDateTime.now() | ||
) | ||
); | ||
} else if (request.type().equals(PENDING_TRANSFER)) { | ||
eventPublisher.publishEvent( | ||
new TransactionCreateEvent( | ||
senderAccountId, | ||
request.receiverAccountId(), | ||
request.money(), | ||
request.type(), | ||
PENDING_DEPOSIT, | ||
LocalDateTime.now() | ||
) | ||
); | ||
} | ||
} | ||
|
||
/** | ||
* 송금 취소 기능(사용자가 직접 취소 요청) | ||
* 취소하려는 송금 내역을 가져와 검증 후 송금을 취소함 | ||
* | ||
* @param senderAccountId | ||
* @param transactionalId | ||
*/ | ||
@Transactional(isolation = Isolation.READ_COMMITTED) | ||
public void cancelWithdraw(Long senderAccountId, Long transactionalId) { | ||
Transaction transaction = transactionRepository.findTransactionalByTransactionIdWithLock(transactionalId) | ||
.orElseThrow(NotFoundTransactionException::new); | ||
|
||
validationTransactional(senderAccountId, transaction); | ||
|
||
eventPublisher.publishEvent( | ||
new WithdrawCompletedEvent( | ||
transactionId, | ||
senderAccountId, | ||
request.receiverAccountId(), | ||
request.money() | ||
) | ||
); | ||
Account senderAccount = accountRepository.findByIdWithLock(senderAccountId) | ||
.orElseThrow(NotFoundAccountException::new); | ||
|
||
senderAccount.deposit(transaction.getAmount()); | ||
transaction.updateStatus(CANCEL); | ||
} | ||
|
||
/** | ||
* 72시간이 지난 송금 내역을 취소하는 비즈니스 로직 | ||
* | ||
* @param transaction | ||
*/ | ||
public void cancelWithdrawByExpirationTime(Transaction transaction) { | ||
Account senderAccount = accountRepository.findByIdWithLock(transaction.getSenderAccountId()) | ||
.orElseThrow(NotFoundAccountException::new); | ||
|
||
senderAccount.deposit(transaction.getAmount()); | ||
transaction.updateStatus(CANCEL); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 스케줄러에 의해 72시간이 지난 송금 내역이 취소되기 전, 동시에 사용자가 송금을 받는다면 어떻게 되나요? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 동시성 문제를 고려해서 현재 입출금 관련해서 Transaction 테이블을 조회해올때 DB단에 락을 걸어 조회합니다 |
||
} | ||
|
||
/** | ||
* 입금 재시도가 실패하면 송금 롤백을 하는 로직 | ||
* | ||
* @param senderAccountId | ||
* @param money | ||
*/ | ||
@Transactional(isolation = Isolation.READ_COMMITTED) | ||
public void rollbackWithdraw(Long senderAccountId, long money) { | ||
Account senderAccount = accountRepository.findByIdWithLock(senderAccountId) | ||
|
@@ -121,6 +185,7 @@ public void rollbackWithdraw(Long senderAccountId, long money) { | |
|
||
/** | ||
* 송금할 때 메인 계좌에 잔액이 부족할 때 10,000원 단위로 충전하는 로직 | ||
* | ||
* @param money | ||
* @param senderAccount | ||
*/ | ||
|
@@ -136,4 +201,14 @@ private void autoCharge(long money, Account senderAccount) { | |
senderAccount.deposit(chargeMoney); | ||
} | ||
|
||
private static void validationTransactional(Long senderAccountId, Transaction transaction) { | ||
if (!transaction.getSenderAccountId().equals(senderAccountId)) { | ||
throw new UnauthorizedTransactionException(); | ||
} | ||
|
||
if (!transaction.getStatus().equals(PENDING_DEPOSIT)) { | ||
throw new InvalidTransactionStatusException(); | ||
} | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
존재하지 않는 receiverAccountId에 대한 유효성 검증 로직이 따로 없는 것 같아서 고려해보면 좋을 것 같습니다.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
네. 한 번 유효성 검증을 통해 넣어야겠네요. step5 에 추가해놓겠습니다!