diff --git a/src/main/java/com/eum/bank/common/dto/request/AccountTransferHistoryRequestDTO.java b/src/main/java/com/eum/bank/common/dto/request/AccountTransferHistoryRequestDTO.java new file mode 100644 index 0000000..54a7ebe --- /dev/null +++ b/src/main/java/com/eum/bank/common/dto/request/AccountTransferHistoryRequestDTO.java @@ -0,0 +1,41 @@ +package com.eum.bank.common.dto.request; + +import com.eum.bank.domain.account.entity.Account; +import com.eum.bank.domain.account.entity.AccountTransferHistory; +import jakarta.validation.constraints.NotEmpty; +import lombok.Builder; +import lombok.Getter; + +public class AccountTransferHistoryRequestDTO { + + // 내역 생성 + @Getter + @Builder + public static class CreateAccountTransferHistory { + @NotEmpty(message = "거래 내역을 생성할 계좌를 입력해주세요.") + private Account ownerAccount; + @NotEmpty(message = "거래 상대 계좌를 입력해주세요.") + private Account oppenentAccount; + @NotEmpty(message = "거래 금액을 입력해주세요.") + private Long transferAmount; + @NotEmpty(message = "거래 유형을 입력해주세요.") + private String transferType; + @NotEmpty(message = "거래 후 잔액을 입력해주세요.") + private Long budgetAfterTransfer; + @NotEmpty(message = "거래 메모를 입력해주세요.") + private String memo; + + // toEntity + public AccountTransferHistory toEntity() { + return AccountTransferHistory.builder() + .ownerAccount(ownerAccount) + .oppenentAccount(oppenentAccount) + .transferAmount(transferAmount) + .transferType(transferType) + .budgetAfterTransfer(budgetAfterTransfer) + .memo(memo) + .build(); + } + } + +} diff --git a/src/main/java/com/eum/bank/common/dto/request/TotalTransferHistoryRequestDTO.java b/src/main/java/com/eum/bank/common/dto/request/TotalTransferHistoryRequestDTO.java new file mode 100644 index 0000000..e08f89d --- /dev/null +++ b/src/main/java/com/eum/bank/common/dto/request/TotalTransferHistoryRequestDTO.java @@ -0,0 +1,33 @@ +package com.eum.bank.common.dto.request; + +import com.eum.bank.domain.account.entity.Account; +import com.eum.bank.domain.account.entity.TotalTransferHistory; +import jakarta.validation.constraints.NotEmpty; +import lombok.Builder; +import lombok.Getter; + +public class TotalTransferHistoryRequestDTO { + + @Getter + @Builder + public static class CreateTotalTransferHistory { + @NotEmpty(message = "송금자 계좌를 입력해주세요.") + private Account senderAccount; + @NotEmpty(message = "수취자 계좌를 입력해주세요.") + private Account receiverAccount; + @NotEmpty(message = "송금 금액을 입력해주세요.") + private Long transferAmount; + @NotEmpty(message = "거래유형을 입력해주세요.") + private String transferType; + + // toEntity + public TotalTransferHistory toEntity() { + return TotalTransferHistory.builder() + .senderAccount(senderAccount) + .receiverAccount(receiverAccount) + .transferAmount(transferAmount) + .transferType(transferType) + .build(); + } + } +} diff --git a/src/main/java/com/eum/bank/common/dto/response/AccountResponseDTO.java b/src/main/java/com/eum/bank/common/dto/response/AccountResponseDTO.java index c2a4d92..5732d2a 100644 --- a/src/main/java/com/eum/bank/common/dto/response/AccountResponseDTO.java +++ b/src/main/java/com/eum/bank/common/dto/response/AccountResponseDTO.java @@ -1,5 +1,6 @@ package com.eum.bank.common.dto.response; +import com.eum.bank.domain.account.entity.Account; import jakarta.validation.constraints.NotEmpty; import lombok.Builder; import lombok.Getter; @@ -20,5 +21,14 @@ public static class AccountInfo { private String accountNumber; private Long totalBudget; private Long availableBudget; + + // fromEntity + public static AccountInfo fromEntity(Account account) { + return AccountInfo.builder() + .accountNumber(account.getAccountNumber()) + .totalBudget(account.getTotalBudget()) + .availableBudget(account.getAvailableBudget()) + .build(); + } } } diff --git a/src/main/java/com/eum/bank/common/dto/response/TotalTransferHistoryResponseDTO.java b/src/main/java/com/eum/bank/common/dto/response/TotalTransferHistoryResponseDTO.java new file mode 100644 index 0000000..ad88629 --- /dev/null +++ b/src/main/java/com/eum/bank/common/dto/response/TotalTransferHistoryResponseDTO.java @@ -0,0 +1,30 @@ +package com.eum.bank.common.dto.response; + +import com.eum.bank.domain.account.entity.TotalTransferHistory; +import lombok.Builder; +import lombok.Getter; + +public class TotalTransferHistoryResponseDTO { + + // 거래 내역 반환 + @Builder + @Getter + public static class GetTotalTransferHistory { + private Long id; + private AccountResponseDTO.AccountInfo senderAccount; + private AccountResponseDTO.AccountInfo receiverAccount; + private Long transferAmount; + private String transferType; + + // fromEntity + public static GetTotalTransferHistory fromEntity(TotalTransferHistory totalTransferHistory) { + return GetTotalTransferHistory.builder() + .id(totalTransferHistory.getId()) + .senderAccount(AccountResponseDTO.AccountInfo.fromEntity(totalTransferHistory.getSenderAccount())) + .receiverAccount(AccountResponseDTO.AccountInfo.fromEntity(totalTransferHistory.getReceiverAccount())) + .transferAmount(totalTransferHistory.getTransferAmount()) + .transferType(totalTransferHistory.getTransferType()) + .build(); + } + } +} diff --git a/src/main/java/com/eum/bank/service/AccountService.java b/src/main/java/com/eum/bank/service/AccountService.java index 49c6dbb..a870c3d 100644 --- a/src/main/java/com/eum/bank/service/AccountService.java +++ b/src/main/java/com/eum/bank/service/AccountService.java @@ -2,11 +2,16 @@ import com.eum.bank.common.APIResponse; import com.eum.bank.common.ErrorResponse; +import com.eum.bank.common.dto.request.AccountTransferHistoryRequestDTO; +import com.eum.bank.common.dto.request.TotalTransferHistoryRequestDTO; import com.eum.bank.common.dto.response.AccountResponseDTO; import com.eum.bank.common.enums.ErrorCode; import com.eum.bank.common.enums.SuccessCode; import com.eum.bank.domain.account.entity.Account; +import com.eum.bank.domain.account.entity.AccountTransferHistory; +import com.eum.bank.domain.account.entity.TotalTransferHistory; import com.eum.bank.repository.AccountRepository; +import jakarta.transaction.Transactional; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @@ -19,6 +24,9 @@ public class AccountService { private final AccountRepository accountRepository; private final PasswordEncoder passwordEncoder; + private final AccountTransferHistoryService accountTransferHistoryService; + private final TotalTransferHistoryService totalTransferHistoryService; + public APIResponse createAccount(Long password) { @@ -87,6 +95,69 @@ public APIResponse getAccount(String accountNumb .build()); } + // 자유송금 + // 1. 송금자 계좌, 수신자 계좌 상태 검증 + // 2. 송금자 잔액 확인 + // 3. 송금자 전체금액, 가용금액 마이너스 + // 4. 수신자 전체금액, 가용금액 플러스 + // 5. 통합 거래내역 생성, 각 계좌 거래내역 생성 + @Transactional + public APIResponse transfer(String senderAccountNumber, String receiverAccountNumber, Long amount, String password, String transferType) { + Account senderAccount = accountRepository.findByAccountNumber(senderAccountNumber).orElseThrow(() -> new IllegalArgumentException("Invalid account number")); + Account receiverAccount = accountRepository.findByAccountNumber(receiverAccountNumber).orElseThrow(() -> new IllegalArgumentException("Invalid account number")); + + // 비밀번호 검증 + if (!passwordEncoder.matches(password, senderAccount.getPassword())) { + throw new IllegalArgumentException("Invalid password"); + } + + // 송금자 잔액 검증 + if (senderAccount.getAvailableBudget() < amount) { + throw new IllegalArgumentException("Insufficient balance"); + } + + // 송금자 잔액 마이너스 + senderAccount.setTotalBudget(senderAccount.getTotalBudget() - amount); + senderAccount.setAvailableBudget(senderAccount.getAvailableBudget() - amount); + // 수신자 잔액 플러스 + receiverAccount.setTotalBudget(receiverAccount.getTotalBudget() + amount); + receiverAccount.setAvailableBudget(receiverAccount.getAvailableBudget() + amount); + + // 통합 거래내역 생성 + TotalTransferHistory response = totalTransferHistoryService.save( + TotalTransferHistoryRequestDTO.CreateTotalTransferHistory.builder() + .senderAccount(senderAccount) + .receiverAccount(receiverAccount) + .transferAmount(amount) + .transferType(transferType) + .build() + ); + + // 각 계좌 거래내역 생성 + accountTransferHistoryService.save( + AccountTransferHistoryRequestDTO.CreateAccountTransferHistory.builder() + .ownerAccount(senderAccount) + .oppenentAccount(receiverAccount) + .transferAmount(amount) + .transferType(transferType) + .budgetAfterTransfer(senderAccount.getAvailableBudget()) + .memo("") + .build() + ); + accountTransferHistoryService.save( + AccountTransferHistoryRequestDTO.CreateAccountTransferHistory.builder() + .ownerAccount(receiverAccount) + .oppenentAccount(senderAccount) + .transferAmount(-amount) + .transferType(transferType) + .budgetAfterTransfer(receiverAccount.getAvailableBudget()) + .memo("") + .build() + ); + + return APIResponse.of(SuccessCode.INSERT_SUCCESS, response); + } + } diff --git a/src/main/java/com/eum/bank/service/AccountTransferHistoryService.java b/src/main/java/com/eum/bank/service/AccountTransferHistoryService.java new file mode 100644 index 0000000..4d08da5 --- /dev/null +++ b/src/main/java/com/eum/bank/service/AccountTransferHistoryService.java @@ -0,0 +1,19 @@ +package com.eum.bank.service; + +import com.eum.bank.common.dto.request.AccountTransferHistoryRequestDTO; +import com.eum.bank.domain.account.entity.AccountTransferHistory; +import com.eum.bank.repository.AccountTransferHistoryRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class AccountTransferHistoryService { + + private final AccountTransferHistoryRepository accountTransferHistoryRepository; + + // 저장 + public AccountTransferHistory save(AccountTransferHistoryRequestDTO.CreateAccountTransferHistory dto) { + return accountTransferHistoryRepository.save(dto.toEntity()); + } +} diff --git a/src/main/java/com/eum/bank/service/TotalTransferHistoryService.java b/src/main/java/com/eum/bank/service/TotalTransferHistoryService.java new file mode 100644 index 0000000..9dcb728 --- /dev/null +++ b/src/main/java/com/eum/bank/service/TotalTransferHistoryService.java @@ -0,0 +1,17 @@ +package com.eum.bank.service; + +import com.eum.bank.common.dto.request.TotalTransferHistoryRequestDTO; +import com.eum.bank.domain.account.entity.TotalTransferHistory; +import com.eum.bank.repository.TotalTransferHistoryRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class TotalTransferHistoryService { + private final TotalTransferHistoryRepository totalTransferHistoryRepository; + + public TotalTransferHistory save(TotalTransferHistoryRequestDTO.CreateTotalTransferHistory dto) { + return totalTransferHistoryRepository.save(dto.toEntity()); + } +}