Skip to content

Commit

Permalink
feat : 입찰기능 추가 (#71)
Browse files Browse the repository at this point in the history
* refactor, feat : 컬럼 추가, 타입변경 및 rename 에 따른 기능 수정

* feat : Scheduling완료, Mail Template 페이지제작

* tempSave

* feat : 입찰 기능 구현

* feat : checkout을 위한 Commit

* feat : Emial Template 제작중

* feat : 이메일 구현
- 입찰자가 없는 경우 유찰 안내메일
- 관리자가 승인하지 않은 경우 유찰 안내메일
- 경매 시작 안내 메일
- 링크 발송을 위한 Properties 추가

* Issue 수정

* feat : detail페이지 이쁘게 꾸미기

* faet : Front로직 추가~

* Feat : 입찰기능 추가
  • Loading branch information
donsonioc2010 authored Sep 26, 2023
1 parent ed6e162 commit ad64a4c
Show file tree
Hide file tree
Showing 12 changed files with 216 additions and 77 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,18 @@
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import picasso.server.api.auction.dto.request.PictureBiddingValidRequestDto;
import picasso.server.api.auction.dto.request.PictureBiddingRequestDto;
import picasso.server.api.auction.dto.response.PictureAbleBidResponseDto;
import picasso.server.api.auction.service.PictureBidHistoryService;
import picasso.server.common.exception.NotLoginUserRestException;
import picasso.server.domain.domains.picture.items.PictureBidHistory;
import picasso.server.domain.domains.user.entity.User;

import java.util.List;

@Slf4j
@RequiredArgsConstructor
@RestController
Expand All @@ -34,14 +32,30 @@ public class PictureBidHistoryRestController {
*/
@PostMapping
public ResponseEntity<Boolean> isAblePictureBidding(
@Valid @RequestBody PictureBiddingValidRequestDto requestDto, HttpSession session
@Valid @RequestBody PictureBiddingRequestDto requestDto, HttpSession session
) {
return ResponseEntity.ok(
pictureBidHistoryService.biddingProcess(session, isSessionHaveLoginUser(session), requestDto)
);
}

@GetMapping("/{pictureId}")
public ResponseEntity<PictureAbleBidResponseDto> isAblePictureBidding(
@PathVariable Long pictureId, HttpSession session
) {
return ResponseEntity.ok(
pictureBidHistoryService.getSessionUserBiddingResult(
isSessionHaveLoginUser(session),
pictureId
)
);
}

private User isSessionHaveLoginUser(HttpSession session) {
User user = (User) session.getAttribute("loginUser");
if (user == null) {
throw NotLoginUserRestException.EXCEPTION;
}
return ResponseEntity.ok(
pictureBidHistoryService.biddingProcess(user, requestDto.getPictureId(), requestDto.getAmount())
);
return user;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import picasso.server.api.auction.dto.response.PictureBidHistoryAmountCreatedAtResponse;
import picasso.server.api.auction.service.PictureBidHistoryService;
import picasso.server.api.auction.service.PictureService;
import picasso.server.api.user.service.UserService;
Expand All @@ -23,6 +24,7 @@
import picasso.server.domain.domains.picture.items.PictureStatus;
import picasso.server.domain.domains.user.entity.User;

import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
Expand Down Expand Up @@ -137,7 +139,15 @@ public String viewPictureDetail(@PathVariable Long id, Model model) {
Picture picture = pictureService.getPictureById(id).orElseThrow(() -> NotFoundException.EXCEPTION);
model.addAllAttributes(new HashMap<>() {{
put("picture", picture);
put("pictureBidHistory", pictureBidHistoryService.getBidAmountListDescByPicture(picture));
put("pictureBidHistory",
pictureBidHistoryService.getBidAmountListDescByPicture(picture)
.stream()
.map(
pictureBidHistory -> PictureBidHistoryAmountCreatedAtResponse.builder()
.bidAmount(String.valueOf(pictureBidHistory.getBidAmount()))
.createdAt(pictureBidHistory.getCreatedAt().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")))
.build()
).toList());
put("topBidHistory", pictureBidHistoryService.getTopBidAmountByPicture(picture));
}});
return "pictures/pictureDetail";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
* 입찰시, 입찰 가능여부 확인을 위한 RequestDTO
*/
@Data
public class PictureBiddingValidRequestDto {
public class PictureBiddingRequestDto {
@PositiveOrZero
@NotNull(message = "PictureId는 필수 입력을 하셔야 합니다.")
private Long pictureId;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package picasso.server.api.auction.dto.response;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;

@Getter
@Builder
@AllArgsConstructor
public class PictureAbleBidResponseDto {
private boolean result;
private String message;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package picasso.server.api.auction.dto.response;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
@Builder
@AllArgsConstructor
public class PictureBidHistoryAmountCreatedAtResponse {
private String bidAmount;
private String createdAt;
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
package picasso.server.api.auction.service;

import jakarta.servlet.http.HttpSession;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import picasso.server.api.auction.dto.request.PictureBiddingRequestDto;
import picasso.server.api.auction.dto.response.PictureAbleBidResponseDto;
import picasso.server.common.exception.NotFoundRestException;
import picasso.server.common.exception.NotLoginUserRestException;
import picasso.server.domain.domains.picture.items.Picture;
Expand All @@ -19,6 +23,7 @@

@Slf4j
@RequiredArgsConstructor
@Transactional
@Service
public class PictureBidHistoryService {
private final UserRepository userRepository;
Expand All @@ -40,23 +45,26 @@ public PictureBidHistory getTopBidAmountByPicture(Picture picture) {
* @param amount
* @return
*/
public boolean biddingProcess(User user, Long pictureId, Long amount) {
@Transactional
public boolean biddingProcess(HttpSession session, User user, PictureBiddingRequestDto requestDto) {
User findUser = userRepository.findById(user.getId()).orElseThrow(() -> NotLoginUserRestException.EXCEPTION);
Picture findPicture = pictureRepository.findById(pictureId).orElseThrow(() -> NotFoundRestException.EXCEPTION);
Optional<PictureBidHistory> optionalTopHistory = pictureBidHistoryRepository.findTopByPictureOrderByBidAmountDesc(findPicture);

//아무도 입찰 신청을 하지 않은 경우 또는 요청한 사용자가 입찰 신청한경우 , DB에 저장
if (optionalTopHistory.isEmpty() || isAbleBiddingPictureByUser(user, findPicture, optionalTopHistory.get(), amount)) {
PictureBidHistory newBidHistory = PictureBidHistory.builder()
.picture(findPicture)
.user(findUser)
.bidAmount(amount)
.build();
findPicture.addBidHistory(newBidHistory);
pictureRepository.save(findPicture);
return true;
}
return false;
Picture findPicture = pictureRepository.findById(requestDto.getPictureId()).orElseThrow(() -> NotFoundRestException.EXCEPTION);
List<PictureBidHistory> history = pictureBidHistoryRepository.findByPicture(findPicture);
history.add(
PictureBidHistory.builder()
.picture(findPicture)
.user(findUser)
.bidAmount(requestDto.getAmount())
.build()
);

findUser.minusPoint(requestDto.getAmount());
pictureBidHistoryRepository.findTopByPictureOrderByBidAmountDesc(findPicture).ifPresent(topHistory ->
topHistory.getUser().updatePoint(topHistory.getBidAmount()));
userRepository.save(findUser);
session.setAttribute("loginUser", findUser);
return true;
}

/**
Expand All @@ -72,7 +80,35 @@ private boolean isAbleBiddingPictureByUser(User user, Picture picture, PictureBi
// 사용자가 최종 입찰자가 아니거나 또는
return !topHistory.getUser().equals(user) && amount <= topHistory.getBidAmount() + picture.getIncrementAmount();
}


/**
* 경매 입찰을 진행한 사용자가 입찰이 가능한지를 검증한다.
* @param sessionHaveLoginUser
* @param pictureId
* @return
*/
@Transactional
public PictureAbleBidResponseDto getSessionUserBiddingResult(User sessionHaveLoginUser, Long pictureId) {
Picture findPicture = pictureRepository.findById(pictureId).orElseThrow(() -> NotFoundRestException.EXCEPTION);
Optional<PictureBidHistory> optionalTopHistory = pictureBidHistoryRepository.findTopByPictureOrderByBidAmountDesc(findPicture);
if (sessionHaveLoginUser.getEmail().equals(findPicture.getUser().getEmail())) {
return PictureAbleBidResponseDto.builder()
.result(false)
.message("경매품 등록자는 입찰이 불가합니다.")
.build();
}

if (optionalTopHistory.isPresent() && optionalTopHistory.get().getUser().getEmail().equals(sessionHaveLoginUser.getEmail())) {
return PictureAbleBidResponseDto.builder()
.result(false)
.message("가장 최근 입찰자 입니다.")
.build();
}

return PictureAbleBidResponseDto.builder()
.result(true)
.build();
}
public List<PictureBidHistory> retrieveMyBidHistoryList(User user) {
return pictureBidHistoryRepository.findAllByUserOrderByCreatedAt(user);
}
Expand Down
46 changes: 31 additions & 15 deletions Api/src/main/resources/static/js/bidModal.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ const bidButton = document.getElementById('bidButton')
function bidProcess() {
let minPictureBidAmount = nowPictureAmountVal+incrementAmountVal
if(parseInt(bidInput.value) < minPictureBidAmount){
alert('입찰 최소 금액은 '+minPictureBidAmount+'원 입니다' )
alert('입찰 최소 금액은 '+ minPictureBidAmount+'원 입니다' )
return false
}

Expand All @@ -73,27 +73,43 @@ function bidProcess() {
return false
}

let pictureId = document.getElementById('pictureId')


//입찰
$.ajax({
type : 'post',
url : '/user/session-info',
type : 'get',
url : '/api/bidding/'+parseInt(pictureId.value),
success : function(data, status, xhr) {
userId = data.userId
console.log(data)
if(data.result) {
$.ajax({
type: 'post',
url: '/api/bidding',
dataType: 'json',
contentType: 'application/json; charset=utf-8',
data: JSON.stringify({
"pictureId" : parseInt(pictureId.value),
"amount" : parseInt(bidInput.value)
}),
success : (data, status, xhr) => {
alert('입찰이 완료되었습니다.')
location.reload();
},
error: (xhr, status, error) => {
alert('입찰 도중 오류가 발생하였습니다.')
location.reload();
}
})

}else {
alert(data.message)
}
},
error : function(xhr, status, error) {
alert('입찰 불가')
alert('입찰 도중 오류가 발생하였습니다.')
},
})

var price = document.getElementById("inputPrice").value;
$.ajax({
type: 'post',
url: 'urlurlurl',
dataType: 'json',
contentType: 'application/json; charset=utf-8',
data: JSON.stringify({
"bidPrice" : price
})
})
}
bidButton.addEventListener('click', bidProcess);
43 changes: 27 additions & 16 deletions Api/src/main/resources/templates/pictures/pictureDetail.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@

<div class="container body" style="margin-top: 100px;">
<div th:if="${picture}" class="picture-details">
<input type="hidden" name="pictureId" id="pictureId" th:value="${picture.pictureId}" />
<input type="hidden" name="incrementAmount" id="incrementAmount" th:value="${picture.incrementAmount}" />
<input type="hidden" name="pictureId" id="pictureId" th:value="${picture.pictureId}"/>
<input type="hidden" name="incrementAmount" id="incrementAmount" th:value="${picture.incrementAmount}"/>

<div class="row" style="margin-bottom: 30px">
<div class="col">
Expand Down Expand Up @@ -100,7 +100,7 @@ <h2 class="accordion-header">
</div>
</div>
<th:block th:if="${session.loginUser != null}">
<input type="hidden" name="userPoint" id="userPoint" th:value="${session.loginUser.point}" />
<input type="hidden" name="userPoint" id="userPoint" th:value="${session.loginUser.point}"/>

<div class="row justify-content-md-center">
<div class="col-md-4">
Expand All @@ -121,16 +121,15 @@ <h5 class="offcanvas-title" id="offcanvasWithBothOptionsLabel">입찰내역 Hist
입찰내역이 존재하지 않습니다.
</th:block>
<th:block th:if="${pictureBidHistory.size() != 0}">
입찰내역이 존재합니다.
<ul class="list-group" th:each=" history : ${pictureBidHistory}">
<li class="list-group-item">
<div class="row">
<div class="col-md-6" th:text="${history.bidAmount}"></div>
<div class="col-md-6" th:text="${history.createdAt}"></div>
</div>
</li>
</ul>
</th:block>

<ul class="list-group">
<li class="list-group-item">An item</li>
<li class="list-group-item">A second item</li>
<li class="list-group-item">A third item</li>
<li class="list-group-item">A fourth item</li>
<li class="list-group-item">And a fifth one</li>
</ul>
</div>
</div>
</div>
Expand All @@ -155,17 +154,29 @@ <h5 class="offcanvas-title" id="offcanvasWithBothOptionsLabel">입찰내역 Hist
<p class="h5 align-baseline">현재 입찰가</p>
</div>
<div class="col-md-9">
<input class="form-control" id="nowPictureAmount" type="text" placeholder="현재 최소 입찰가" th:if="${topBidHistory != null}" th:value="${topBidHistory.bidAmount}" aria-label="Disabled input example" disabled>
<input class="form-control" id="nowPictureAmount" type="text" placeholder="현재 최소 입찰가" th:if="${topBidHistory == null}" th:value="${picture.startingPrice}" aria-label="Disabled input example" disabled>
<input class="form-control" id="nowPictureAmount" type="text"
placeholder="현재 최소 입찰가" th:if="${topBidHistory != null}"
th:value="${topBidHistory.bidAmount}"
aria-label="Disabled input example" disabled>
<input class="form-control" id="nowPictureAmount" type="text"
placeholder="현재 최소 입찰가" th:if="${topBidHistory == null}"
th:value="${picture.startingPrice}"
aria-label="Disabled input example" disabled>
</div>
</div>
<div class="row">
<div class="col-md-3">
<p class="h5 align-baseline">입찰 희망가</p>
</div>
<div class="col-md-7">
<input id="bidInput" class="form-control me-auto" th:if="${topBidHistory != null}" th:value="${topBidHistory.bidAmount} + ${picture.incrementAmount}" placeholder="입찰 금액 입력"/>
<input id="bidInput" class="form-control me-auto" th:if="${topBidHistory == null}" th:value="${picture.startingPrice} + ${picture.incrementAmount}" placeholder="입찰 금액 입력"/>
<input id="bidInput" class="form-control me-auto"
th:if="${topBidHistory != null}"
th:value="${topBidHistory.bidAmount} + ${picture.incrementAmount}"
placeholder="입찰 금액 입력"/>
<input id="bidInput" class="form-control me-auto"
th:if="${topBidHistory == null}"
th:value="${picture.startingPrice} + ${picture.incrementAmount}"
placeholder="입찰 금액 입력"/>
</div>
<div class="col-md-2">
<button id="bidButton" class="btn btn-primary w-100">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ public class Picture {
private LocalDate bidEndDate; // 경매 종료일

@ManyToOne
@JoinColumn(name = "id")
@JoinColumn(name = "user_id")
private User user;

//경매 내역 History
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ public interface PictureBidHistoryRepository extends JpaRepository<PictureBidHis
List<PictureBidHistory> findByUserOrderByCreatedAtDesc(User user);

List<PictureBidHistory> findByPictureOrderByBidAmountDesc(Picture picture);


List<PictureBidHistory> findByPicture(Picture picture);

List<PictureBidHistory> findAllByUserOrderByCreatedAt(User user);
}
Loading

0 comments on commit ad64a4c

Please sign in to comment.