Skip to content

Commit

Permalink
Merge branch 'develop' into feature/#111-approve-payment
Browse files Browse the repository at this point in the history
  • Loading branch information
kmebin committed Nov 26, 2023
2 parents 574fa34 + 43efc00 commit bde153c
Show file tree
Hide file tree
Showing 99 changed files with 3,879 additions and 5,389 deletions.
8 changes: 4 additions & 4 deletions nginx/conf.d/header.conf
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
proxy_pass_header Server;
proxy_http_version 1.1;
proxy_set_header Host $http_host;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Upgrade $http_upgrade;

proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
4 changes: 2 additions & 2 deletions nginx/templates/http-server.template
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
server {
listen 80;
server_name ${SERVER_DOMAIN};
listen 80;
server_name ${SERVER_DOMAIN};

location / {
return 301 https://$http_host$request_uri;
Expand Down
6 changes: 3 additions & 3 deletions nginx/templates/ssl-server.template
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
server {
listen 443 ssl;
server_name ${SERVER_DOMAIN};
server_name ${SERVER_DOMAIN};

ssl_certificate /etc/letsencrypt/live/${SERVER_DOMAIN}/fullchain.pem;
ssl_certificate /etc/letsencrypt/live/${SERVER_DOMAIN}/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/${SERVER_DOMAIN}/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

location / {
location / {
proxy_pass http://backend;
}
}
9 changes: 9 additions & 0 deletions src/docs/asciidoc/coupon.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,15 @@ include::{snippets}/coupons/http-response.adoc[]

사용자가 자신의 보관함에 있는 쿠폰들을 조회합니다.

==== 요청

include::{snippets}/my-coupons/couponId/http-request.adoc[]

[discrete]
==== 응답

include::{snippets}/my-coupons/couponId/http-response.adoc[]

---

=== 쿠폰 사용 (진행 중)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public PurchaseProductResponse purchaseBugProduct(Long memberId, Long productId,
Payment payment = PaymentMapper.toPayment(memberId, product);

if (!isNull(request.couponWalletId())) {
Coupon coupon = couponService.getByWallet(memberId, request.couponWalletId());
Coupon coupon = couponService.getByWalletIdAndMemberId(request.couponWalletId(), memberId);
payment.applyCoupon(coupon, request.couponWalletId());
}
paymentRepository.save(payment);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package com.moabam.api.application.coupon;

import java.time.LocalDate;
import java.util.Optional;
import java.util.Set;

import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import com.moabam.api.domain.coupon.Coupon;
import com.moabam.api.domain.coupon.CouponWallet;
import com.moabam.api.domain.coupon.repository.CouponManageRepository;
import com.moabam.api.domain.coupon.repository.CouponRepository;
import com.moabam.api.domain.coupon.repository.CouponWalletRepository;
import com.moabam.global.auth.model.AuthMember;
import com.moabam.global.common.util.ClockHolder;
import com.moabam.global.error.exception.BadRequestException;
import com.moabam.global.error.model.ErrorMessage;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
@RequiredArgsConstructor
public class CouponManageService {

private static final long ISSUE_SIZE = 10;

private final ClockHolder clockHolder;

private final CouponRepository couponRepository;
private final CouponManageRepository couponManageRepository;
private final CouponWalletRepository couponWalletRepository;

@Scheduled(fixedDelay = 1000)
public void issue() {
LocalDate now = clockHolder.date();
Optional<Coupon> isCoupon = couponRepository.findByStartAt(now);

if (!canIssue(isCoupon)) {
return;
}

Coupon coupon = isCoupon.get();
Set<Long> membersId = couponManageRepository.popMinQueue(coupon.getName(), ISSUE_SIZE);

membersId.forEach(memberId -> {
int nextStock = couponManageRepository.increaseIssuedStock(coupon.getName());

if (coupon.getStock() < nextStock) {
return;
}

CouponWallet couponWallet = CouponWallet.create(memberId, coupon);
couponWalletRepository.save(couponWallet);
});
}

public void register(AuthMember authMember, String couponName) {
double registerTime = System.currentTimeMillis();
validateRegister(couponName);
couponManageRepository.addIfAbsentQueue(couponName, authMember.id(), registerTime);
}

public void deleteCouponManage(String couponName) {
couponManageRepository.deleteQueue(couponName);
couponManageRepository.deleteIssuedStock(couponName);
}

private void validateRegister(String couponName) {
LocalDate now = clockHolder.date();
Optional<Coupon> coupon = couponRepository.findByStartAt(now);

if (coupon.isEmpty() || !coupon.get().getName().equals(couponName)) {
throw new BadRequestException(ErrorMessage.INVALID_COUPON_PERIOD);
}
}

private boolean canIssue(Optional<Coupon> coupon) {
if (coupon.isEmpty()) {
return false;
}

Coupon currentCoupon = coupon.get();
int currentStock = couponManageRepository.getIssuedStock(currentCoupon.getName());
int maxStock = currentCoupon.getStock();

return currentStock < maxStock;
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
package com.moabam.api.application.coupon;

import java.util.List;

import com.moabam.api.domain.coupon.Coupon;
import com.moabam.api.domain.coupon.CouponType;
import com.moabam.api.domain.coupon.CouponWallet;
import com.moabam.api.dto.coupon.CouponResponse;
import com.moabam.api.dto.coupon.CreateCouponRequest;
import com.moabam.api.dto.coupon.MyCouponResponse;
import com.moabam.global.common.util.StreamUtils;

import lombok.AccessLevel;
import lombok.NoArgsConstructor;
Expand All @@ -25,7 +30,7 @@ public static Coupon toEntity(Long adminId, CreateCouponRequest coupon) {
}

// TODO : Admin Table 생성 시, 관리자 명 추가할 예정
public static CouponResponse toDto(Coupon coupon) {
public static CouponResponse toResponse(Coupon coupon) {
return CouponResponse.builder()
.id(coupon.getId())
.adminName(coupon.getAdminId() + "admin")
Expand All @@ -38,4 +43,24 @@ public static CouponResponse toDto(Coupon coupon) {
.openAt(coupon.getOpenAt())
.build();
}

public static List<CouponResponse> toResponses(List<Coupon> coupons) {
return StreamUtils.map(coupons, CouponMapper::toResponse);
}

public static MyCouponResponse toMyResponse(CouponWallet couponWallet) {
Coupon coupon = couponWallet.getCoupon();

return MyCouponResponse.builder()
.id(coupon.getId())
.name(coupon.getName())
.description(coupon.getDescription())
.point(coupon.getPoint())
.type(coupon.getType())
.build();
}

public static List<MyCouponResponse> toMyResponses(List<CouponWallet> couponWallets) {
return StreamUtils.map(couponWallets, CouponMapper::toMyResponse);
}
}

This file was deleted.

42 changes: 27 additions & 15 deletions src/main/java/com/moabam/api/application/coupon/CouponService.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,16 @@
import org.springframework.transaction.annotation.Transactional;

import com.moabam.api.domain.coupon.Coupon;
import com.moabam.api.domain.coupon.CouponWallet;
import com.moabam.api.domain.coupon.repository.CouponRepository;
import com.moabam.api.domain.coupon.repository.CouponSearchRepository;
import com.moabam.api.domain.coupon.repository.CouponWalletRepository;
import com.moabam.api.domain.coupon.repository.CouponWalletSearchRepository;
import com.moabam.api.domain.member.Role;
import com.moabam.api.dto.coupon.CouponResponse;
import com.moabam.api.dto.coupon.CouponStatusRequest;
import com.moabam.api.dto.coupon.CreateCouponRequest;
import com.moabam.api.dto.coupon.MyCouponResponse;
import com.moabam.global.auth.model.AuthMember;
import com.moabam.global.common.util.ClockHolder;
import com.moabam.global.error.exception.BadRequestException;
Expand All @@ -28,15 +31,18 @@
@Transactional(readOnly = true)
public class CouponService {

private final ClockHolder clockHolder;
private final CouponManageService couponManageService;
private final CouponRepository couponRepository;
private final CouponSearchRepository couponSearchRepository;
private final CouponWalletRepository couponWalletRepository;
private final ClockHolder clockHolder;
private final CouponWalletSearchRepository couponWalletSearchRepository;

@Transactional
public void create(AuthMember admin, CreateCouponRequest request) {
validateAdminRole(admin);
validateConflictName(request.name());
validateConflictStartAt(request.startAt());
validatePeriod(request.startAt(), request.openAt());

Coupon coupon = CouponMapper.toEntity(admin.id(), request);
Expand All @@ -49,6 +55,7 @@ public void delete(AuthMember admin, Long couponId) {
Coupon coupon = couponRepository.findById(couponId)
.orElseThrow(() -> new NotFoundException(ErrorMessage.NOT_FOUND_COUPON));
couponRepository.delete(coupon);
couponManageService.deleteCouponManage(coupon.getName());
}

@Transactional
Expand All @@ -61,7 +68,7 @@ public CouponResponse getById(Long couponId) {
Coupon coupon = couponRepository.findById(couponId)
.orElseThrow(() -> new NotFoundException(ErrorMessage.NOT_FOUND_COUPON));

return CouponMapper.toDto(coupon);
return CouponMapper.toResponse(coupon);
}

public Coupon getByWallet(Long memberId, Long couponWalletId) {
Expand All @@ -71,28 +78,27 @@ public Coupon getByWallet(Long memberId, Long couponWalletId) {
}

public List<CouponResponse> getAllByStatus(CouponStatusRequest request) {
LocalDate now = LocalDate.from(clockHolder.times());
LocalDate now = clockHolder.date();
List<Coupon> coupons = couponSearchRepository.findAllByStatus(now, request);

return coupons.stream()
.map(CouponMapper::toDto)
.toList();
return CouponMapper.toResponses(coupons);
}

public Coupon validatePeriod(String couponName) {
LocalDate now = LocalDate.from(clockHolder.times());
Coupon coupon = couponRepository.findByName(couponName)
.orElseThrow(() -> new NotFoundException(ErrorMessage.NOT_FOUND_COUPON));
public List<MyCouponResponse> getWallet(Long couponId, AuthMember authMember) {
List<CouponWallet> couponWallets =
couponWalletSearchRepository.findAllByCouponIdAndMemberId(couponId, authMember.id());

if (!now.equals(coupon.getStartAt())) {
throw new BadRequestException(ErrorMessage.INVALID_COUPON_PERIOD);
}
return CouponMapper.toMyResponses(couponWallets);
}

return coupon;
public Coupon getByWalletIdAndMemberId(Long couponWalletId, Long memberId) {
return couponWalletSearchRepository.findByIdAndMemberId(couponWalletId, memberId)
.orElseThrow(() -> new NotFoundException(ErrorMessage.NOT_FOUND_COUPON_WALLET))
.getCoupon();
}

private void validatePeriod(LocalDate startAt, LocalDate openAt) {
LocalDate now = LocalDate.from(clockHolder.times());
LocalDate now = clockHolder.date();

if (!now.isBefore(startAt)) {
throw new BadRequestException(ErrorMessage.INVALID_COUPON_START_AT_PERIOD);
Expand All @@ -114,4 +120,10 @@ private void validateConflictName(String couponName) {
throw new ConflictException(ErrorMessage.CONFLICT_COUPON_NAME);
}
}

private void validateConflictStartAt(LocalDate startAt) {
if (couponRepository.existsByStartAt(startAt)) {
throw new ConflictException(ErrorMessage.CONFLICT_COUPON_START_AT);
}
}
}
Loading

0 comments on commit bde153c

Please sign in to comment.