Skip to content

Commit

Permalink
Merge branch 'feature/#111-approve-payment' into feature/#150-get-bug…
Browse files Browse the repository at this point in the history
…-history
  • Loading branch information
kmebin committed Nov 26, 2023
2 parents 2925f0f + abe23c7 commit f3beca8
Show file tree
Hide file tree
Showing 64 changed files with 1,286 additions and 320 deletions.
4 changes: 4 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ dependencies {

// Test
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'com.squareup.okhttp3:mockwebserver:4.11.0'

// Querydsl
implementation 'com.querydsl:querydsl-jpa:5.0.0:jakarta'
Expand Down Expand Up @@ -92,6 +93,9 @@ dependencies {
// S3
implementation platform("io.awspring.cloud:spring-cloud-aws-dependencies:3.0.2")
implementation 'io.awspring.cloud:spring-cloud-aws-starter-s3'

// webflux
implementation 'org.springframework.boot:spring-boot-starter-webflux'
}

tasks.named('test') {
Expand Down
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
4 changes: 2 additions & 2 deletions src/main/java/com/moabam/api/application/bug/BugMapper.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ public static BugHistoryItemResponse toBugHistoryItemResponse(BugHistoryDto dto)
BugHistoryItemResponse.PaymentResponse payment = BugHistoryItemResponse.PaymentResponse.builder()
.id(dto.payment().getId())
.orderName(dto.payment().getOrder().getName())
.discountAmount(dto.payment().getCoupon().getPoint())
.totalAmount(dto.payment().getAmount())
.discountAmount(dto.payment().getDiscountAmount())
.totalAmount(dto.payment().getTotalAmount())
.build();

return BugHistoryItemResponse.builder()
Expand Down
12 changes: 9 additions & 3 deletions src/main/java/com/moabam/api/application/bug/BugService.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@
import com.moabam.api.application.member.MemberService;
import com.moabam.api.application.payment.PaymentMapper;
import com.moabam.api.application.product.ProductMapper;
import com.moabam.api.domain.bug.Bug;
import com.moabam.api.domain.bug.repository.BugHistorySearchRepository;
import com.moabam.api.domain.coupon.Coupon;
import com.moabam.api.domain.item.repository.BugHistoryDto;
import com.moabam.api.domain.member.Member;
import com.moabam.api.domain.payment.Payment;
import com.moabam.api.domain.payment.repository.PaymentRepository;
import com.moabam.api.domain.product.Product;
Expand All @@ -42,9 +42,9 @@ public class BugService {
private final PaymentRepository paymentRepository;

public BugResponse getBug(Long memberId) {
Member member = memberService.getById(memberId);
Bug bug = memberService.getById(memberId).getBug();

return BugMapper.toBugResponse(member.getBug());
return BugMapper.toBugResponse(bug);
}

public BugHistoryResponse getBugHistory(Long memberId) {
Expand Down Expand Up @@ -73,6 +73,12 @@ public PurchaseProductResponse purchaseBugProduct(Long memberId, Long productId,
return ProductMapper.toPurchaseProductResponse(payment);
}

@Transactional
public void charge(Long memberId, Product bugProduct) {
Bug bug = memberService.getById(memberId).getBug();
bug.charge(bugProduct.getQuantity());
}

private Product getById(Long productId) {
return productRepository.findById(productId)
.orElseThrow(() -> new NotFoundException(PRODUCT_NOT_FOUND));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public class CouponManageService {

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

if (!canIssue(isCoupon)) {
Expand Down Expand Up @@ -69,7 +69,7 @@ public void deleteCouponManage(String couponName) {
}

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

if (coupon.isEmpty() || !coupon.get().getName().equals(couponName)) {
Expand Down
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);
}
}
38 changes: 29 additions & 9 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 @@ -30,9 +33,9 @@ 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 CouponWalletSearchRepository couponWalletSearchRepository;

@Transactional
Expand All @@ -55,30 +58,47 @@ public void delete(AuthMember admin, Long couponId) {
couponManageService.deleteCouponManage(coupon.getName());
}

@Transactional
public void use(Long memberId, Long couponWalletId) {
Coupon coupon = getByWallet(memberId, couponWalletId);
couponRepository.delete(coupon);
}

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 getByWalletIdAndMemberId(Long couponWalletId, Long memberId) {
return couponWalletSearchRepository.findByIdAndMemberId(couponWalletId, memberId)
public Coupon getByWallet(Long memberId, Long couponWalletId) {
return couponWalletRepository.findByIdAndMemberId(couponWalletId, memberId)
.orElseThrow(() -> new NotFoundException(ErrorMessage.NOT_FOUND_COUPON_WALLET))
.getCoupon();
}

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 List<MyCouponResponse> getWallet(Long couponId, AuthMember authMember) {
List<CouponWallet> couponWallets =
couponWalletSearchRepository.findAllByCouponIdAndMemberId(couponId, authMember.id());

return CouponMapper.toMyResponses(couponWallets);
}

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 Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,24 +30,22 @@ public class NotificationService {

private static final String KNOCK_BODY = "%s님이 콕 찔렀습니다.";
private static final String CERTIFY_TIME_BODY = "%s방 인증 시간입니다.";
private static final String KNOCK_KEY = "room_%s_member_%s_knocks_%s";

private final ClockHolder clockHolder;
private final FcmService fcmService;
private final RoomService roomService;

private final NotificationRepository notificationRepository;
private final ParticipantSearchRepository participantSearchRepository;
private final ClockHolder clockHolder;

@Transactional
public void sendKnock(AuthMember member, Long targetId, Long roomId) {
roomService.validateRoomById(roomId);

String knockKey = generateKnockKey(member.id(), targetId, roomId);
validateConflictKnock(knockKey);
validateConflictKnock(member.id(), targetId, roomId);

String fcmToken = fcmService.findTokenByMemberId(targetId);
fcmService.sendAsync(fcmToken, String.format(KNOCK_BODY, member.nickname()));
notificationRepository.saveKnock(knockKey);
notificationRepository.saveKnock(member.id(), targetId, roomId);
}

@Scheduled(cron = "0 50 * * * *")
Expand All @@ -68,8 +66,8 @@ public List<Long> getMyKnockStatusInRoom(Long memberId, Long roomId, List<Partic
.filter(participant -> !participant.getMemberId().equals(memberId))
.toList();

Predicate<Long> knockPredicate = targetId
-> notificationRepository.existsKnockByKey(generateKnockKey(memberId, targetId, roomId));
Predicate<Long> knockPredicate = targetId ->
notificationRepository.existsKnockByKey(memberId, targetId, roomId);

Map<Boolean, List<Long>> knockStatus = filteredParticipants.stream()
.map(Participant::getMemberId)
Expand All @@ -78,13 +76,9 @@ public List<Long> getMyKnockStatusInRoom(Long memberId, Long roomId, List<Partic
return knockStatus.get(true);
}

private void validateConflictKnock(String knockKey) {
if (notificationRepository.existsKnockByKey(knockKey)) {
private void validateConflictKnock(Long memberId, Long targetId, Long roomId) {
if (notificationRepository.existsKnockByKey(memberId, targetId, roomId)) {
throw new ConflictException(ErrorMessage.CONFLICT_KNOCK);
}
}

private String generateKnockKey(Long memberId, Long targetId, Long roomId) {
return String.format(KNOCK_KEY, roomId, memberId, targetId);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public static Payment toPayment(Long memberId, Product product) {
.memberId(memberId)
.product(product)
.order(order)
.amount(product.getPrice())
.totalAmount(product.getPrice())
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,17 @@
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.moabam.api.application.bug.BugService;
import com.moabam.api.application.coupon.CouponService;
import com.moabam.api.domain.payment.Payment;
import com.moabam.api.domain.payment.repository.PaymentRepository;
import com.moabam.api.domain.payment.repository.PaymentSearchRepository;
import com.moabam.api.dto.payment.ConfirmPaymentRequest;
import com.moabam.api.dto.payment.ConfirmTossPaymentResponse;
import com.moabam.api.dto.payment.PaymentRequest;
import com.moabam.api.infrastructure.payment.TossPaymentMapper;
import com.moabam.api.infrastructure.payment.TossPaymentService;
import com.moabam.global.error.exception.MoabamException;
import com.moabam.global.error.exception.NotFoundException;

import lombok.RequiredArgsConstructor;
Expand All @@ -17,7 +25,11 @@
@RequiredArgsConstructor
public class PaymentService {

private final BugService bugService;
private final CouponService couponService;
private final TossPaymentService tossPaymentService;
private final PaymentRepository paymentRepository;
private final PaymentSearchRepository paymentSearchRepository;

@Transactional
public void request(Long memberId, Long paymentId, PaymentRequest request) {
Expand All @@ -26,8 +38,33 @@ public void request(Long memberId, Long paymentId, PaymentRequest request) {
payment.request(request.orderId());
}

@Transactional
public void confirm(Long memberId, ConfirmPaymentRequest request) {
Payment payment = getByOrderId(request.orderId());
payment.validateInfo(memberId, request.amount());

try {
ConfirmTossPaymentResponse response = tossPaymentService.confirm(
TossPaymentMapper.toConfirmRequest(request.paymentKey(), request.orderId(), request.amount())
);
payment.confirm(response.paymentKey(), response.approvedAt());

if (payment.isCouponApplied()) {
couponService.use(memberId, payment.getCouponWalletId());
}
bugService.charge(memberId, payment.getProduct());
} catch (MoabamException exception) {
payment.fail(request.paymentKey());
}
}

private Payment getById(Long paymentId) {
return paymentRepository.findById(paymentId)
.orElseThrow(() -> new NotFoundException(PAYMENT_NOT_FOUND));
}

private Payment getByOrderId(String orderId) {
return paymentSearchRepository.findByOrderId(orderId)
.orElseThrow(() -> new NotFoundException(PAYMENT_NOT_FOUND));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public static PurchaseProductResponse toPurchaseProductResponse(Payment payment)
return PurchaseProductResponse.builder()
.paymentId(payment.getId())
.orderName(payment.getOrder().getName())
.price(payment.getAmount())
.price(payment.getTotalAmount())
.build();
}
}
15 changes: 11 additions & 4 deletions src/main/java/com/moabam/api/domain/bug/Bug.java
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,17 @@ private void decreaseBug(BugType bugType, int bug) {
}

public void increaseBug(BugType bugType, int bug) {
switch (bugType) {
case MORNING -> this.morningBug += bug;
case NIGHT -> this.nightBug += bug;
case GOLDEN -> this.goldenBug += bug;
if (bugType.equals(BugType.MORNING)) {
this.morningBug += bug;
return;
}

if (bugType.equals(BugType.NIGHT)) {
this.nightBug += bug;
}
}

public void charge(int quantity) {
this.goldenBug += quantity;
}
}
Loading

0 comments on commit f3beca8

Please sign in to comment.