Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(server) : 정산금액을 계산해서 갱신하는 기능을 스케줄러에 등록한다. (#439) #440

Merged
merged 7 commits into from
Oct 8, 2021
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,20 @@
import com.example.tyfserver.common.util.SmtpMailConnector;
import com.example.tyfserver.donation.domain.Donation;
import com.example.tyfserver.donation.repository.DonationRepository;
import com.example.tyfserver.member.domain.*;
import com.example.tyfserver.member.domain.Account;
import com.example.tyfserver.member.domain.Exchange;
import com.example.tyfserver.member.domain.ExchangeStatus;
import com.example.tyfserver.member.domain.Member;
import com.example.tyfserver.member.dto.ExchangeAmountDto;
import com.example.tyfserver.member.exception.MemberNotFoundException;
import com.example.tyfserver.member.repository.ExchangeRepository;
import com.example.tyfserver.member.repository.MemberRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.YearMonth;
import java.util.ArrayList;
import java.util.List;

Expand Down Expand Up @@ -148,4 +154,17 @@ public TokenResponse login(AdminLoginRequest adminLoginRequest) {
String token = authenticationService.createAdminToken(adminLoginRequest.getId());
return new TokenResponse(token);
}

@Scheduled(cron = "0 0 0 1 * *")
public void calculateExchangeAmount() {
List<ExchangeAmountDto> exchangeAmountDtos = exchangeRepository.calculateExchangeAmountFromDonation(YearMonth.now());

exchangeAmountDtos.forEach(exchangeAmountDto -> {
exchangeRepository.findById(exchangeAmountDto.getExchangeId())
.ifPresentOrElse(exchange -> exchange.registerExchangeAmount(exchangeAmountDto.getExchangeAmount()),
() -> {
throw new NotRegisteredAccountException();
});
});
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

image

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Be-poz 그런데 회원마다 업데이트 되는 금액이 다른데 벌크 업데이트가 가능한거야?
전에 근로 때도 내가 정책 정할 일이 있었는데, 잘 몰라서 이거 bulk update 하는게 어떻냐구 했다가.... 잘 안돼서 작업자가 고생했거든

}
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package com.example.tyfserver.common.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.view.InternalResourceViewResolver;

@Configuration
@EnableScheduling
public class CommonConfig implements WebMvcConfigurer {

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,6 @@ public interface DonationQueryRepository {
Long exchangedTotalPoint(Long creatorId);

List<Donation> findDonationsToExchange(Member creator, YearMonth exchangeOn);

Long calculateExchangeAmountFromDonation(Member creator, YearMonth exchangeOn);
}
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,19 @@ public List<Donation> findDonationsToExchange(Member creator, YearMonth exchange
.fetch();
}

@Override
public Long calculateExchangeAmountFromDonation(Member creator, YearMonth exchangeOn) {
return queryFactory
.select(donation.point.sum())
.from(donation)
.where(
donationOwner(creator.getId()),
waitingForExchangeStatus(),
beforeStartOfNextMonth(exchangeOn)
)
.fetchOne();
}

private BooleanExpression waitingForExchangeStatus() {
return donation.status.eq(DonationStatus.WAITING_FOR_EXCHANGE);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ private void exchangeOn() {
}
}

public void registerExchangeAmount(Long exchangeAmount) {
this.exchangeAmount = exchangeAmount;
}

public void toApproved() {
status = ExchangeStatus.APPROVED;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.example.tyfserver.member.dto;

import com.querydsl.core.annotations.QueryProjection;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class ExchangeAmountDto {
private Long exchangeId;
private Long exchangeAmount;

@QueryProjection
public ExchangeAmountDto(Long exchangeId, Long exchangeAmount) {
this.exchangeId = exchangeId;
this.exchangeAmount = exchangeAmount;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.example.tyfserver.member.repository;

import com.example.tyfserver.member.dto.ExchangeAmountDto;

import java.time.YearMonth;
import java.util.List;

public interface ExchangeQueryRepository {
List<ExchangeAmountDto> calculateExchangeAmountFromDonation(YearMonth exchangeOn);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
List<ExchangeAmountDto> calculateExchangeAmountFromDonation(YearMonth exchangeOn);
List<ExchangeAmountDto> calculateExchangeAmountFromDonation(YearMonth exchangeOn);

다른 클래스들처럼 첫 줄은 띄우면 좋을 것 같아! 😃

}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

import java.util.List;

public interface ExchangeRepository extends JpaRepository<Exchange, Long> {
public interface ExchangeRepository extends JpaRepository<Exchange, Long>, ExchangeQueryRepository {

List<Exchange> findByStatusAndMember(ExchangeStatus status, Member member);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package com.example.tyfserver.member.repository;

import com.example.tyfserver.donation.domain.DonationStatus;
import com.example.tyfserver.member.domain.ExchangeStatus;
import com.example.tyfserver.member.dto.ExchangeAmountDto;
import com.example.tyfserver.member.dto.QExchangeAmountDto;
import com.querydsl.core.types.dsl.BooleanExpression;
import com.querydsl.jpa.impl.JPAQueryFactory;

import javax.persistence.EntityManager;
import java.time.LocalDateTime;
import java.time.YearMonth;
import java.util.List;

import static com.example.tyfserver.donation.domain.QDonation.donation;
import static com.example.tyfserver.member.domain.QExchange.exchange;

public class ExchangeRepositoryImpl implements ExchangeQueryRepository{

private final JPAQueryFactory queryFactory;

public ExchangeRepositoryImpl(EntityManager em) {
queryFactory = new JPAQueryFactory(em);
}

@Override
public List<ExchangeAmountDto> calculateExchangeAmountFromDonation(YearMonth exchangeOn) {
return queryFactory
.select(new QExchangeAmountDto(exchange.id, donation.point.sum()))
.from(exchange)
.leftJoin(exchange.member.receivedDonations, donation)
.groupBy(exchange.id)
.where(
exchange.status.eq(ExchangeStatus.WAITING),
waitingForExchangeStatus(),
beforeStartOfNextMonth(exchangeOn)
)
.fetch();
}

private BooleanExpression waitingForExchangeStatus() {
return donation.status.eq(DonationStatus.WAITING_FOR_EXCHANGE);
}

private BooleanExpression beforeStartOfNextMonth(YearMonth exchangeOn) {
// 정산신청일자 다음달 1일 00:00 이전
LocalDateTime startOfNextMonth = exchangeOn.plusMonths(1).atDay(1).atStartOfDay();
return donation.createdAt.before(startOfNextMonth);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,15 @@
import com.example.tyfserver.member.repository.ExchangeRepository;
import com.example.tyfserver.member.repository.MemberRepository;
import com.example.tyfserver.payment.repository.PaymentRepository;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
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.scheduling.config.CronTask;
import org.springframework.scheduling.config.ScheduledTaskHolder;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.EntityManager;
Expand Down Expand Up @@ -61,6 +64,8 @@ class AdminServiceTest {
private PaymentRepository paymentRepository;
@Autowired
private DonationRepository donationRepository;
@Autowired
private ScheduledTaskHolder scheduledTaskHolder;

@MockBean
private S3Connector s3Connector;
Expand Down Expand Up @@ -317,4 +322,19 @@ public void findRequestingAccounts() {
assertThat(response.getBank()).isEqualTo(findRequestingMember.getAccount().getBank());
assertThat(response.getBankbookImageUrl()).isEqualTo(findRequestingMember.getAccount().getBankbookUrl());
}

@Test
@DisplayName("매달 1일 00:00에 정산금액을 계산한다.")
public void calculateExchangeAmount() {
String methodName = AdminService.class.getName() + ".calculateExchangeAmount";
String cron = "0 0 0 1 * *";

long count = scheduledTaskHolder.getScheduledTasks().stream()
.filter(scheduledTask -> scheduledTask.getTask() instanceof CronTask)
.map(scheduledTask -> (CronTask) scheduledTask.getTask())
.filter(cronTask -> cronTask.getExpression().equals(cron) && cronTask.toString().equals(methodName))
.count();

Assertions.assertThat(count).isEqualTo(1L);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ public void exchangedTotalPoint() {

@Test
@DisplayName("정산해야하는 도네이션들을 조회한다.")
void findDonationsToExchange() {
public void findDonationsToExchange() {
// given
Member creator1 = initMember(3);
Member creator2 = initMember(4);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,21 @@
package com.example.tyfserver.member.repository;

import com.example.tyfserver.admin.dto.ExchangeResponse;
import com.example.tyfserver.common.config.JpaAuditingConfig;
import com.example.tyfserver.donation.domain.Donation;
import com.example.tyfserver.donation.domain.DonationStatus;
import com.example.tyfserver.donation.domain.Message;
import com.example.tyfserver.donation.repository.DonationRepository;
import com.example.tyfserver.member.domain.*;
import com.example.tyfserver.member.dto.ExchangeAmountDto;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.context.annotation.Import;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.YearMonth;
import java.util.List;

Expand All @@ -22,6 +28,8 @@ class ExchangeRepositoryTest {
@Autowired
private ExchangeRepository exchangeRepository;
@Autowired
private DonationRepository donationRepository;
@Autowired
private MemberRepository memberRepository;
@Autowired
private AccountRepository accountRepository;
Expand Down Expand Up @@ -68,4 +76,43 @@ void findByStatusAndMember() {
assertThat(exchange.getMember()).isEqualTo(member);
assertThat(exchange.getExchangeAmount()).isEqualTo(10000);
}

@Test
@DisplayName("정산해야 하는 도네이션들의 총 정산금액을 계산한다.")
public void calculateExchangeAmountFromDonation() {
//given
Member member = initMember(5);
member.receiveDonation(
donationRepository.save(new Donation(new Message(""), 5000, createdAt(1, 1))));
member.receiveDonation(
donationRepository.save(new Donation(new Message(""), 5000, createdAt(2, 1))));
member.receiveDonation(
donationRepository.save(new Donation(new Message(""), 5000,
LocalDateTime.of(2021, 2, 28, 23, 59))));

member.receiveDonation(donationRepository.save(new Donation(new Message(""), 5000,
createdAt(3, 1))));
member.receiveDonation(donationRepository.save(new Donation(new Message(""), 5000,
createdAt(12, 31))));
member.receiveDonation(donationRepository.save(new Donation(new Message(""), 5000, DonationStatus.EXCHANGED,
createdAt(1, 1))));

memberRepository.save(member);

Exchange exchange = new Exchange(0L, YearMonth.of(2021, 1), member);
exchangeRepository.save(exchange);
//when
List<ExchangeAmountDto> exchangeAmountDtos = exchangeRepository.calculateExchangeAmountFromDonation(YearMonth.of(2021, 2));

//then
assertThat(exchangeAmountDtos).hasSize(1);
assertThat(exchangeAmountDtos.get(0).getExchangeId()).isEqualTo(exchange.getId());
assertThat(exchangeAmountDtos.get(0).getExchangeAmount()).isEqualTo(15000);
}

private LocalDateTime createdAt(int month, int dayOfMonth) {
return LocalDate.of(2021, month, dayOfMonth).atStartOfDay();
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.example.tyfserver.auth.domain.Oauth2Type;
import com.example.tyfserver.common.config.JpaAuditingConfig;
import com.example.tyfserver.donation.domain.Donation;
import com.example.tyfserver.donation.domain.DonationStatus;
import com.example.tyfserver.donation.domain.DonationTest;
import com.example.tyfserver.member.domain.Account;
import com.example.tyfserver.member.domain.Member;
Expand All @@ -19,6 +20,7 @@
import org.springframework.context.annotation.Import;

import javax.persistence.EntityManager;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;

Expand Down Expand Up @@ -172,6 +174,12 @@ private Member initMember(int i) {
return member;
}

private void initDonation(Member member, long amount, DonationStatus status, LocalDateTime createAt) {
Donation donation = new Donation(DonationTest.testMessage(), amount, status, createAt);
member.receiveDonation(donation);
em.persist(donation);
}

private void initDonation(Member member, long amount) {
Donation donation = new Donation(DonationTest.testMessage(), amount);
member.receiveDonation(donation);
Expand Down