From cfcc46f873fc3f0ee729f8106ef1d4024a9b36d2 Mon Sep 17 00:00:00 2001 From: jykim-rust Date: Mon, 29 Jan 2024 18:01:42 +0900 Subject: [PATCH 1/6] =?UTF-8?q?:adhesive=5Fbandage:=20#19=20Account?= =?UTF-8?q?=EC=97=90=20isBlocked=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/eum/bank/common/dto/response/AccountResponseDTO.java | 2 ++ src/main/java/com/eum/bank/domain/account/entity/Account.java | 4 ++++ 2 files changed, 6 insertions(+) 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 5732d2a..ad2b83e 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 @@ -21,6 +21,7 @@ public static class AccountInfo { private String accountNumber; private Long totalBudget; private Long availableBudget; + private Boolean isBlocked; // fromEntity public static AccountInfo fromEntity(Account account) { @@ -28,6 +29,7 @@ public static AccountInfo fromEntity(Account account) { .accountNumber(account.getAccountNumber()) .totalBudget(account.getTotalBudget()) .availableBudget(account.getAvailableBudget()) + .isBlocked(account.getIsBlocked()) .build(); } } diff --git a/src/main/java/com/eum/bank/domain/account/entity/Account.java b/src/main/java/com/eum/bank/domain/account/entity/Account.java index ecbf1ef..bf8e7f9 100644 --- a/src/main/java/com/eum/bank/domain/account/entity/Account.java +++ b/src/main/java/com/eum/bank/domain/account/entity/Account.java @@ -30,4 +30,8 @@ public class Account extends BaseEntity { // 계좌 사용 가능 잔액 @Column(name = "available_budget", nullable = false) private Long availableBudget; + + // 블락 여부 + @Column(name = "is_blocked", nullable = false) + private Boolean isBlocked; } From a7aac0a1f94552811fc3fc03218e13bc15eeb0c3 Mon Sep 17 00:00:00 2001 From: jykim-rust Date: Mon, 29 Jan 2024 18:02:24 +0900 Subject: [PATCH 2/6] =?UTF-8?q?:sparkles:=20#19=20=EA=B3=84=EC=A2=8C?= =?UTF-8?q?=EB=A5=BC=20=EC=A1=B4=EC=9E=AC=EC=97=AC=EB=B6=80=20+=20?= =?UTF-8?q?=EB=B8=94=EB=9D=BD=EC=97=AC=EB=B6=80=EB=A1=9C=20=EA=B2=80?= =?UTF-8?q?=EC=A6=9D=20=ED=9B=84=20=EB=B0=9B=EC=95=84=EC=98=A4=EB=8A=94=20?= =?UTF-8?q?validateAccount=EB=A9=94=EC=86=8C=EB=93=9C=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/eum/bank/service/AccountService.java | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/eum/bank/service/AccountService.java b/src/main/java/com/eum/bank/service/AccountService.java index cf2e919..b082eca 100644 --- a/src/main/java/com/eum/bank/service/AccountService.java +++ b/src/main/java/com/eum/bank/service/AccountService.java @@ -42,6 +42,7 @@ public APIResponse createAccount(String password) { .password(passwordEncoder.encode(password)) .totalBudget(0L) .availableBudget(0L) + .isBlocked(false) .build(); accountRepository.save(account); @@ -77,9 +78,18 @@ public Boolean validateAccountNumber(String accountNumber) { return true; } + // 계좌 검증 (계좌 존재여부 + 블락 여부) + public Account validateAccount(String accountNumber) { + Account account = accountRepository.findByAccountNumber(accountNumber).orElseThrow(() -> new IllegalArgumentException("Invalid account number : " + accountNumber)); + if(account.getIsBlocked()){ + throw new IllegalArgumentException("Blocked account : " + accountNumber); + } + return account; + } + // 계좌번호와 비밀번호로 계좌 조회 public APIResponse getAccount(String accountNumber, String password) { - Account account = accountRepository.findByAccountNumber(accountNumber).orElseThrow(() -> new IllegalArgumentException("Invalid account number")); + Account account = this.validateAccount(accountNumber); // 비밀번호 검증 if (!passwordEncoder.matches(password, account.getPassword())) { @@ -100,8 +110,8 @@ public APIResponse getAccount(String accountNumb // 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")); + Account senderAccount = this.validateAccount(senderAccountNumber); + Account receiverAccount = this.validateAccount(receiverAccountNumber); // 비밀번호 검증 if (!passwordEncoder.matches(password, senderAccount.getPassword())) { From 42d89433fc2eab91720f1854d94e0e285804acc9 Mon Sep 17 00:00:00 2001 From: jykim-rust Date: Mon, 29 Jan 2024 19:32:14 +0900 Subject: [PATCH 3/6] =?UTF-8?q?:sparkles:=20#19=20=EA=B1=B0=EB=9E=98=20?= =?UTF-8?q?=EC=84=B1=EC=82=AC=20=EB=A1=9C=EC=A7=81=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/dto/request/DealRequestDTO.java | 20 +++++ .../com/eum/bank/service/DealService.java | 76 +++++++++++++++++++ 2 files changed, 96 insertions(+) create mode 100644 src/main/java/com/eum/bank/common/dto/request/DealRequestDTO.java create mode 100644 src/main/java/com/eum/bank/service/DealService.java diff --git a/src/main/java/com/eum/bank/common/dto/request/DealRequestDTO.java b/src/main/java/com/eum/bank/common/dto/request/DealRequestDTO.java new file mode 100644 index 0000000..b8ee3ae --- /dev/null +++ b/src/main/java/com/eum/bank/common/dto/request/DealRequestDTO.java @@ -0,0 +1,20 @@ +package com.eum.bank.common.dto.request; + +import jakarta.validation.constraints.NotEmpty; +import lombok.Getter; + +public class DealRequestDTO { + + @Getter + public static class completeDeal{ + // 거래ID + @NotEmpty(message = "거래ID를 입력해주세요.") + private Long dealId; + // 예치금 + @NotEmpty(message = "예치금을 입력해주세요.") + private Long deposit; + // 수신 계좌번호 리스트 + @NotEmpty(message = "수신 계좌번호를 입력해주세요.") + private String[] receiverAccountNumbers; + } +} diff --git a/src/main/java/com/eum/bank/service/DealService.java b/src/main/java/com/eum/bank/service/DealService.java new file mode 100644 index 0000000..0ba04f3 --- /dev/null +++ b/src/main/java/com/eum/bank/service/DealService.java @@ -0,0 +1,76 @@ +package com.eum.bank.service; + +import com.eum.bank.common.APIResponse; +import com.eum.bank.common.dto.request.DealRequestDTO; +import com.eum.bank.common.enums.SuccessCode; +import com.eum.bank.domain.account.entity.Account; +import com.eum.bank.domain.deal.entity.Deal; +import com.eum.bank.domain.deal.entity.DealReceiver; +import com.eum.bank.repository.DealReceiverRepository; +import com.eum.bank.repository.DealRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +@Service +@RequiredArgsConstructor +public class DealService { + + private final DealRepository dealRepository; + private final AccountService accountService; + private final DealReceiverRepository dealReceiverRepository; + + + // 거래 성사 + // 1. 거래상태 a인지 확인 + // 2. 수신계좌들 검증 + // 3. 최종 예치금 확인해서 차액만큼 가용금액 플러스 + // 4. 수신자 계좌번호 거래에 묶기 + // 5. 거래상태 b로 변경 + // 6. 거래ID 반환 + @Transactional + public APIResponse completeDeal(DealRequestDTO.completeDeal dto) { + // 거래 검증 및 거래 상태 a 인지 검증 + Deal deal = this.validateDeal(dto.getDealId(), List.of("a")); + + List receiverAccountNumbers = List.of(dto.getReceiverAccountNumbers()); + + // 송신계좌 검증 및 잔액 확인 + // 최종 예치금 - 기존 거래의 예치금 만큼 송신자 계좌의 가용금액을 마이너스 + Account senderAccount = accountService.validateAccount(deal.getSenderAccount().getAccountNumber()); + Long finalDeposit = dto.getDeposit() - deal.getDeposit(); + if (senderAccount.getAvailableBudget() < finalDeposit) { + throw new IllegalArgumentException("잔액이 부족합니다."); + } + senderAccount.setAvailableBudget(senderAccount.getAvailableBudget() - finalDeposit); + + // 수신자 계좌번호 검증하면서 DealReceiver로 만들어서 저장 + for (String receiverAccountNumber : receiverAccountNumbers) { + dealReceiverRepository.save( + DealReceiver.builder() + .deal(deal) + .receiverAccount(accountService.validateAccount(receiverAccountNumber)) + .build() + ); + } + + // 거래상태 b로 변경 + deal.setStatus("b"); + + return APIResponse.of(SuccessCode.INSERT_SUCCESS, dealRepository.save(deal).getId()); + } + + // 거래ID로 존재여부 + 거래상태 검증 + private Deal validateDeal(Long dealId, List status) { + Deal deal = dealRepository.findById(dealId) + .orElseThrow(() -> new IllegalArgumentException("존재하지 않는 거래입니다.")); + + if (!status.contains(deal.getStatus())) { + throw new IllegalArgumentException("거래 상태가 올바르지 않습니다."); + } + + return deal; + } +} From 335fb9211b61a40f735c4ddf7bd0f10d7192ad4c Mon Sep 17 00:00:00 2001 From: jykim-rust Date: Tue, 30 Jan 2024 15:09:16 +0900 Subject: [PATCH 4/6] =?UTF-8?q?:sparkles:=20#22=20=EA=B1=B0=EB=9E=98=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20=EB=A1=9C=EC=A7=81=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/dto/request/DealRequestDTO.java | 20 ++++++++ .../repository/DealReceiverRepository.java | 2 + .../com/eum/bank/service/DealService.java | 49 +++++++++++++++++++ 3 files changed, 71 insertions(+) diff --git a/src/main/java/com/eum/bank/common/dto/request/DealRequestDTO.java b/src/main/java/com/eum/bank/common/dto/request/DealRequestDTO.java index b8ee3ae..b39ff95 100644 --- a/src/main/java/com/eum/bank/common/dto/request/DealRequestDTO.java +++ b/src/main/java/com/eum/bank/common/dto/request/DealRequestDTO.java @@ -17,4 +17,24 @@ public static class completeDeal{ @NotEmpty(message = "수신 계좌번호를 입력해주세요.") private String[] receiverAccountNumbers; } + + + @Getter + public static class updateDeal{ + // 거래ID + @NotEmpty(message = "거래ID를 입력해주세요.") + private Long dealId; + // 송금자 계좌번호 + @NotEmpty(message = "송금자 계좌번호를 입력해주세요.") + private String senderAccountNumber; + // 비밀번호 + @NotEmpty(message = "비밀번호를 입력해주세요.") + private String password; + // 예치금 + @NotEmpty(message = "예치금을 입력해주세요.") + private Long deposit; + // 최대인원수 + @NotEmpty(message = "최대인원수를 입력해주세요.") + private Long numberOfPeople; + } } diff --git a/src/main/java/com/eum/bank/repository/DealReceiverRepository.java b/src/main/java/com/eum/bank/repository/DealReceiverRepository.java index 62d8f16..4c44dc2 100644 --- a/src/main/java/com/eum/bank/repository/DealReceiverRepository.java +++ b/src/main/java/com/eum/bank/repository/DealReceiverRepository.java @@ -1,7 +1,9 @@ package com.eum.bank.repository; +import com.eum.bank.domain.deal.entity.Deal; import com.eum.bank.domain.deal.entity.DealReceiver; import org.springframework.data.jpa.repository.JpaRepository; public interface DealReceiverRepository extends JpaRepository { + void deleteByDeal(Deal deal); } \ No newline at end of file diff --git a/src/main/java/com/eum/bank/service/DealService.java b/src/main/java/com/eum/bank/service/DealService.java index 0ba04f3..8fde19d 100644 --- a/src/main/java/com/eum/bank/service/DealService.java +++ b/src/main/java/com/eum/bank/service/DealService.java @@ -9,6 +9,7 @@ import com.eum.bank.repository.DealReceiverRepository; import com.eum.bank.repository.DealRepository; import lombok.RequiredArgsConstructor; +import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -21,6 +22,7 @@ public class DealService { private final DealRepository dealRepository; private final AccountService accountService; private final DealReceiverRepository dealReceiverRepository; + private final PasswordEncoder passwordEncoder; // 거래 성사 @@ -45,6 +47,7 @@ public APIResponse completeDeal(DealRequestDTO.completeDeal dto) { throw new IllegalArgumentException("잔액이 부족합니다."); } senderAccount.setAvailableBudget(senderAccount.getAvailableBudget() - finalDeposit); + deal.setDeposit(dto.getDeposit()); // 수신자 계좌번호 검증하면서 DealReceiver로 만들어서 저장 for (String receiverAccountNumber : receiverAccountNumbers) { @@ -73,4 +76,50 @@ private Deal validateDeal(Long dealId, List status) { return deal; } + + // 거래 수정 + // 1. 거래 ID 확인 + // 2. 송금자 계좌 검증 + // 3. 비밀번호 검증 + // 4. 거래 상태 확인 + // 5. 예치금 수정 및 송신자 계좌에 가용금액 플러스 + // 6. 거래 인원수 수정 + // 7. b일 경우 dealReceiver 삭제 + // 8. 거래 상태 a로 변경 + // 9. 거래ID 반환 + @Transactional + public APIResponse updateDeal(DealRequestDTO.updateDeal dto) { + // 거래ID로 존재여부 + 거래상태 검증 + Deal deal = this.validateDeal(dto.getDealId(), List.of("a", "b")); + + // 송금자 계좌 검증 + Account senderAccount = accountService.validateAccount(dto.getSenderAccountNumber()); + + // 비밀번호 검증 + if (!passwordEncoder.matches(dto.getPassword(), senderAccount.getPassword())) { + throw new IllegalArgumentException("비밀번호가 올바르지 않습니다."); + } + + // 거래 상태 확인 + if (deal.getStatus().equals("b")) { + // 거래 상태가 b일 경우 dealReceiver 삭제 + dealReceiverRepository.deleteByDeal(deal); + } + + // 예치금 수정 및 송신자 계좌에 가용금액 마이너스 + Long finalDeposit = dto.getDeposit() - deal.getDeposit(); + if (senderAccount.getAvailableBudget() < finalDeposit) { + throw new IllegalArgumentException("잔액이 부족합니다."); + } + senderAccount.setAvailableBudget(senderAccount.getAvailableBudget() - finalDeposit); + deal.setDeposit(dto.getDeposit()); + + // 거래 인원수 수정 + deal.setNumberOfPeople(dto.getNumberOfPeople()); + + // 거래 상태 a로 변경 + deal.setStatus("a"); + + return APIResponse.of(SuccessCode.UPDATE_SUCCESS, dealRepository.save(deal).getId()); + } } From de8ae8f866e514e112f22f36ca7e94809bdea699 Mon Sep 17 00:00:00 2001 From: jykim-rust Date: Tue, 30 Jan 2024 15:20:29 +0900 Subject: [PATCH 5/6] =?UTF-8?q?:sparkles:=20#24=20=EA=B1=B0=EB=9E=98=20?= =?UTF-8?q?=EC=B7=A8=EC=86=8C=20=EB=A1=9C=EC=A7=81=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/dto/request/DealRequestDTO.java | 13 +++++++ .../com/eum/bank/service/DealService.java | 38 +++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/src/main/java/com/eum/bank/common/dto/request/DealRequestDTO.java b/src/main/java/com/eum/bank/common/dto/request/DealRequestDTO.java index b39ff95..037fedf 100644 --- a/src/main/java/com/eum/bank/common/dto/request/DealRequestDTO.java +++ b/src/main/java/com/eum/bank/common/dto/request/DealRequestDTO.java @@ -37,4 +37,17 @@ public static class updateDeal{ @NotEmpty(message = "최대인원수를 입력해주세요.") private Long numberOfPeople; } + + @Getter + public static class cancelDeal{ + // 거래ID + @NotEmpty(message = "거래ID를 입력해주세요.") + private Long dealId; + // 송금자 계좌번호 + @NotEmpty(message = "송금자 계좌번호를 입력해주세요.") + private String senderAccountNumber; + // 비밀번호 + @NotEmpty(message = "비밀번호를 입력해주세요.") + private String password; + } } diff --git a/src/main/java/com/eum/bank/service/DealService.java b/src/main/java/com/eum/bank/service/DealService.java index 8fde19d..81fe214 100644 --- a/src/main/java/com/eum/bank/service/DealService.java +++ b/src/main/java/com/eum/bank/service/DealService.java @@ -122,4 +122,42 @@ public APIResponse updateDeal(DealRequestDTO.updateDeal dto) { return APIResponse.of(SuccessCode.UPDATE_SUCCESS, dealRepository.save(deal).getId()); } + + // 거래 취소 + // 1. 거래 ID 확인 + // 2. 송금자 계좌 검증 + // 3. 비밀번호 검증 + // 4. 거래 상태 확인 + // 5. 거래 상태 b일 경우 dealReceiver 삭제 + // 6. 송신자 계좌에 가용금액 플러스 + // 7. 거래 상태 c로 변경 + // 8. 거래ID 반환 + @Transactional + public APIResponse cancelDeal(DealRequestDTO.cancelDeal dto) { + // 거래ID로 존재여부 + 거래상태 검증 + Deal deal = this.validateDeal(dto.getDealId(), List.of("a", "b")); + + // 송금자 계좌 검증 + Account senderAccount = accountService.validateAccount(dto.getSenderAccountNumber()); + + // 비밀번호 검증 + if (!passwordEncoder.matches(dto.getPassword(), senderAccount.getPassword())) { + throw new IllegalArgumentException("비밀번호가 올바르지 않습니다."); + } + + // 거래 상태 확인 + if (deal.getStatus().equals("b")) { + // 거래 상태가 b일 경우 dealReceiver 삭제 + // 근데 삭제해야 하나? + dealReceiverRepository.deleteByDeal(deal); + } + + // 송신자 계좌에 가용금액 플러스 + senderAccount.setAvailableBudget(senderAccount.getAvailableBudget() + deal.getDeposit()); + + // 거래 상태 c로 변경 + deal.setStatus("c"); + + return APIResponse.of(SuccessCode.DELETE_SUCCESS, dealRepository.save(deal).getId()); + } } From 3c283116718d35f7b49a02388c0e4b2f2ee6b620 Mon Sep 17 00:00:00 2001 From: jykim-rust Date: Tue, 30 Jan 2024 15:21:55 +0900 Subject: [PATCH 6/6] =?UTF-8?q?:speech=5Fballoon:=20#24=20=EA=B1=B0?= =?UTF-8?q?=EB=9E=98=20=EC=83=81=ED=83=9C=20=EC=A3=BC=EC=84=9D=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/eum/bank/domain/deal/entity/Deal.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/com/eum/bank/domain/deal/entity/Deal.java b/src/main/java/com/eum/bank/domain/deal/entity/Deal.java index 262a467..0ac9a26 100644 --- a/src/main/java/com/eum/bank/domain/deal/entity/Deal.java +++ b/src/main/java/com/eum/bank/domain/deal/entity/Deal.java @@ -23,6 +23,10 @@ public class Deal extends BaseEntity { private Account senderAccount; // 상태 + // a: 거래 생성 후 거래 성사 전 (수신계좌가 안엮인 상태) + // b: 거래 성사 후 (수신계좌가 엮인 상태) + // c: 거래 취소 됨 + // d: 거래 수행 됨 @Column(name = "status", nullable = false) private String status;