diff --git a/build.gradle b/build.gradle index 41f022be..5a69a7f2 100644 --- a/build.gradle +++ b/build.gradle @@ -22,6 +22,7 @@ repositories { } dependencies { + implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' implementation 'org.springframework.boot:spring-boot-starter-amqp' implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-data-redis' @@ -37,6 +38,10 @@ dependencies { testImplementation 'org.springframework.amqp:spring-rabbit-test' testImplementation 'org.springframework.security:spring-security-test' + // https://mvnrepository.com/artifact/com.slack.api/slack-api-client + // 슬랙 api 추가 + implementation group: 'com.slack.api', name: 'slack-api-client', version: '1.29.2' + implementation 'io.jsonwebtoken:jjwt-api:0.11.5' implementation 'io.jsonwebtoken:jjwt-impl:0.11.5' implementation 'io.jsonwebtoken:jjwt-jackson:0.11.5' diff --git a/src/main/java/com/postgraduate/domain/salary/application/usecase/SalaryManageUseCase.java b/src/main/java/com/postgraduate/domain/salary/application/usecase/SalaryManageUseCase.java index b1a5e683..61030755 100644 --- a/src/main/java/com/postgraduate/domain/salary/application/usecase/SalaryManageUseCase.java +++ b/src/main/java/com/postgraduate/domain/salary/application/usecase/SalaryManageUseCase.java @@ -7,11 +7,13 @@ import com.postgraduate.domain.salary.util.SalaryUtil; import com.postgraduate.domain.senior.domain.entity.Senior; import com.postgraduate.domain.senior.domain.service.SeniorGetService; +import com.postgraduate.global.slack.SlackMessage; import lombok.RequiredArgsConstructor; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.io.IOException; import java.time.LocalDate; import java.util.List; @@ -21,9 +23,11 @@ public class SalaryManageUseCase { private final SalarySaveService salarySaveService; private final SeniorGetService seniorGetService; + private final SlackMessage slackMessage; @Scheduled(cron = "0 0 0 10 * *", zone = "Asia/Seoul") - public void createSalary() { + public void createSalary() throws IOException { + slackMessage.sendSlackSalary(); List seniors = seniorGetService.all(); LocalDate salaryDate = SalaryUtil.getSalaryDate(); seniors.forEach(senior -> { diff --git a/src/main/java/com/postgraduate/domain/salary/domain/service/SalaryGetService.java b/src/main/java/com/postgraduate/domain/salary/domain/service/SalaryGetService.java index 45f27e3e..dbd52e0a 100644 --- a/src/main/java/com/postgraduate/domain/salary/domain/service/SalaryGetService.java +++ b/src/main/java/com/postgraduate/domain/salary/domain/service/SalaryGetService.java @@ -13,6 +13,7 @@ import org.springframework.stereotype.Service; import java.time.LocalDate; +import java.util.List; @Service @RequiredArgsConstructor @@ -31,4 +32,8 @@ public Page findDistinctSeniors(String search, Integer page) { Pageable pageable = PageRequest.of(page - 1, ADMIN_PAGE_SIZE); return salaryRepository.findDistinctBySearchSenior(search, pageable); } + + public List findAll() { + return salaryRepository.findAll(); + } } diff --git a/src/main/java/com/postgraduate/global/slack/SlackMessage.java b/src/main/java/com/postgraduate/global/slack/SlackMessage.java new file mode 100644 index 00000000..21fb883d --- /dev/null +++ b/src/main/java/com/postgraduate/global/slack/SlackMessage.java @@ -0,0 +1,87 @@ +package com.postgraduate.global.slack; + +import com.postgraduate.domain.salary.domain.entity.Salary; +import com.postgraduate.domain.salary.domain.service.SalaryGetService; +import com.slack.api.Slack; +import com.slack.api.model.Attachment; +import com.slack.api.model.Field; +import com.slack.api.webhook.Payload; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import java.io.IOException; +import java.time.LocalDate; +import java.util.List; + +@Slf4j +@Component +@RequiredArgsConstructor +public class SlackMessage { + private final Slack slackClient = Slack.getInstance(); + private final SalaryGetService salaryGetService; + + @Value("${slack.url}") + private String webHookUrl; + + public void sendSlackSalary() throws IOException{ + List salaries = salaryGetService.findAll(); + List attachments = salaries.stream() + .filter(salary -> salary.getTotalAmount() > 0) + .map(salary -> generateSalarySlackAttachment(salary)) + .toList(); + slackClient.send(webHookUrl, Payload.builder() + .text("---" + LocalDate.now() + "에 정산할 목록 ---") + .attachments(attachments) + .build()); + + Attachment attachment = generateSalarySlackAttachment(salaries); + slackClient.send(webHookUrl, Payload.builder() + .attachments(List.of(attachment)) + .build()); + } + + //attach 생성 -> Field를 리스트로 담자 + private Attachment generateSalarySlackAttachment(Salary salary) { + return Attachment.builder() + .color("#36a64f") + .fields(generateSalaryFields(salary)) + .build(); + } + + private Attachment generateSalarySlackAttachment(List salaries) { + return Attachment.builder() + .color("#1900ff") + .fields(generateTotalField(salaries)) + .build(); + } + + private List generateSalaryFields(Salary salary) { + return List.of( + generateSlackField( + "선배 닉네임 : " + salary.getSenior().getUser().getNickName(), + "금액 : " + salary.getTotalAmount() + )); + } + + private List generateTotalField(List salaries) { + Integer totalAmount = salaries.stream() + .map(Salary::getTotalAmount) + .reduce(0, Integer::sum); + + return List.of( + generateSlackField( + "총 정산 금액", String.valueOf(totalAmount) + "원" + )); + } + + // Field 생성 메서드 + private Field generateSlackField(String title, String value) { + return Field.builder() + .title(title) + .value(value) + .valueShortEnough(false) + .build(); + } +} \ No newline at end of file