Skip to content

Commit

Permalink
feat: 사용자는 환불 시에 환불액을 주고 받는다 (#67)
Browse files Browse the repository at this point in the history
* feat: 환불 요청에 대한 검증 후 포인트 교환

- 환불 수량은 인자에서 제외했습니다
- 포인트 교환 이후 이루어질 task를 todo로 정리했습니다

* refactor: 환불에 사용되는 에러 코드 정의

- 기존에 사용된 P000 에러는 입찰과 환불 모두 사용되어 거래 시로 변경합니다

* feat: 사용자 도메인 equals 구현

- 환불 요청 사용자와 거래 내역의 사용자가 동일한 지 검증하기 위해 재정의합니다

* test: 환불 메서드의 테스트 코드 스켈레톤 작성

* refactor: 코드 정렬 및 경매 취소 인터페이스 정의

- todo로 넘긴 입찰 취소 요청, 정보 저장을 뼈대 코드로 구현했습니다
- 입찰 취소 요청 시 거래 내역이 경매 id를 보내줘야 하므로 필드에 추가했습니다

* refactor: 이미 환불된 거래 내역 검증 로직 구현

- 이미 환불된 내역일 경우의 예외를 추가했습니다

* refactor: 식별자인 로그인 아이디로 동일성 검증

- signInId를 통한 동일성 검증으로 변경했습니다

* test: 사용자 동일성 검증, 거래 내역 환불 상태 검증 테스트 추가
  • Loading branch information
minseok-oh authored Aug 13, 2024
1 parent 7c074b0 commit 74dae60
Show file tree
Hide file tree
Showing 9 changed files with 172 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -127,4 +127,11 @@ public void submitBid(long auctionId, long price, long quantity) {

// TODO 구매(입찰) 로직
}

/**
* 경매 상품에 대한 입찰 취소를 진행한다.
*/
public void cancelBid(long auctionId, long quantity) {
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ public boolean confirmPassword(String password) {
return this.password.equals(password);
}

public boolean isSameMember(String signInId) {
return this.signInId.equals(signInId);
}

public boolean isBuyer() {
return role.equals(Role.BUYER);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,34 @@

import com.wootecam.luckyvickyauction.core.member.domain.Member;
import lombok.Builder;
import lombok.Getter;

@Getter
public class BidHistory {

private Long id;
private String productName;
private long price;
private long quantity;
private BidStatus bidStatus;
private long auctionId;
private Member seller;
private Member buyer;

@Builder
public BidHistory(final Long id, final String productName, final long price, final long quantity,
BidStatus bidStatus, final Member seller, final Member buyer) {
BidStatus bidStatus, final long auctionId, final Member seller, final Member buyer) {
this.id = id;
this.productName = productName;
this.price = price;
this.quantity = quantity;
this.bidStatus = bidStatus;
this.auctionId = auctionId;
this.seller = seller;
this.buyer = buyer;
}

public boolean isRefundStatus() {
return bidStatus.equals(BidStatus.REFUND);
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package com.wootecam.luckyvickyauction.core.payment.domain;

import java.util.Optional;

public interface BidHistoryRepository {

BidHistory save(BidHistory bidHistory);

Optional<BidHistory> findById(long bidHistoryId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,54 @@ private boolean submitBid(long price, long auctionId, long quantity, Member buye
return false;
}
}

/**
* 구매자는 자신의 입찰 내역에서 상품을 환불할 수 있다 <br> 1. 환불을 요청한 사용자가 구매자 권한이 맞는 지 확인한다 <br> 2. 환불할 입찰 내역의 구매자가 환불을 요청한 사용자인지 확인한다
* <br> 3. 환불 금액과 수량을 받아와서 교환한다 <br> 4. 경매 서비스에 환불 요청한다 <br> 5. 환불 이후 정보들을 저장한다
*
* @param buyer 환불을 요청한 사용자
* @param bidHistoryId 환불할 입찰 내역의 id
*/
public void refund(Member buyer, long bidHistoryId) {
if (!buyer.isBuyer()) {
throw new BadRequestException("구매자만 환불을 할 수 있습니다.", ErrorCode.P000);
}

BidHistory refundTargetBidHistory = findRefundTargetBidHistory(bidHistoryId);
if (refundTargetBidHistory.isRefundStatus()) {
throw new BadRequestException("이미 환불된 입찰 내역입니다.", ErrorCode.P003);
}

Member refundTargetBuyer = refundTargetBidHistory.getBuyer();
if (!buyer.isSameMember(refundTargetBuyer.getSignInId())) {
throw new BadRequestException("환불할 입찰 내역의 구매자만 환불을 할 수 있습니다.", ErrorCode.P004);
}

long price = refundTargetBidHistory.getPrice();
long quantity = refundTargetBidHistory.getQuantity();

Member seller = refundTargetBidHistory.getSeller();
buyer.chargePoint(price * quantity);
seller.usePoint(price * quantity);

// 경매 서비스에 환불 요청
auctionService.cancelBid(refundTargetBidHistory.getAuctionId(), quantity);

// 환불 요청에 대한 정보 저장
Member savedBuyer = memberRepository.save(buyer);
Member savedSeller = memberRepository.save(seller);
bidHistoryRepository.save(BidHistory.builder()
.productName(refundTargetBidHistory.getProductName())
.price(price)
.quantity(quantity)
.bidStatus(BidStatus.REFUND)
.seller(savedSeller)
.buyer(savedBuyer)
.build());
}

private BidHistory findRefundTargetBidHistory(long bidHistoryId) {
return bidHistoryRepository.findById(bidHistoryId).orElseThrow(
() -> new NotFoundException("환불할 입찰 내역을 찾을 수 없습니다. 내역 id=" + bidHistoryId, ErrorCode.P002));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,11 @@ public enum ErrorCode {
M003("로그인 시, 입력 패스워드와 실제 패스워드가 다른 경우 예외가 발생합니다."),

// Payment 관련 예외 코드
P000("입찰 시, 로그인한 사용자가 구매자가 아닌 경우 예외가 발생합니다."),
P000("거래 시, 로그인한 사용자가 구매자가 아닌 경우 예외가 발생합니다."),
P001("입찰 시, 사용자의 포인트가 부족한 경우 예외가 발생합니다."),
P002("환불 시, 환불할 입찰 내역을 찾을 수 없을 경우 예외가 발생합니다."),
P003("환불 시, 이미 환불된 입찰 내역일 경우 예외가 발생합니다."),
P004("환불 시, 요청한 사용자가 환불할 입찰의 구매자가 아닌 경우 예외가 발생합니다."),

// Global 예외
G000("DTO 생성 시, 필드의 값이 NULL인 경우 예외가 발생합니다.");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,4 +146,16 @@ class isBuyer_메소드는 {
assertThat(seller.isBuyer()).isFalse();
}
}

@Test
void 동일한_사용자인지_확인할__있다() {
// given
Member member = new Member("testId", "password", Role.BUYER, new Point(100));

// when
boolean isSameMember = member.isSameMember("testId");

// then
assertThat(isSameMember).isTrue();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.wootecam.luckyvickyauction.core.payment.domain;

import static org.assertj.core.api.Assertions.assertThat;

import org.junit.jupiter.api.Test;

public class BidHistoryTest {

@Test
void 거래_내역이_환불_상태인지_확인할__있다() {
// given
BidHistory refundBidHistory = BidHistory.builder()
.bidStatus(BidStatus.REFUND)
.build();

// when
boolean isRefundStatus = refundBidHistory.isRefundStatus();

// then
assertThat(isRefundStatus).isTrue();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
class PaymentServiceTest {

@Nested
class submitBid_메소드는 {
class process_메소드는 {

@Nested
class 정상적인_요청_흐름이면 {
Expand Down Expand Up @@ -53,4 +53,63 @@ class 만약_요청한_물건의_금액이_사용자가_가진_포인트보다_
}
}
}

@Nested
class refund_메소드는 {

@Nested
class 정상적인_요청_흐름이면 {

@Test
void 환불이_진행된다() {
// given
// when
// then
}
}

@Nested
class 만약_요청한_사용자가_구매자가_아니라면 {

@Test
void 예외가_발생한다() {
// given
// when
// then
}
}

@Nested
class 만약_환불할_입찰_내역을_찾을__없다면 {

@Test
void 예외가_발생한다() {
// given
// when
// then
}
}

@Nested
class 만약_이미_환불된_입찰_내역이라면 {

@Test
void 예외가_발생한다() {
// given
// when
// then
}
}

@Nested
class 만약_입찰_내역의_구매자가_요청한_사용자가_아니라면 {

@Test
void 예외가_발생한다() {
// given
// when
// then
}
}
}
}

0 comments on commit 74dae60

Please sign in to comment.