From 63117beb936b50daa08133955d7300da82b5c991 Mon Sep 17 00:00:00 2001 From: M-ung Date: Tue, 6 May 2025 15:43:09 +0900 Subject: [PATCH 1/4] =?UTF-8?q?Feat:=20=EC=9E=85=EC=B0=B0=20=EC=8B=9C,=20?= =?UTF-8?q?=EC=82=AC=EC=9A=A9=EC=9E=90=20=EB=B3=B4=EC=9C=A0=20=EA=B8=88?= =?UTF-8?q?=EC=95=A1=20=ED=99=95=EC=9D=B8=ED=95=98=EB=8A=94=20=EB=A9=94?= =?UTF-8?q?=EC=84=9C=EB=93=9C=20=EC=B6=94=EA=B0=80=ED=95=B4=EB=9D=BC=20-?= =?UTF-8?q?=20#142?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bid/application/BidCommandService.java | 18 ++++++++++++++---- .../bid/application/BidCommandServiceTest.java | 10 ++++++++++ .../src/main/java/tictoc/error/ErrorCode.java | 1 + .../java/tictoc/auction/model/Auction.java | 2 +- .../adapter/ProfileRepositoryAdapter.java | 7 ++++++- .../profile/port/ProfileRepositoryPort.java | 1 + .../profile/repository/ProfileRepository.java | 1 + 7 files changed, 34 insertions(+), 6 deletions(-) diff --git a/tictoc-api/src/main/java/tictoc/bid/application/BidCommandService.java b/tictoc-api/src/main/java/tictoc/bid/application/BidCommandService.java index 8b6586d..6dfc79b 100644 --- a/tictoc-api/src/main/java/tictoc/bid/application/BidCommandService.java +++ b/tictoc-api/src/main/java/tictoc/bid/application/BidCommandService.java @@ -4,6 +4,7 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import tictoc.annotation.DistributedLock; +import tictoc.auction.model.Auction; import tictoc.auction.port.AuctionRepositoryPort; import tictoc.bid.dto.request.BidUseCaseReqDTO; import tictoc.constants.RedisConstants; @@ -11,12 +12,15 @@ import tictoc.bid.model.Bid; import tictoc.bid.port.BidCommandUseCase; import tictoc.bid.port.BidRepositoryPort; +import tictoc.profile.port.ProfileRepositoryPort; import static tictoc.error.ErrorCode.BID_FAIL; +import static tictoc.error.ErrorCode.INVALID_PROFILE_MONEY; @Service @Transactional @RequiredArgsConstructor public class BidCommandService implements BidCommandUseCase { + private final ProfileRepositoryPort profileRepositoryPort; private final AuctionRepositoryPort auctionRepositoryPort; private final BidRepositoryPort bidRepositoryPort; @@ -24,11 +28,17 @@ public class BidCommandService implements BidCommandUseCase { @DistributedLock(key = "#requestDTO.auctionId", delayTime = RedisConstants.LOCK_LEASE_TIME) public void bid(final Long userId, BidUseCaseReqDTO.Bid requestDTO) { var findAuction = auctionRepositoryPort.findAuctionById(requestDTO.auctionId()); - bidRepositoryPort.checkBeforeBid(findAuction); - findAuction.startBid(userId); - Integer beforePrice = findAuction.getCurrentPrice(); + validateBid(userId, requestDTO.price(), findAuction); executeAtomicBidUpdate(requestDTO); - bidRepositoryPort.saveBid(Bid.of(userId, requestDTO, beforePrice)); + bidRepositoryPort.saveBid(Bid.of(userId, requestDTO, findAuction.getCurrentPrice())); + } + + private void validateBid(Long userId, Integer price, Auction auction) { + if (!profileRepositoryPort.checkMoney(userId, price)) { + throw new BidException(INVALID_PROFILE_MONEY); + } + bidRepositoryPort.checkBeforeBid(auction); + auction.checkAuction(userId); } private void executeAtomicBidUpdate(BidUseCaseReqDTO.Bid requestDTO) { diff --git a/tictoc-api/src/test/java/tictoc/bid/application/BidCommandServiceTest.java b/tictoc-api/src/test/java/tictoc/bid/application/BidCommandServiceTest.java index f7cbc16..2e65435 100644 --- a/tictoc-api/src/test/java/tictoc/bid/application/BidCommandServiceTest.java +++ b/tictoc-api/src/test/java/tictoc/bid/application/BidCommandServiceTest.java @@ -6,6 +6,7 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.junit.jupiter.SpringExtension; import tictoc.TicTocApiApplication; @@ -18,6 +19,8 @@ import tictoc.bid.port.BidCommandUseCase; import tictoc.bid.port.BidRepositoryPort; import tictoc.error.ErrorCode; +import tictoc.profile.port.ProfileRepositoryPort; + import java.time.LocalDateTime; import java.util.Collections; import java.util.concurrent.CountDownLatch; @@ -26,6 +29,9 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.Mockito.when; @ExtendWith(SpringExtension.class) @SpringBootTest(classes = TicTocApiApplication.class) @@ -38,6 +44,9 @@ public class BidCommandServiceTest { @Autowired private BidRepositoryPort bidRepositoryPort; + @MockBean + private ProfileRepositoryPort profileRepositoryPort; + private static final Integer BID_PRICE = 1500; private static final int NUM_USERS = 5000; private Auction auction; @@ -48,6 +57,7 @@ public void setup() { LocalDateTime sellStartTime = now.plusMinutes(10); LocalDateTime sellEndTime = now.plusHours(2); LocalDateTime auctionCloseTime = now.plusHours(3); + when(profileRepositoryPort.checkMoney(anyLong(), anyInt())).thenReturn(true); AuctionUseCaseReqDTO.Register requestDTO = new AuctionUseCaseReqDTO.Register( "Test Auction", diff --git a/tictoc-common/src/main/java/tictoc/error/ErrorCode.java b/tictoc-common/src/main/java/tictoc/error/ErrorCode.java index c942f87..7443d71 100644 --- a/tictoc-common/src/main/java/tictoc/error/ErrorCode.java +++ b/tictoc-common/src/main/java/tictoc/error/ErrorCode.java @@ -24,6 +24,7 @@ public enum ErrorCode { AUCTION_ALREADY_FINISHED(HttpStatus.BAD_REQUEST, "이미 경매가 종료되었습니다."), BID_NO_ACCESS(HttpStatus.FORBIDDEN,"입찰에 대한 접근 권한이 없습니다."), INVALID_BID_PRICE(HttpStatus.BAD_REQUEST,"현재 경매가보다 낮은 입찰가를 입력했습니다."), + INVALID_PROFILE_MONEY(HttpStatus.BAD_REQUEST,"현재 경매가보다 낮은 금액을 소유하고 있습니다."), BID_NOT_FOUND(HttpStatus.BAD_REQUEST,"찾을 수 없는 입찰입니다."), BID_FAIL(HttpStatus.BAD_REQUEST,"이미 입찰되었습니다."), diff --git a/tictoc-domain/src/main/java/tictoc/auction/model/Auction.java b/tictoc-domain/src/main/java/tictoc/auction/model/Auction.java index 840a851..a739b0d 100644 --- a/tictoc-domain/src/main/java/tictoc/auction/model/Auction.java +++ b/tictoc-domain/src/main/java/tictoc/auction/model/Auction.java @@ -99,7 +99,7 @@ private void validateAuctionAlreadyStarted() { } } - public void startBid(final Long userId) { + public void checkAuction(final Long userId) { this.validateAuctionTime(); this.validateBidAccess(userId); this.validateAuctionProgress(); diff --git a/tictoc-domain/src/main/java/tictoc/profile/adapter/ProfileRepositoryAdapter.java b/tictoc-domain/src/main/java/tictoc/profile/adapter/ProfileRepositoryAdapter.java index a577c3d..87f4658 100644 --- a/tictoc-domain/src/main/java/tictoc/profile/adapter/ProfileRepositoryAdapter.java +++ b/tictoc-domain/src/main/java/tictoc/profile/adapter/ProfileRepositoryAdapter.java @@ -25,4 +25,9 @@ public Profile saveProfile(Profile profile) { public ProfileImage saveProfileImage(ProfileImage profileImage) { return profileImageRepository.save(profileImage); } -} + + @Override + public boolean checkMoney(Long userId, Integer price) { + return profileRepository.existsByUserIdAndMoneyGreaterThanEqual(userId, price); + } +} \ No newline at end of file diff --git a/tictoc-domain/src/main/java/tictoc/profile/port/ProfileRepositoryPort.java b/tictoc-domain/src/main/java/tictoc/profile/port/ProfileRepositoryPort.java index f636dd2..8165686 100644 --- a/tictoc-domain/src/main/java/tictoc/profile/port/ProfileRepositoryPort.java +++ b/tictoc-domain/src/main/java/tictoc/profile/port/ProfileRepositoryPort.java @@ -6,4 +6,5 @@ public interface ProfileRepositoryPort { Profile saveProfile(Profile profile); ProfileImage saveProfileImage(ProfileImage profileImage); + boolean checkMoney(Long userId, Integer price); } diff --git a/tictoc-domain/src/main/java/tictoc/profile/repository/ProfileRepository.java b/tictoc-domain/src/main/java/tictoc/profile/repository/ProfileRepository.java index fd8522a..4772376 100644 --- a/tictoc-domain/src/main/java/tictoc/profile/repository/ProfileRepository.java +++ b/tictoc-domain/src/main/java/tictoc/profile/repository/ProfileRepository.java @@ -4,4 +4,5 @@ import tictoc.profile.model.Profile; public interface ProfileRepository extends JpaRepository { + boolean existsByUserIdAndMoneyGreaterThanEqual(Long userId, Integer price); } From efd677211424bccf9d0e67307b28d10e47c2bff9 Mon Sep 17 00:00:00 2001 From: M-ung Date: Tue, 6 May 2025 15:45:50 +0900 Subject: [PATCH 2/4] =?UTF-8?q?Style:=20=EB=A9=94=EC=84=9C=EB=93=9C?= =?UTF-8?q?=EB=AA=85=20=EB=B3=80=EA=B2=BD=ED=95=B4=EB=9D=BC=20-=20#142?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/tictoc/bid/application/BidCommandService.java | 2 +- tictoc-domain/src/main/java/tictoc/auction/model/Auction.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tictoc-api/src/main/java/tictoc/bid/application/BidCommandService.java b/tictoc-api/src/main/java/tictoc/bid/application/BidCommandService.java index 6dfc79b..27389fe 100644 --- a/tictoc-api/src/main/java/tictoc/bid/application/BidCommandService.java +++ b/tictoc-api/src/main/java/tictoc/bid/application/BidCommandService.java @@ -38,7 +38,7 @@ private void validateBid(Long userId, Integer price, Auction auction) { throw new BidException(INVALID_PROFILE_MONEY); } bidRepositoryPort.checkBeforeBid(auction); - auction.checkAuction(userId); + auction.validateBeforeBid(userId); } private void executeAtomicBidUpdate(BidUseCaseReqDTO.Bid requestDTO) { diff --git a/tictoc-domain/src/main/java/tictoc/auction/model/Auction.java b/tictoc-domain/src/main/java/tictoc/auction/model/Auction.java index a739b0d..b424582 100644 --- a/tictoc-domain/src/main/java/tictoc/auction/model/Auction.java +++ b/tictoc-domain/src/main/java/tictoc/auction/model/Auction.java @@ -99,7 +99,7 @@ private void validateAuctionAlreadyStarted() { } } - public void checkAuction(final Long userId) { + public void validateBeforeBid(final Long userId) { this.validateAuctionTime(); this.validateBidAccess(userId); this.validateAuctionProgress(); From 7adb9cf3fcd961f37d8ab044cabba88d8c4861d5 Mon Sep 17 00:00:00 2001 From: M-ung Date: Tue, 6 May 2025 16:00:55 +0900 Subject: [PATCH 3/4] =?UTF-8?q?Feat:=20=EC=9E=85=EC=B0=B0=20=EC=8B=9C,=20?= =?UTF-8?q?=EB=B3=B4=EC=9C=A0=20=EA=B8=88=EC=95=A1=20=EB=A7=88=EC=9D=B4?= =?UTF-8?q?=EB=84=88=EC=8A=A4=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= =?UTF-8?q?=ED=95=B4=EB=9D=BC=20-=20#142?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/tictoc/error/ErrorCode.java | 1 + .../event/CloseAuctionEventListener.java | 29 ++++++++++++------- .../exception/CloseAuctionException.java | 10 +++++++ .../adapter/ProfileRepositoryAdapter.java | 15 ++++++++++ .../tictoc/profile/model/MoneyHistory.java | 2 +- .../profile/port/ProfileRepositoryPort.java | 1 + .../profile/repository/ProfileRepository.java | 6 ++++ 7 files changed, 52 insertions(+), 12 deletions(-) create mode 100644 tictoc-domain/src/main/java/tictoc/auction/exception/CloseAuctionException.java diff --git a/tictoc-common/src/main/java/tictoc/error/ErrorCode.java b/tictoc-common/src/main/java/tictoc/error/ErrorCode.java index 7443d71..5a4e1e9 100644 --- a/tictoc-common/src/main/java/tictoc/error/ErrorCode.java +++ b/tictoc-common/src/main/java/tictoc/error/ErrorCode.java @@ -19,6 +19,7 @@ public enum ErrorCode { CONFLICT_AUCTION_DELETE(HttpStatus.BAD_REQUEST,"경매 삭제가 충돌나서 할 수 없습니다."), AUCTION_TIME_OVER(HttpStatus.BAD_REQUEST,"경매 시간이 종료되었습니다."), INVALID_AUCTION_TIME_RANGE(HttpStatus.BAD_REQUEST,"sellStartTime은 sellEndTime보다 이전이어야 합니다."), + CLOSE_AUCTION_ERROR(HttpStatus.BAD_REQUEST,"경매 종료 실패입니다. (찾을 수 없는 사용거나 보유 금액이 적습니다.)"), // Bid AUCTION_ALREADY_FINISHED(HttpStatus.BAD_REQUEST, "이미 경매가 종료되었습니다."), diff --git a/tictoc-domain/src/main/java/tictoc/auction/event/CloseAuctionEventListener.java b/tictoc-domain/src/main/java/tictoc/auction/event/CloseAuctionEventListener.java index 9894aca..6332963 100644 --- a/tictoc-domain/src/main/java/tictoc/auction/event/CloseAuctionEventListener.java +++ b/tictoc-domain/src/main/java/tictoc/auction/event/CloseAuctionEventListener.java @@ -12,6 +12,7 @@ import tictoc.bid.port.BidRepositoryPort; import tictoc.bid.port.WinningBidRepositoryPort; import tictoc.constants.RedisConstants; +import tictoc.profile.port.ProfileRepositoryPort; import tictoc.redis.auction.port.out.CloseAuctionUseCase; import tictoc.user.model.UserSchedule; import tictoc.user.port.UserScheduleRepositoryPort; @@ -20,6 +21,7 @@ @Event("Listener") @RequiredArgsConstructor public class CloseAuctionEventListener implements MessageListener { + private final ProfileRepositoryPort profileRepositoryPort; private final AuctionRepositoryPort auctionRepositoryPort; private final BidRepositoryPort bidRepositoryPort; private final WinningBidRepositoryPort winningBidRepositoryPort; @@ -30,29 +32,34 @@ public class CloseAuctionEventListener implements MessageListener { public void onMessage(Message message, byte[] pattern) { String expiredKey = new String(message.getBody(), StandardCharsets.UTF_8); if (expiredKey.startsWith(RedisConstants.AUCTION_CLOSE_KEY_PREFIX)) { - Long auctionId = Long.parseLong(expiredKey.replace(RedisConstants.AUCTION_CLOSE_KEY_PREFIX, "")); - Auction findAuction = auctionRepositoryPort.findAuctionById(auctionId); - close(findAuction); + Long auctionId = parseAuctionId(expiredKey); + Auction auction = auctionRepositoryPort.findAuctionById(auctionId); + closeAuction(auction); closeAuctionUseCase.delete(auctionId); } } - private void close(Auction findAuction) { - if (findAuction.getProgress().equals(AuctionProgress.NOT_STARTED)) { - findAuction.notBid(); + private Long parseAuctionId(String expiredKey) { + return Long.parseLong(expiredKey.replace(RedisConstants.AUCTION_CLOSE_KEY_PREFIX, "")); + } + + private void closeAuction(Auction auction) { + if (auction.getProgress() == AuctionProgress.NOT_STARTED) { + auction.notBid(); } else { - findAuction.bid(); - Bid findBid = bidRepositoryPort.findBidByAuctionId(findAuction.getId()); - processWinningBid(findAuction, findBid); - processUserSchedule(findAuction, findBid); + auction.bid(); + Bid bid = bidRepositoryPort.findBidByAuctionId(auction.getId()); + processWinningBid(auction, bid); + processUserSchedule(auction, bid); } - auctionRepositoryPort.saveAuction(findAuction); + auctionRepositoryPort.saveAuction(auction); } private void processWinningBid(Auction auction, Bid bid) { bid.win(); bidRepositoryPort.saveBid(bid); winningBidRepositoryPort.saveWinningBid(WinningBid.of(auction, bid)); + profileRepositoryPort.subtractMoney(bid.getBidderId(), bid.getBidPrice()); } private void processUserSchedule(Auction auction, Bid bid) { diff --git a/tictoc-domain/src/main/java/tictoc/auction/exception/CloseAuctionException.java b/tictoc-domain/src/main/java/tictoc/auction/exception/CloseAuctionException.java new file mode 100644 index 0000000..1d2d282 --- /dev/null +++ b/tictoc-domain/src/main/java/tictoc/auction/exception/CloseAuctionException.java @@ -0,0 +1,10 @@ +package tictoc.auction.exception; + +import tictoc.error.ErrorCode; +import tictoc.error.exception.TicTocException; + +public class CloseAuctionException extends TicTocException { + public CloseAuctionException(final ErrorCode errorCode) { + super(errorCode); + } +} \ No newline at end of file diff --git a/tictoc-domain/src/main/java/tictoc/profile/adapter/ProfileRepositoryAdapter.java b/tictoc-domain/src/main/java/tictoc/profile/adapter/ProfileRepositoryAdapter.java index 87f4658..cb2bdd6 100644 --- a/tictoc-domain/src/main/java/tictoc/profile/adapter/ProfileRepositoryAdapter.java +++ b/tictoc-domain/src/main/java/tictoc/profile/adapter/ProfileRepositoryAdapter.java @@ -2,6 +2,9 @@ import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; +import tictoc.auction.exception.CloseAuctionException; +import tictoc.bid.exception.BidException; import tictoc.profile.model.Profile; import tictoc.profile.model.ProfileImage; import tictoc.profile.port.ProfileRepositoryPort; @@ -9,6 +12,9 @@ import tictoc.profile.repository.ProfileImageRepository; import tictoc.profile.repository.ProfileRepository; +import static tictoc.error.ErrorCode.CLOSE_AUCTION_ERROR; +import static tictoc.error.ErrorCode.INVALID_PROFILE_MONEY; + @Component @RequiredArgsConstructor public class ProfileRepositoryAdapter implements ProfileRepositoryPort { @@ -30,4 +36,13 @@ public ProfileImage saveProfileImage(ProfileImage profileImage) { public boolean checkMoney(Long userId, Integer price) { return profileRepository.existsByUserIdAndMoneyGreaterThanEqual(userId, price); } + + @Override + @Transactional + public void subtractMoney(Long userId, Integer price) { + int updatedCount = profileRepository.subtractMoney(userId, price); + if (updatedCount == 0) { + throw new CloseAuctionException(CLOSE_AUCTION_ERROR); + } + } } \ No newline at end of file diff --git a/tictoc-domain/src/main/java/tictoc/profile/model/MoneyHistory.java b/tictoc-domain/src/main/java/tictoc/profile/model/MoneyHistory.java index 6982f88..1c4a06d 100644 --- a/tictoc-domain/src/main/java/tictoc/profile/model/MoneyHistory.java +++ b/tictoc-domain/src/main/java/tictoc/profile/model/MoneyHistory.java @@ -23,4 +23,4 @@ public class MoneyHistory extends BaseTimeEntity { private Integer finalMoney; @Enumerated(EnumType.STRING) private MoneyHistoryStatus status; -} +} \ No newline at end of file diff --git a/tictoc-domain/src/main/java/tictoc/profile/port/ProfileRepositoryPort.java b/tictoc-domain/src/main/java/tictoc/profile/port/ProfileRepositoryPort.java index 8165686..204f05b 100644 --- a/tictoc-domain/src/main/java/tictoc/profile/port/ProfileRepositoryPort.java +++ b/tictoc-domain/src/main/java/tictoc/profile/port/ProfileRepositoryPort.java @@ -7,4 +7,5 @@ public interface ProfileRepositoryPort { Profile saveProfile(Profile profile); ProfileImage saveProfileImage(ProfileImage profileImage); boolean checkMoney(Long userId, Integer price); + void subtractMoney(Long userId, Integer price); } diff --git a/tictoc-domain/src/main/java/tictoc/profile/repository/ProfileRepository.java b/tictoc-domain/src/main/java/tictoc/profile/repository/ProfileRepository.java index 4772376..ec1f5a4 100644 --- a/tictoc-domain/src/main/java/tictoc/profile/repository/ProfileRepository.java +++ b/tictoc-domain/src/main/java/tictoc/profile/repository/ProfileRepository.java @@ -1,8 +1,14 @@ package tictoc.profile.repository; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; import tictoc.profile.model.Profile; public interface ProfileRepository extends JpaRepository { boolean existsByUserIdAndMoneyGreaterThanEqual(Long userId, Integer price); + @Modifying(clearAutomatically = true) + @Query("UPDATE Profile p SET p.money = p.money - :price WHERE p.userId = :userId AND p.money >= :price") + int subtractMoney(@Param("userId") Long userId, @Param("price") Integer price); } From 9194f468d341009daf81469601b43ae4bd17c703 Mon Sep 17 00:00:00 2001 From: M-ung Date: Tue, 6 May 2025 16:05:51 +0900 Subject: [PATCH 4/4] =?UTF-8?q?Feat:=20=EC=9E=85=EC=B0=B0=20=EC=8B=9C,=20?= =?UTF-8?q?=EC=9E=85=EC=B0=B0=EA=B8=88=20=ED=94=8C=EB=9F=AC=EC=8A=A4=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84=ED=95=B4=EB=9D=BC=20-?= =?UTF-8?q?=20#142?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/tictoc/error/ErrorCode.java | 3 ++- .../auction/event/CloseAuctionEventListener.java | 1 + .../profile/adapter/ProfileRepositoryAdapter.java | 15 +++++++++++---- .../profile/port/ProfileRepositoryPort.java | 1 + .../profile/repository/ProfileRepository.java | 5 +++++ 5 files changed, 20 insertions(+), 5 deletions(-) diff --git a/tictoc-common/src/main/java/tictoc/error/ErrorCode.java b/tictoc-common/src/main/java/tictoc/error/ErrorCode.java index 5a4e1e9..331ddc1 100644 --- a/tictoc-common/src/main/java/tictoc/error/ErrorCode.java +++ b/tictoc-common/src/main/java/tictoc/error/ErrorCode.java @@ -19,7 +19,8 @@ public enum ErrorCode { CONFLICT_AUCTION_DELETE(HttpStatus.BAD_REQUEST,"경매 삭제가 충돌나서 할 수 없습니다."), AUCTION_TIME_OVER(HttpStatus.BAD_REQUEST,"경매 시간이 종료되었습니다."), INVALID_AUCTION_TIME_RANGE(HttpStatus.BAD_REQUEST,"sellStartTime은 sellEndTime보다 이전이어야 합니다."), - CLOSE_AUCTION_ERROR(HttpStatus.BAD_REQUEST,"경매 종료 실패입니다. (찾을 수 없는 사용거나 보유 금액이 적습니다.)"), + CLOSE_AUCTION_ERROR_FROM_BIDDER(HttpStatus.BAD_REQUEST,"경매 종료 실패입니다. (찾을 수 없는 사용거나 보유 금액이 적습니다.)"), + CLOSE_AUCTION_ERROR_FROM_AUCTIONEER(HttpStatus.BAD_REQUEST,"경매 종료 실패입니다. (찾을 수 없는 사용거나 보유 금액이 적습니다.)"), // Bid AUCTION_ALREADY_FINISHED(HttpStatus.BAD_REQUEST, "이미 경매가 종료되었습니다."), diff --git a/tictoc-domain/src/main/java/tictoc/auction/event/CloseAuctionEventListener.java b/tictoc-domain/src/main/java/tictoc/auction/event/CloseAuctionEventListener.java index 6332963..ea289d4 100644 --- a/tictoc-domain/src/main/java/tictoc/auction/event/CloseAuctionEventListener.java +++ b/tictoc-domain/src/main/java/tictoc/auction/event/CloseAuctionEventListener.java @@ -60,6 +60,7 @@ private void processWinningBid(Auction auction, Bid bid) { bidRepositoryPort.saveBid(bid); winningBidRepositoryPort.saveWinningBid(WinningBid.of(auction, bid)); profileRepositoryPort.subtractMoney(bid.getBidderId(), bid.getBidPrice()); + profileRepositoryPort.addMoney(auction.getAuctioneerId(), bid.getBidPrice()); } private void processUserSchedule(Auction auction, Bid bid) { diff --git a/tictoc-domain/src/main/java/tictoc/profile/adapter/ProfileRepositoryAdapter.java b/tictoc-domain/src/main/java/tictoc/profile/adapter/ProfileRepositoryAdapter.java index cb2bdd6..1bbb530 100644 --- a/tictoc-domain/src/main/java/tictoc/profile/adapter/ProfileRepositoryAdapter.java +++ b/tictoc-domain/src/main/java/tictoc/profile/adapter/ProfileRepositoryAdapter.java @@ -4,7 +4,6 @@ import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; import tictoc.auction.exception.CloseAuctionException; -import tictoc.bid.exception.BidException; import tictoc.profile.model.Profile; import tictoc.profile.model.ProfileImage; import tictoc.profile.port.ProfileRepositoryPort; @@ -12,8 +11,7 @@ import tictoc.profile.repository.ProfileImageRepository; import tictoc.profile.repository.ProfileRepository; -import static tictoc.error.ErrorCode.CLOSE_AUCTION_ERROR; -import static tictoc.error.ErrorCode.INVALID_PROFILE_MONEY; +import static tictoc.error.ErrorCode.*; @Component @RequiredArgsConstructor @@ -42,7 +40,16 @@ public boolean checkMoney(Long userId, Integer price) { public void subtractMoney(Long userId, Integer price) { int updatedCount = profileRepository.subtractMoney(userId, price); if (updatedCount == 0) { - throw new CloseAuctionException(CLOSE_AUCTION_ERROR); + throw new CloseAuctionException(CLOSE_AUCTION_ERROR_FROM_BIDDER); + } + } + + @Override + @Transactional + public void addMoney(Long userId, Integer price) { + int updatedCount = profileRepository.addMoney(userId, price); + if (updatedCount == 0) { + throw new CloseAuctionException(CLOSE_AUCTION_ERROR_FROM_AUCTIONEER); } } } \ No newline at end of file diff --git a/tictoc-domain/src/main/java/tictoc/profile/port/ProfileRepositoryPort.java b/tictoc-domain/src/main/java/tictoc/profile/port/ProfileRepositoryPort.java index 204f05b..ef0f8d8 100644 --- a/tictoc-domain/src/main/java/tictoc/profile/port/ProfileRepositoryPort.java +++ b/tictoc-domain/src/main/java/tictoc/profile/port/ProfileRepositoryPort.java @@ -8,4 +8,5 @@ public interface ProfileRepositoryPort { ProfileImage saveProfileImage(ProfileImage profileImage); boolean checkMoney(Long userId, Integer price); void subtractMoney(Long userId, Integer price); + void addMoney(Long auctioneerId, Integer bidPrice); } diff --git a/tictoc-domain/src/main/java/tictoc/profile/repository/ProfileRepository.java b/tictoc-domain/src/main/java/tictoc/profile/repository/ProfileRepository.java index ec1f5a4..137cc4e 100644 --- a/tictoc-domain/src/main/java/tictoc/profile/repository/ProfileRepository.java +++ b/tictoc-domain/src/main/java/tictoc/profile/repository/ProfileRepository.java @@ -8,7 +8,12 @@ public interface ProfileRepository extends JpaRepository { boolean existsByUserIdAndMoneyGreaterThanEqual(Long userId, Integer price); + @Modifying(clearAutomatically = true) @Query("UPDATE Profile p SET p.money = p.money - :price WHERE p.userId = :userId AND p.money >= :price") int subtractMoney(@Param("userId") Long userId, @Param("price") Integer price); + + @Modifying(clearAutomatically = true) + @Query("UPDATE Profile p SET p.money = p.money + :price WHERE p.userId = :userId") + int addMoney(@Param("userId") Long userId, @Param("price") Integer price); }