From edd439074e77f32325e9d6d8d7e43844001d9ff2 Mon Sep 17 00:00:00 2001 From: Chan Jin Date: Mon, 3 Apr 2023 00:00:20 +0900 Subject: [PATCH] =?UTF-8?q?refactor=20:=20=EB=B0=B0=EC=B9=98=20=EC=9D=B4?= =?UTF-8?q?=EB=B2=A4=ED=8A=B8=20=EC=A0=95=EC=82=B0=20=ED=94=84=EB=A1=9C?= =?UTF-8?q?=EC=84=B8=EC=8A=A4=20=EC=86=8C=EC=8A=A4=20=EC=A0=95=EB=A6=AC=20?= =?UTF-8?q?(#554)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor : event 오더 주문 잡 리펙터링 * refactor : 정산 관련 이메일 발송 잡 리펙토링 * refactor : 정산 정보 저장 잡 리팩토링 * refactor : 이벤트 정산요약 리팩토링 * style : 주석추가 * fix : try - resource 형태로 엑셀 열기 --- .../band/gosrock/excel/ExcelOrderHelper.java | 120 ---------------- .../gosrock/helper/SettlementEmailHelper.java | 64 +++++++++ .../gosrock/helper/SettlementPdfHelper.java | 69 +++++++++ .../{ => helper}/excel/ExcelOrderDto.java | 2 +- .../helper/excel/ExcelOrderHelper.java | 133 ++++++++++++++++++ .../slack/SlackEventExpirationSender.java | 2 +- .../slack/SlackUserNotificationSender.java | 2 +- .../band/gosrock/job/EventExpiration.java | 2 +- .../band/gosrock/job/EventOrdersToExcel.java | 43 ++---- .../job/EventSettlementEmailToAdmin.java | 57 +------- .../job/EventSettlementEmailToHost.java | 49 +------ .../band/gosrock/job/EventSettlementPDF.java | 61 +------- .../gosrock/job/EventSummarySettlement.java | 88 +----------- .../job/EventTransactionSettlement.java | 67 +++++---- .../band/gosrock/job/SlackUserStatistic.java | 2 +- .../domain/domains/event/domain/Event.java | 4 + .../service/EventSettlementDomainService.java | 90 +++++++++++- .../config/s3/S3PrivateFileService.java | 16 ++- .../config/ses/AwsSesUtils.java | 4 +- 19 files changed, 435 insertions(+), 440 deletions(-) delete mode 100644 DuDoong-Batch/src/main/java/band/gosrock/excel/ExcelOrderHelper.java create mode 100644 DuDoong-Batch/src/main/java/band/gosrock/helper/SettlementEmailHelper.java create mode 100644 DuDoong-Batch/src/main/java/band/gosrock/helper/SettlementPdfHelper.java rename DuDoong-Batch/src/main/java/band/gosrock/{ => helper}/excel/ExcelOrderDto.java (97%) create mode 100644 DuDoong-Batch/src/main/java/band/gosrock/helper/excel/ExcelOrderHelper.java rename DuDoong-Batch/src/main/java/band/gosrock/{ => helper}/slack/SlackEventExpirationSender.java (98%) rename DuDoong-Batch/src/main/java/band/gosrock/{ => helper}/slack/SlackUserNotificationSender.java (98%) diff --git a/DuDoong-Batch/src/main/java/band/gosrock/excel/ExcelOrderHelper.java b/DuDoong-Batch/src/main/java/band/gosrock/excel/ExcelOrderHelper.java deleted file mode 100644 index 9bb9583d..00000000 --- a/DuDoong-Batch/src/main/java/band/gosrock/excel/ExcelOrderHelper.java +++ /dev/null @@ -1,120 +0,0 @@ -package band.gosrock.excel; - - -import java.lang.reflect.Field; -import java.time.LocalDateTime; -import java.time.format.DateTimeFormatter; -import java.util.Arrays; -import java.util.List; -import java.util.stream.IntStream; -import org.apache.poi.ss.usermodel.Cell; -import org.apache.poi.ss.usermodel.CellStyle; -import org.apache.poi.ss.usermodel.FillPatternType; -import org.apache.poi.ss.usermodel.IndexedColors; -import org.apache.poi.ss.usermodel.Row; -import org.apache.poi.ss.usermodel.Sheet; -import org.apache.poi.ss.usermodel.Workbook; -import org.apache.poi.xssf.usermodel.XSSFFont; -import org.apache.poi.xssf.usermodel.XSSFWorkbook; -import org.springframework.stereotype.Component; - -@Component -public class ExcelOrderHelper { - - DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"); - - public Workbook execute(List excelOrders) { - Workbook workbook = new XSSFWorkbook(); - - Field[] declaredFields = ExcelOrderDto.class.getDeclaredFields(); - - List fieldNames = Arrays.stream(declaredFields).map(Field::getName).toList(); - Sheet sheet = workbook.createSheet("orderList"); - sheet.setColumnWidth(0, 6000); - sheet.setColumnWidth(1, 6000); - sheet.setColumnWidth(2, 6000); - sheet.setColumnWidth(3, 6000); - sheet.setColumnWidth(4, 6000); - sheet.setColumnWidth(5, 6000); - sheet.setColumnWidth(6, 6000); - sheet.setColumnWidth(7, 6000); - sheet.setColumnWidth(8, 6000); - // create header - Row header = sheet.createRow(0); - CellStyle headerStyle = workbook.createCellStyle(); - headerStyle.setFillForegroundColor(IndexedColors.LIGHT_GREEN.getIndex()); - headerStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND); - XSSFFont font = ((XSSFWorkbook) workbook).createFont(); - font.setFontName("Arial"); - font.setFontHeightInPoints((short) 16); - font.setBold(true); - headerStyle.setFont(font); - - Cell headerCell0 = header.createCell(0); - headerCell0.setCellValue("주문번호"); - headerCell0.setCellStyle(headerStyle); - - Cell headerCell1 = header.createCell(1); - headerCell1.setCellValue("주문 방식"); - headerCell1.setCellStyle(headerStyle); - - Cell headerCell2 = header.createCell(2); - headerCell2.setCellValue("주문 상태"); - headerCell2.setCellStyle(headerStyle); - - Cell headerCell3 = header.createCell(3); - headerCell3.setCellValue("주문 이름"); - headerCell3.setCellStyle(headerStyle); - - Cell headerCell4 = header.createCell(4); - headerCell4.setCellValue("주문자 아이디"); - headerCell4.setCellStyle(headerStyle); - - Cell headerCell5 = header.createCell(5); - headerCell5.setCellValue("총액"); - headerCell5.setCellStyle(headerStyle); - - Cell headerCell6 = header.createCell(6); - headerCell6.setCellValue("티켓 수량"); - headerCell6.setCellStyle(headerStyle); - - Cell headerCell7 = header.createCell(7); - headerCell7.setCellValue("생성 일시"); - headerCell7.setCellStyle(headerStyle); - - Cell headerCell8 = header.createCell(8); - headerCell8.setCellValue("환불 일시"); - headerCell8.setCellStyle(headerStyle); - - CellStyle style = workbook.createCellStyle(); - style.setWrapText(true); - IntStream.range(0, excelOrders.size()) - .forEach( - idx -> { - Row row = sheet.createRow(idx + 1); - ExcelOrderDto excelOrderDto = excelOrders.get(idx); - row.createCell(0).setCellValue(excelOrderDto.getOrderNo()); - - row.createCell(1).setCellValue(excelOrderDto.getOrderMethod().getKr()); - - row.createCell(2).setCellValue(excelOrderDto.getOrderStatus().getKr()); - - row.createCell(3).setCellValue(excelOrderDto.getOrderName()); - - row.createCell(4).setCellValue(excelOrderDto.getUserId()); - - row.createCell(5).setCellValue(excelOrderDto.getAmount().toString()); - - row.createCell(6).setCellValue(excelOrderDto.getQuantity()); - - row.createCell(7) - .setCellValue(excelOrderDto.getCreatedAt().format(formatter)); - - LocalDateTime refundAt = excelOrderDto.getRefundAt(); - row.createCell(8) - .setCellValue( - refundAt != null ? refundAt.format(formatter) : null); - }); - return workbook; - } -} diff --git a/DuDoong-Batch/src/main/java/band/gosrock/helper/SettlementEmailHelper.java b/DuDoong-Batch/src/main/java/band/gosrock/helper/SettlementEmailHelper.java new file mode 100644 index 00000000..1a7ec4ca --- /dev/null +++ b/DuDoong-Batch/src/main/java/band/gosrock/helper/SettlementEmailHelper.java @@ -0,0 +1,64 @@ +package band.gosrock.helper; + + +import band.gosrock.common.annotation.Helper; +import band.gosrock.domain.domains.event.domain.Event; +import band.gosrock.infrastructure.config.s3.S3PrivateFileService; +import band.gosrock.infrastructure.config.ses.AwsSesUtils; +import band.gosrock.infrastructure.config.ses.RawEmailAttachmentDto; +import band.gosrock.infrastructure.config.ses.SendRawEmailDto; +import javax.mail.MessagingException; +import lombok.RequiredArgsConstructor; +import org.thymeleaf.context.Context; +import org.thymeleaf.spring5.SpringTemplateEngine; + +@Helper +@RequiredArgsConstructor +public class SettlementEmailHelper { + private final SpringTemplateEngine templateEngine; + + private final S3PrivateFileService s3PrivateFileService; + private final AwsSesUtils awsSesUtils; + + private RawEmailAttachmentDto getSettlementPdfAttachment(Event event) { + return RawEmailAttachmentDto.builder() + .fileName(event.getEventName() + "_정산서.pdf") + .fileBytes(s3PrivateFileService.downloadEventSettlementPdf(event.getId())) + .type("application/pdf") + .build(); + } + + private RawEmailAttachmentDto getOrderListExcelAttachment(Event event) { + return RawEmailAttachmentDto.builder() + .fileName(event.getEventName() + "_주문목록.xlsx") + .fileBytes(s3PrivateFileService.downloadEventOrdersExcel(event.getId())) + .type("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet") + .build(); + } + + public void sendToAdmin(Event event) throws MessagingException { + SendRawEmailDto sendRawEmailDto = + SendRawEmailDto.builder() + .bodyHtml(templateEngine.process("eventSettlement", new Context())) + .recipient("support@dudoong.com") + .subject(event.getEventName() + "공연 정산서 어드민 발송 ( 관리자용 )") + .build(); + + sendRawEmailDto.addEmailAttachments(getSettlementPdfAttachment(event)); + sendRawEmailDto.addEmailAttachments(getOrderListExcelAttachment(event)); + awsSesUtils.sendRawEmails(sendRawEmailDto); + } + + public void sendToHost(Event event, String hostUserEmail) throws MessagingException { + SendRawEmailDto sendRawEmailDto = + SendRawEmailDto.builder() + .bodyHtml(templateEngine.process("eventSettlement", new Context())) + .recipient(hostUserEmail) + .subject(event.getEventName() + "공연 정산관련 안내") + .build(); + + sendRawEmailDto.addEmailAttachments(getSettlementPdfAttachment(event)); + sendRawEmailDto.addEmailAttachments(getOrderListExcelAttachment(event)); + awsSesUtils.sendRawEmails(sendRawEmailDto); + } +} diff --git a/DuDoong-Batch/src/main/java/band/gosrock/helper/SettlementPdfHelper.java b/DuDoong-Batch/src/main/java/band/gosrock/helper/SettlementPdfHelper.java new file mode 100644 index 00000000..53792d6f --- /dev/null +++ b/DuDoong-Batch/src/main/java/band/gosrock/helper/SettlementPdfHelper.java @@ -0,0 +1,69 @@ +package band.gosrock.helper; + + +import band.gosrock.common.annotation.Helper; +import band.gosrock.domain.common.vo.Money; +import band.gosrock.domain.domains.event.domain.Event; +import band.gosrock.domain.domains.settlement.domain.EventSettlement; +import band.gosrock.domain.domains.user.domain.User; +import band.gosrock.dto.SettlementPDFDto; +import band.gosrock.infrastructure.config.pdf.PdfRender; +import band.gosrock.infrastructure.config.s3.S3PrivateFileService; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.lowagie.text.DocumentException; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.time.LocalDateTime; +import java.util.Map; +import lombok.RequiredArgsConstructor; +import org.thymeleaf.context.Context; +import org.thymeleaf.spring5.SpringTemplateEngine; + +@Helper +@RequiredArgsConstructor +public class SettlementPdfHelper { + private final PdfRender pdfRender; + + private final ObjectMapper objectMapper; + + private final SpringTemplateEngine templateEngine; + + private final S3PrivateFileService s3PrivateFileUploadService; + + public void uploadPdfToS3(Event event, EventSettlement eventSettlement, User masterUser) + throws DocumentException, IOException { + SettlementPDFDto settlementPDFDto = getSettlementPDFDto(event, masterUser, eventSettlement); + // 정산 관련 타임리프 파일. + String html = templateEngine.process("settlement", getPdfHtmlContext(settlementPDFDto)); + ByteArrayOutputStream outputStream = pdfRender.generatePdfFromHtml(html); + s3PrivateFileUploadService.eventSettlementPdfUpload(event.getId(), outputStream); + } + + private Context getPdfHtmlContext(SettlementPDFDto settlementPDFDto) { + Map result = objectMapper.convertValue(settlementPDFDto, Map.class); + + Context context = new Context(null, result); + context.setVariable("settlementAt", settlementPDFDto.getSettlementAt()); + context.setVariable("now", settlementPDFDto.getNow()); + return context; + } + + private SettlementPDFDto getSettlementPDFDto( + Event event, User masterUser, EventSettlement eventSettlement) { + return SettlementPDFDto.builder() + .eventTitle(event.getEventBasic().getName()) + .hostName(masterUser.getProfile().getName()) + .settlementAt(event.getEndAt().plusDays(6L)) + .dudoongTicketAmount(eventSettlement.getDudoongAmount().toString()) + .pgTicketAmount(eventSettlement.getPaymentAmount().toString()) + .totalAmount(eventSettlement.getTotalSalesAmount().toString()) + // 초기 두둥 자체 수수료 없음. + .dudoongFee(Money.ZERO.toString()) + .pgFee(eventSettlement.getPgFee().toString()) + .totalFee(eventSettlement.getPgFee().toString()) + .totalFeeVat(eventSettlement.getPgFeeVat().toString()) + .totalSettlement(eventSettlement.getTotalAmount().toString()) + .now(LocalDateTime.now()) + .build(); + } +} diff --git a/DuDoong-Batch/src/main/java/band/gosrock/excel/ExcelOrderDto.java b/DuDoong-Batch/src/main/java/band/gosrock/helper/excel/ExcelOrderDto.java similarity index 97% rename from DuDoong-Batch/src/main/java/band/gosrock/excel/ExcelOrderDto.java rename to DuDoong-Batch/src/main/java/band/gosrock/helper/excel/ExcelOrderDto.java index 3ca69177..0826b7f7 100644 --- a/DuDoong-Batch/src/main/java/band/gosrock/excel/ExcelOrderDto.java +++ b/DuDoong-Batch/src/main/java/band/gosrock/helper/excel/ExcelOrderDto.java @@ -1,4 +1,4 @@ -package band.gosrock.excel; +package band.gosrock.helper.excel; import band.gosrock.domain.common.vo.Money; diff --git a/DuDoong-Batch/src/main/java/band/gosrock/helper/excel/ExcelOrderHelper.java b/DuDoong-Batch/src/main/java/band/gosrock/helper/excel/ExcelOrderHelper.java new file mode 100644 index 00000000..238c495b --- /dev/null +++ b/DuDoong-Batch/src/main/java/band/gosrock/helper/excel/ExcelOrderHelper.java @@ -0,0 +1,133 @@ +package band.gosrock.helper.excel; + + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.lang.reflect.Field; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.Arrays; +import java.util.List; +import java.util.stream.IntStream; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.CellStyle; +import org.apache.poi.ss.usermodel.FillPatternType; +import org.apache.poi.ss.usermodel.IndexedColors; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.usermodel.Workbook; +import org.apache.poi.xssf.usermodel.XSSFFont; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; +import org.springframework.stereotype.Component; + +@Component +public class ExcelOrderHelper { + + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"); + + public ByteArrayOutputStream execute(List excelOrders) { + try (Workbook workbook = new XSSFWorkbook()) { + Field[] declaredFields = ExcelOrderDto.class.getDeclaredFields(); + + List fieldNames = Arrays.stream(declaredFields).map(Field::getName).toList(); + Sheet sheet = workbook.createSheet("orderList"); + sheet.setColumnWidth(0, 6000); + sheet.setColumnWidth(1, 6000); + sheet.setColumnWidth(2, 6000); + sheet.setColumnWidth(3, 6000); + sheet.setColumnWidth(4, 6000); + sheet.setColumnWidth(5, 6000); + sheet.setColumnWidth(6, 6000); + sheet.setColumnWidth(7, 6000); + sheet.setColumnWidth(8, 6000); + // create header + Row header = sheet.createRow(0); + CellStyle headerStyle = workbook.createCellStyle(); + headerStyle.setFillForegroundColor(IndexedColors.LIGHT_GREEN.getIndex()); + headerStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND); + XSSFFont font = ((XSSFWorkbook) workbook).createFont(); + font.setFontName("Arial"); + font.setFontHeightInPoints((short) 16); + font.setBold(true); + headerStyle.setFont(font); + + Cell headerCell0 = header.createCell(0); + headerCell0.setCellValue("주문번호"); + headerCell0.setCellStyle(headerStyle); + + Cell headerCell1 = header.createCell(1); + headerCell1.setCellValue("주문 방식"); + headerCell1.setCellStyle(headerStyle); + + Cell headerCell2 = header.createCell(2); + headerCell2.setCellValue("주문 상태"); + headerCell2.setCellStyle(headerStyle); + + Cell headerCell3 = header.createCell(3); + headerCell3.setCellValue("주문 이름"); + headerCell3.setCellStyle(headerStyle); + + Cell headerCell4 = header.createCell(4); + headerCell4.setCellValue("주문자 아이디"); + headerCell4.setCellStyle(headerStyle); + + Cell headerCell5 = header.createCell(5); + headerCell5.setCellValue("총액"); + headerCell5.setCellStyle(headerStyle); + + Cell headerCell6 = header.createCell(6); + headerCell6.setCellValue("티켓 수량"); + headerCell6.setCellStyle(headerStyle); + + Cell headerCell7 = header.createCell(7); + headerCell7.setCellValue("생성 일시"); + headerCell7.setCellStyle(headerStyle); + + Cell headerCell8 = header.createCell(8); + headerCell8.setCellValue("환불 일시"); + headerCell8.setCellStyle(headerStyle); + + CellStyle style = workbook.createCellStyle(); + style.setWrapText(true); + IntStream.range(0, excelOrders.size()) + .forEach( + idx -> { + Row row = sheet.createRow(idx + 1); + ExcelOrderDto excelOrderDto = excelOrders.get(idx); + row.createCell(0).setCellValue(excelOrderDto.getOrderNo()); + + row.createCell(1) + .setCellValue(excelOrderDto.getOrderMethod().getKr()); + + row.createCell(2) + .setCellValue(excelOrderDto.getOrderStatus().getKr()); + + row.createCell(3).setCellValue(excelOrderDto.getOrderName()); + + row.createCell(4).setCellValue(excelOrderDto.getUserId()); + + row.createCell(5) + .setCellValue(excelOrderDto.getAmount().toString()); + + row.createCell(6).setCellValue(excelOrderDto.getQuantity()); + + row.createCell(7) + .setCellValue( + excelOrderDto.getCreatedAt().format(formatter)); + + LocalDateTime refundAt = excelOrderDto.getRefundAt(); + row.createCell(8) + .setCellValue( + refundAt != null + ? refundAt.format(formatter) + : null); + }); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + workbook.write(outputStream); + workbook.close(); + return outputStream; + } catch (IOException e) { + throw new RuntimeException(e); + } + } +} diff --git a/DuDoong-Batch/src/main/java/band/gosrock/slack/SlackEventExpirationSender.java b/DuDoong-Batch/src/main/java/band/gosrock/helper/slack/SlackEventExpirationSender.java similarity index 98% rename from DuDoong-Batch/src/main/java/band/gosrock/slack/SlackEventExpirationSender.java rename to DuDoong-Batch/src/main/java/band/gosrock/helper/slack/SlackEventExpirationSender.java index 67f599c4..7c88d8bf 100644 --- a/DuDoong-Batch/src/main/java/band/gosrock/slack/SlackEventExpirationSender.java +++ b/DuDoong-Batch/src/main/java/band/gosrock/helper/slack/SlackEventExpirationSender.java @@ -1,4 +1,4 @@ -package band.gosrock.slack; +package band.gosrock.helper.slack; import static com.slack.api.model.block.Blocks.divider; import static com.slack.api.model.block.Blocks.section; diff --git a/DuDoong-Batch/src/main/java/band/gosrock/slack/SlackUserNotificationSender.java b/DuDoong-Batch/src/main/java/band/gosrock/helper/slack/SlackUserNotificationSender.java similarity index 98% rename from DuDoong-Batch/src/main/java/band/gosrock/slack/SlackUserNotificationSender.java rename to DuDoong-Batch/src/main/java/band/gosrock/helper/slack/SlackUserNotificationSender.java index 7183d8f1..57fcac41 100644 --- a/DuDoong-Batch/src/main/java/band/gosrock/slack/SlackUserNotificationSender.java +++ b/DuDoong-Batch/src/main/java/band/gosrock/helper/slack/SlackUserNotificationSender.java @@ -1,4 +1,4 @@ -package band.gosrock.slack; +package band.gosrock.helper.slack; import static com.slack.api.model.block.Blocks.divider; import static com.slack.api.model.block.Blocks.section; diff --git a/DuDoong-Batch/src/main/java/band/gosrock/job/EventExpiration.java b/DuDoong-Batch/src/main/java/band/gosrock/job/EventExpiration.java index 592ab92e..0d28d49d 100644 --- a/DuDoong-Batch/src/main/java/band/gosrock/job/EventExpiration.java +++ b/DuDoong-Batch/src/main/java/band/gosrock/job/EventExpiration.java @@ -3,8 +3,8 @@ import band.gosrock.domain.domains.event.domain.Event; import band.gosrock.domain.domains.event.service.EventService; +import band.gosrock.helper.slack.SlackEventExpirationSender; import band.gosrock.parameter.DateTimeJobParameter; -import band.gosrock.slack.SlackEventExpirationSender; import java.time.LocalDateTime; import java.util.List; import lombok.RequiredArgsConstructor; diff --git a/DuDoong-Batch/src/main/java/band/gosrock/job/EventOrdersToExcel.java b/DuDoong-Batch/src/main/java/band/gosrock/job/EventOrdersToExcel.java index 1c145b2b..6a219447 100644 --- a/DuDoong-Batch/src/main/java/band/gosrock/job/EventOrdersToExcel.java +++ b/DuDoong-Batch/src/main/java/band/gosrock/job/EventOrdersToExcel.java @@ -5,15 +5,13 @@ import band.gosrock.domain.domains.event.domain.Event; import band.gosrock.domain.domains.order.adaptor.OrderAdaptor; import band.gosrock.domain.domains.order.domain.Order; -import band.gosrock.excel.ExcelOrderDto; -import band.gosrock.excel.ExcelOrderHelper; +import band.gosrock.helper.excel.ExcelOrderDto; +import band.gosrock.helper.excel.ExcelOrderHelper; import band.gosrock.infrastructure.config.s3.S3PrivateFileService; import band.gosrock.parameter.EventJobParameter; -import java.io.ByteArrayOutputStream; import java.util.List; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.apache.poi.ss.usermodel.Workbook; import org.springframework.batch.core.Job; import org.springframework.batch.core.Step; import org.springframework.batch.core.configuration.annotation.JobBuilderFactory; @@ -24,6 +22,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +/** 공연 관련 주문 목록을 엑셀화 하여 프라이빗한 S3에 저장합니다. */ @Slf4j @RequiredArgsConstructor @Configuration @@ -65,34 +64,20 @@ public Step userStatisticStep() { Event event = eventJobParameter.getEvent(); List eventOrders = orderAdaptor.findByEventId(event.getId()); - // 주문 상태가 결제 완료, 승인 완료 , 환불 , 취소 인것만 가져오도록 필터링. - List excelOrders = - eventOrders.stream() - .filter( - order -> - order.getOrderStatus() - .isInEventOrderExcelStatus()) - .map(ExcelOrderDto::from) - .toList(); - - // 엑셀에 만들기 - // 주문 번호 , 주문 방식 , 유저아이디 , 주문 이름 , 매수 , 총 결제금액 , 일시 , 환불일시. - Workbook workbook = excelOrderHelper.execute(excelOrders); - ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); - workbook.write(outputStream); - workbook.close(); - - String fileKey = - s3PrivateFileUploadService.eventOrdersExcelUpload( - event.getId(), outputStream); - // 이벤트 정산용 엑셀 파일 업로드 정보 저장 - // 파일 키 형식 맞출꺼라서 필요없을듯. - // - // eventSettlementDomainService.updateEventOrderListExcelFileKey( - // event.getId(), fileKey); + List excelOrders = getExcelOrders(eventOrders); + s3PrivateFileUploadService.eventOrdersExcelUpload( + event.getId(), excelOrderHelper.execute(excelOrders)); return RepeatStatus.FINISHED; }) .build(); } + + // 주문 상태가 결제 완료, 승인 완료 , 환불 , 취소 인것만 가져오도록 필터링. + private List getExcelOrders(List eventOrders) { + return eventOrders.stream() + .filter(order -> order.getOrderStatus().isInEventOrderExcelStatus()) + .map(ExcelOrderDto::from) + .toList(); + } } diff --git a/DuDoong-Batch/src/main/java/band/gosrock/job/EventSettlementEmailToAdmin.java b/DuDoong-Batch/src/main/java/band/gosrock/job/EventSettlementEmailToAdmin.java index 957f56cb..c2ecf5f4 100644 --- a/DuDoong-Batch/src/main/java/band/gosrock/job/EventSettlementEmailToAdmin.java +++ b/DuDoong-Batch/src/main/java/band/gosrock/job/EventSettlementEmailToAdmin.java @@ -3,14 +3,7 @@ import band.gosrock.domain.domains.event.adaptor.EventAdaptor; import band.gosrock.domain.domains.event.domain.Event; -import band.gosrock.domain.domains.host.adaptor.HostAdaptor; -import band.gosrock.domain.domains.host.domain.Host; -import band.gosrock.domain.domains.user.adaptor.UserAdaptor; -import band.gosrock.domain.domains.user.domain.User; -import band.gosrock.infrastructure.config.s3.S3PrivateFileService; -import band.gosrock.infrastructure.config.ses.AwsSesUtils; -import band.gosrock.infrastructure.config.ses.RawEmailAttachmentDto; -import band.gosrock.infrastructure.config.ses.SendRawEmailDto; +import band.gosrock.helper.SettlementEmailHelper; import band.gosrock.parameter.EventJobParameter; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -23,8 +16,6 @@ import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.thymeleaf.context.Context; -import org.thymeleaf.spring5.SpringTemplateEngine; @Slf4j @RequiredArgsConstructor @@ -38,14 +29,7 @@ public class EventSettlementEmailToAdmin { private final StepBuilderFactory stepBuilderFactory; private final EventAdaptor eventAdaptor; - private final HostAdaptor hostAdaptor; - private final UserAdaptor userAdaptor; - - private final SpringTemplateEngine templateEngine; - - private final S3PrivateFileService s3PrivateFileUploadService; - - private final AwsSesUtils awsSesUtils; + private final SettlementEmailHelper settlementEmailHelper; @Bean(BEAN_PREFIX + "eventJobParameter") @JobScope @@ -69,42 +53,7 @@ public Step userStatisticStep() { .tasklet( (contribution, chunkContext) -> { Event event = eventJobParameter.getEvent(); - String eventName = event.getEventBasic().getName(); - Long eventId = event.getId(); - Host host = hostAdaptor.findById(event.getHostId()); - User masterUser = userAdaptor.queryUser(host.getMasterUserId()); - byte[] eventSettlementPdf = - s3PrivateFileUploadService.downloadEventSettlementPdf(eventId); - RawEmailAttachmentDto eventSettlementPdfAttachment = - RawEmailAttachmentDto.builder() - .fileName(eventName + "_정산서.pdf") - .fileBytes(eventSettlementPdf) - .type("application/pdf") - .build(); - - byte[] eventOrderListExcel = - s3PrivateFileUploadService.downloadEventOrdersExcel(eventId); - RawEmailAttachmentDto eventOrderListExcelAttachment = - RawEmailAttachmentDto.builder() - .fileName(eventName + "_주문목록.xlsx") - .fileBytes(eventOrderListExcel) - .type( - "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet") - .build(); - - SendRawEmailDto sendRawEmailDto = - SendRawEmailDto.builder() - .bodyHtml( - templateEngine.process( - "eventSettlement", new Context())) - .recipient("support@dudoong.com") - .subject(eventName + "공연 정산서 어드민 발송 ( 관리자용 )") - .build(); - - sendRawEmailDto.addEmailAttachments(eventSettlementPdfAttachment); - sendRawEmailDto.addEmailAttachments(eventOrderListExcelAttachment); - - awsSesUtils.sendRawEmails(sendRawEmailDto); + settlementEmailHelper.sendToAdmin(event); return RepeatStatus.FINISHED; }) .build(); diff --git a/DuDoong-Batch/src/main/java/band/gosrock/job/EventSettlementEmailToHost.java b/DuDoong-Batch/src/main/java/band/gosrock/job/EventSettlementEmailToHost.java index c9620cee..63ff275b 100644 --- a/DuDoong-Batch/src/main/java/band/gosrock/job/EventSettlementEmailToHost.java +++ b/DuDoong-Batch/src/main/java/band/gosrock/job/EventSettlementEmailToHost.java @@ -7,10 +7,7 @@ import band.gosrock.domain.domains.host.domain.Host; import band.gosrock.domain.domains.user.adaptor.UserAdaptor; import band.gosrock.domain.domains.user.domain.User; -import band.gosrock.infrastructure.config.s3.S3PrivateFileService; -import band.gosrock.infrastructure.config.ses.AwsSesUtils; -import band.gosrock.infrastructure.config.ses.RawEmailAttachmentDto; -import band.gosrock.infrastructure.config.ses.SendRawEmailDto; +import band.gosrock.helper.SettlementEmailHelper; import band.gosrock.parameter.EventJobParameter; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -23,8 +20,6 @@ import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.thymeleaf.context.Context; -import org.thymeleaf.spring5.SpringTemplateEngine; @Slf4j @RequiredArgsConstructor @@ -37,15 +32,10 @@ public class EventSettlementEmailToHost { private final JobBuilderFactory jobBuilderFactory; private final StepBuilderFactory stepBuilderFactory; private final EventAdaptor eventAdaptor; - private final HostAdaptor hostAdaptor; private final UserAdaptor userAdaptor; - private final SpringTemplateEngine templateEngine; - - private final S3PrivateFileService s3PrivateFileUploadService; - - private final AwsSesUtils awsSesUtils; + private final SettlementEmailHelper settlementEmailHelper; @Bean(BEAN_PREFIX + "eventJobParameter") @JobScope @@ -69,42 +59,11 @@ public Step userStatisticStep() { .tasklet( (contribution, chunkContext) -> { Event event = eventJobParameter.getEvent(); - String eventName = event.getEventBasic().getName(); - Long eventId = event.getId(); Host host = hostAdaptor.findById(event.getHostId()); User masterUser = userAdaptor.queryUser(host.getMasterUserId()); - byte[] eventSettlementPdf = - s3PrivateFileUploadService.downloadEventSettlementPdf(eventId); - RawEmailAttachmentDto eventSettlementPdfAttachment = - RawEmailAttachmentDto.builder() - .fileName(eventName + "_정산서.pdf") - .fileBytes(eventSettlementPdf) - .type("application/pdf") - .build(); - - byte[] eventOrderListExcel = - s3PrivateFileUploadService.downloadEventOrdersExcel(eventId); - RawEmailAttachmentDto eventOrderListExcelAttachment = - RawEmailAttachmentDto.builder() - .fileName(eventName + "_주문목록.xlsx") - .fileBytes(eventOrderListExcel) - .type( - "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet") - .build(); - - SendRawEmailDto sendRawEmailDto = - SendRawEmailDto.builder() - .bodyHtml( - templateEngine.process( - "eventSettlement", new Context())) - .recipient(masterUser.getProfile().getEmail()) - .subject(eventName + "공연 정산관련 안내") - .build(); - - sendRawEmailDto.addEmailAttachments(eventSettlementPdfAttachment); - sendRawEmailDto.addEmailAttachments(eventOrderListExcelAttachment); + settlementEmailHelper.sendToHost( + event, masterUser.getProfile().getEmail()); - awsSesUtils.sendRawEmails(sendRawEmailDto); return RepeatStatus.FINISHED; }) .build(); diff --git a/DuDoong-Batch/src/main/java/band/gosrock/job/EventSettlementPDF.java b/DuDoong-Batch/src/main/java/band/gosrock/job/EventSettlementPDF.java index 01c9c18c..7798ec51 100644 --- a/DuDoong-Batch/src/main/java/band/gosrock/job/EventSettlementPDF.java +++ b/DuDoong-Batch/src/main/java/band/gosrock/job/EventSettlementPDF.java @@ -1,7 +1,6 @@ package band.gosrock.job; -import band.gosrock.domain.common.vo.Money; import band.gosrock.domain.domains.event.adaptor.EventAdaptor; import band.gosrock.domain.domains.event.domain.Event; import band.gosrock.domain.domains.host.adaptor.HostAdaptor; @@ -10,14 +9,8 @@ import band.gosrock.domain.domains.settlement.domain.EventSettlement; import band.gosrock.domain.domains.user.adaptor.UserAdaptor; import band.gosrock.domain.domains.user.domain.User; -import band.gosrock.dto.SettlementPDFDto; -import band.gosrock.infrastructure.config.pdf.PdfRender; -import band.gosrock.infrastructure.config.s3.S3PrivateFileService; +import band.gosrock.helper.SettlementPdfHelper; import band.gosrock.parameter.EventJobParameter; -import com.fasterxml.jackson.databind.ObjectMapper; -import java.io.ByteArrayOutputStream; -import java.time.LocalDateTime; -import java.util.Map; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.batch.core.Job; @@ -29,8 +22,6 @@ import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.thymeleaf.context.Context; -import org.thymeleaf.spring5.SpringTemplateEngine; @Slf4j @RequiredArgsConstructor @@ -49,13 +40,7 @@ public class EventSettlementPDF { private final EventSettlementAdaptor eventSettlementAdaptor; - private final PdfRender pdfRender; - - private final ObjectMapper objectMapper; - - private final SpringTemplateEngine templateEngine; - - private final S3PrivateFileService s3PrivateFileUploadService; + private final SettlementPdfHelper settlementPdfHelper; @Bean(BEAN_PREFIX + "eventJobParameter") @JobScope @@ -84,47 +69,7 @@ public Step userStatisticStep() { User masterUser = userAdaptor.queryUser(host.getMasterUserId()); EventSettlement eventSettlement = eventSettlementAdaptor.findByEventId(eventId); - // 결제 대행사 수수료 - - Money pgFee = eventSettlement.getPgFee(); - Money pgFeeVat = eventSettlement.getPgFeeVat(); - SettlementPDFDto settlementPDFDto = - SettlementPDFDto.builder() - .eventTitle(event.getEventBasic().getName()) - .hostName(masterUser.getProfile().getName()) - .settlementAt(event.getEndAt().plusDays(6L)) - .dudoongTicketAmount( - eventSettlement.getDudoongAmount().toString()) - .pgTicketAmount( - eventSettlement.getPaymentAmount().toString()) - .totalAmount( - eventSettlement - .getTotalSalesAmount() - .toString()) - // 초기 두둥 자체 수수료 없음. - .dudoongFee(Money.ZERO.toString()) - .pgFee(pgFee.toString()) - .totalFee(pgFee.toString()) - .totalFeeVat(pgFeeVat.toString()) - .totalSettlement( - eventSettlement.getTotalAmount().toString()) - .now(LocalDateTime.now()) - .build(); - Map result = objectMapper.convertValue(settlementPDFDto, Map.class); - - Context context = new Context(null, result); - context.setVariable("settlementAt", settlementPDFDto.getSettlementAt()); - context.setVariable("now", settlementPDFDto.getNow()); - // 정산 관련 타임리프 파일. - String html = templateEngine.process("settlement", context); - // html - ByteArrayOutputStream outputStream = - pdfRender.generatePdfFromHtml(html); - - String fileKey = - s3PrivateFileUploadService.eventSettlementPdfUpload( - event.getId(), outputStream); - log.info(fileKey); + settlementPdfHelper.uploadPdfToS3(event, eventSettlement, masterUser); return RepeatStatus.FINISHED; }) .build(); diff --git a/DuDoong-Batch/src/main/java/band/gosrock/job/EventSummarySettlement.java b/DuDoong-Batch/src/main/java/band/gosrock/job/EventSummarySettlement.java index 0b2e5b6c..b73aac1f 100644 --- a/DuDoong-Batch/src/main/java/band/gosrock/job/EventSummarySettlement.java +++ b/DuDoong-Batch/src/main/java/band/gosrock/job/EventSummarySettlement.java @@ -1,17 +1,12 @@ package band.gosrock.job; -import band.gosrock.domain.common.vo.Money; import band.gosrock.domain.domains.event.adaptor.EventAdaptor; import band.gosrock.domain.domains.event.domain.Event; import band.gosrock.domain.domains.order.adaptor.OrderAdaptor; import band.gosrock.domain.domains.order.domain.Order; -import band.gosrock.domain.domains.order.domain.OrderStatus; import band.gosrock.domain.domains.settlement.adaptor.EventSettlementAdaptor; -import band.gosrock.domain.domains.settlement.adaptor.TransactionSettlementAdaptor; -import band.gosrock.domain.domains.settlement.domain.EventSettlement; -import band.gosrock.domain.domains.settlement.domain.EventSettlementStatus; -import band.gosrock.domain.domains.settlement.domain.TransactionSettlement; +import band.gosrock.domain.domains.settlement.service.EventSettlementDomainService; import band.gosrock.parameter.EventJobParameter; import java.util.List; import lombok.RequiredArgsConstructor; @@ -26,6 +21,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +/** 이벤트 정산 수수료 , 내역등을 요약해서 저장합니다. */ @Slf4j @RequiredArgsConstructor @Configuration @@ -44,7 +40,7 @@ public class EventSummarySettlement { private final EventSettlementAdaptor eventSettlementAdaptor; - private final TransactionSettlementAdaptor transactionSettlementAdaptor; + private final EventSettlementDomainService eventSettlementDomainService; @Bean(BEAN_PREFIX + "eventJobParameter") @JobScope @@ -67,84 +63,8 @@ public Step eventSettlement() { Event event = eventJobParameter.getEvent(); Long eventId = event.getId(); eventSettlementAdaptor.deleteByEventId(eventId); - List orders = orderAdaptor.findByEventId(eventId); - Money totalSalesAmount = - orders.stream() - .filter(order -> order.getOrderStatus().isCanWithDraw()) - .map(Order::getTotalPaymentPrice) - .reduce(Money.ZERO, Money::plus); - - // 오더중에 승인 주문중 두둥 총 - Money dudoongTicketSalesAmount = - orders.stream() - .filter( - order -> - order.getOrderStatus() - == OrderStatus.APPROVED) - .map(Order::getTotalPaymentPrice) - .reduce(Money.ZERO, Money::plus); - // 오더중에 토스 페이먼츠 로결제를 진행한 목록을 추출. - Money paymentOrderTotalSales = - orders.stream() - .filter( - order -> - order.getOrderStatus() - == OrderStatus.CONFIRM) - .map(Order::getTotalPaymentPrice) - .reduce(Money.ZERO, Money::plus); - log.info("주문 결제 금액" + paymentOrderTotalSales); - // 오더중에 토스 페이먼츠로 결제를 진행한 목록중 쿠폰 할인 금액. - Money paymentOrderDiscountAmount = - orders.stream() - .filter( - order -> - order.getOrderStatus() - == OrderStatus.CONFIRM) - .map(Order::getTotalDiscountPrice) - .reduce(Money.ZERO, Money::plus); - - // 이벤트 트랜잭션 저장 목록 조회 - List transactionSettlements = - transactionSettlementAdaptor.findByEventId(eventId); - // 결제 된 금액 - - Money paymentAmount = - transactionSettlements.stream() - .map(TransactionSettlement::getPaymentAmount) - .reduce(Money.ZERO, Money::plus); - // TODO : 정산금액 밸리데이션 - // paymentOrderTotalSales == paymentAmount 이어야함! - - // 결제 정산 받을금액 - Money settlementAmount = - transactionSettlements.stream() - .map(TransactionSettlement::getSettlementAmount) - .reduce(Money.ZERO, Money::plus); - // PG 수수료 - Money pgFee = paymentAmount.minus(settlementAmount); - - // 중개 수수료 계산 공식? 그냥 정액으로.. - // 소숫점 없애기 - Money pgFeeVat = Money.wons(pgFee.times(0.1).longValue()); - Money totalAmount = paymentAmount.minus(pgFee).minus(pgFeeVat); - EventSettlement eventSettlement = - EventSettlement.builder() - .eventId(eventId) - .totalSalesAmount(totalSalesAmount) - .dudoongAmount(dudoongTicketSalesAmount) - .paymentAmount(paymentAmount) - .couponAmount(paymentOrderDiscountAmount) - .dudoongFee(Money.ZERO) - .pgFee(pgFee) - .pgFeeVat(pgFeeVat) - // 최종 정산금액 - .totalAmount(totalAmount) - .eventSettlementStatus(EventSettlementStatus.CALCULATED) - .build(); - - // 최종 정산 금액 계산. - eventSettlementAdaptor.save(eventSettlement); + eventSettlementDomainService.generateEventSettlement(eventId, orders); return RepeatStatus.FINISHED; }) .build(); diff --git a/DuDoong-Batch/src/main/java/band/gosrock/job/EventTransactionSettlement.java b/DuDoong-Batch/src/main/java/band/gosrock/job/EventTransactionSettlement.java index c845b68f..67dad868 100644 --- a/DuDoong-Batch/src/main/java/band/gosrock/job/EventTransactionSettlement.java +++ b/DuDoong-Batch/src/main/java/band/gosrock/job/EventTransactionSettlement.java @@ -24,6 +24,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +/** 토스페이먼츠 거래 내역들을 이벤트별로 취합 후 저장합니다. */ @Slf4j @RequiredArgsConstructor @Configuration @@ -64,46 +65,42 @@ public Step eventSettlement() { (contribution, chunkContext) -> { Event event = eventJobParameter.getEvent(); Long eventId = event.getId(); - // 멱등성 유지하기위해 - // 저장된 정산 목록에서 지움 + // 멱등성 유지하기위해 저장된 정산 목록에서 지움 ( 실제로 다시만들일은 없을듯...? ) transactionSettlementAdaptor.deleteByEventId(eventId); - List orders = orderAdaptor.findByEventId(eventId); - // 오더중에 토스 페이먼츠 로결제를 진행한 목록을 추출. - // 해당이벤트의 모든 주문 내역을 불러와야함. - // 토스에 환불진행되는 입금 건도 있음 - List paymentOrderUuids = - orders.stream() - .filter(order -> order.isPaid()) - .map(order -> order.getPgPaymentInfo().getPaymentKey()) - .toList(); - - // 시작 날짜. ( 이벤트 생성 시간 ) - LocalDate startAt = event.getCreatedAt().toLocalDate(); - // 끝나는 날짜. - LocalDate endAt = event.getEndAt().toLocalDate(); - // 데이터가 실제로 들어가야만 있음.. 테스트 코드로 돌려야함. - List settlements = - settlementClient.execute(startAt, endAt, "soldDate", 1, 10000); - - // 이벤트와 관련된 정산 객체 집합. - List transactionSettlements = - settlements.stream() - .filter( - settlementResponse -> - paymentOrderUuids.contains( - settlementResponse - .getPaymentKey())) - .map( - settlementResponse -> - TransactionSettlement.of( - eventId, settlementResponse)) - .toList(); - // 정산 정보 저장. - transactionSettlementAdaptor.saveAll(transactionSettlements); + // 정산 정보 저장 + transactionSettlementAdaptor.saveAll(getTransactionSettlements(event)); return RepeatStatus.FINISHED; }) .build(); } + + private List getPaymentOrderUUIDs(Long eventId) { + List orders = orderAdaptor.findByEventId(eventId); + return orders.stream() + .filter(Order::isPaid) + .map(order -> order.getPgPaymentInfo().getPaymentKey()) + .toList(); + } + + private List getTransactionSettlements(Event event) { + Long eventId = event.getId(); + List paymentOrderUuids = getPaymentOrderUUIDs(eventId); + List settlements = getTossPaymentsSettlementData(event); + + return settlements.stream() + .filter( + settlementResponse -> + paymentOrderUuids.contains(settlementResponse.getPaymentKey())) + .map(settlementResponse -> TransactionSettlement.of(eventId, settlementResponse)) + .toList(); + } + + // 토스페이먼츠에서 시작일 종료일 매출일 기준 정산액을 조회합니다. + private List getTossPaymentsSettlementData(Event event) { + LocalDate startAt = event.getCreatedAt().toLocalDate(); + LocalDate endAt = event.getEndAt().toLocalDate(); + return settlementClient.execute(startAt, endAt, "soldDate", 1, 10000); + } } diff --git a/DuDoong-Batch/src/main/java/band/gosrock/job/SlackUserStatistic.java b/DuDoong-Batch/src/main/java/band/gosrock/job/SlackUserStatistic.java index 2d754e20..1918f21f 100644 --- a/DuDoong-Batch/src/main/java/band/gosrock/job/SlackUserStatistic.java +++ b/DuDoong-Batch/src/main/java/band/gosrock/job/SlackUserStatistic.java @@ -2,8 +2,8 @@ import band.gosrock.domain.domains.user.adaptor.UserAdaptor; +import band.gosrock.helper.slack.SlackUserNotificationSender; import band.gosrock.parameter.DateJobParameter; -import band.gosrock.slack.SlackUserNotificationSender; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; diff --git a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/event/domain/Event.java b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/event/domain/Event.java index 9935516b..1e413cb9 100644 --- a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/event/domain/Event.java +++ b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/event/domain/Event.java @@ -178,4 +178,8 @@ public void deleteSoft() { this.status = DELETED; Events.raise(EventDeletionEvent.of(this)); } + + public String getEventName() { + return eventBasic.getName(); + } } diff --git a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/settlement/service/EventSettlementDomainService.java b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/settlement/service/EventSettlementDomainService.java index 2cec804d..eb821593 100644 --- a/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/settlement/service/EventSettlementDomainService.java +++ b/DuDoong-Domain/src/main/java/band/gosrock/domain/domains/settlement/service/EventSettlementDomainService.java @@ -2,8 +2,15 @@ import band.gosrock.common.annotation.DomainService; +import band.gosrock.domain.common.vo.Money; +import band.gosrock.domain.domains.order.domain.Order; +import band.gosrock.domain.domains.order.domain.OrderStatus; import band.gosrock.domain.domains.settlement.adaptor.EventSettlementAdaptor; +import band.gosrock.domain.domains.settlement.adaptor.TransactionSettlementAdaptor; import band.gosrock.domain.domains.settlement.domain.EventSettlement; +import band.gosrock.domain.domains.settlement.domain.EventSettlementStatus; +import band.gosrock.domain.domains.settlement.domain.TransactionSettlement; +import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.transaction.annotation.Transactional; @@ -12,10 +19,87 @@ public class EventSettlementDomainService { private final EventSettlementAdaptor eventSettlementAdaptor; + private final TransactionSettlementAdaptor transactionSettlementAdaptor; @Transactional - public void updateEventOrderListExcelFileKey(Long eventId, String key) { - EventSettlement eventSettlement = eventSettlementAdaptor.upsertByEventId(eventId); - eventSettlement.updateEventOrderListExcelKey(key); + public void generateEventSettlement(Long eventId, List orders) { + List transactionSettlements = + transactionSettlementAdaptor.findByEventId(eventId); + Money totalPaymentAmount = getTotalPaymentAmount(transactionSettlements); + Money pgFee = getPgFee(transactionSettlements, totalPaymentAmount); + Money pgFeeVat = getPgFeeVat(pgFee); + + EventSettlement eventSettlement = + EventSettlement.builder() + .eventId(eventId) + .totalSalesAmount(getTotalSalesAmount(orders)) + .dudoongAmount(getDudoongTicketSalesAmount(orders)) + .paymentAmount(totalPaymentAmount) + .couponAmount(getPaymentOrderDiscountAmount(orders)) + .dudoongFee(Money.ZERO) + .pgFee(pgFee) + .pgFeeVat(pgFeeVat) + .totalAmount(getTotalSettlementAmount(totalPaymentAmount, pgFee, pgFeeVat)) + .eventSettlementStatus(EventSettlementStatus.CALCULATED) + .build(); + + // 최종 정산 금액 계산. + eventSettlementAdaptor.save(eventSettlement); + } + /** 토스페이먼츠 수수료 */ + private Money getPgFee( + List transactionSettlements, Money paymentAmount) { + return paymentAmount.minus(getSettlementAmount(transactionSettlements)); + } + + /** 최종 정산금액 ( 판매대금 - 토스페이먼츠 수수료 - 토스페이먼츠 수수료 vat ) */ + private static Money getTotalSettlementAmount( + Money paymentAmount, Money pgFee, Money pgFeeVat) { + return paymentAmount.minus(pgFee).minus(pgFeeVat); + } + /** 토스페이먼츠 수수료 vat */ + private Money getPgFeeVat(Money pgFee) { + return Money.wons(pgFee.times(0.1).longValue()); + } + + private Money getPaymentOrderDiscountAmount(List orders) { + return orders.stream() + .filter(order -> order.getOrderStatus() == OrderStatus.CONFIRM) + .map(Order::getTotalDiscountPrice) + .reduce(Money.ZERO, Money::plus); + } + + private Money getPaymentOrderTotalSales(List orders) { + return orders.stream() + .filter(order -> order.getOrderStatus() == OrderStatus.CONFIRM) + .map(Order::getTotalPaymentPrice) + .reduce(Money.ZERO, Money::plus); + } + /** 주문목록 두둥티켓 판매 대금 */ + private Money getDudoongTicketSalesAmount(List orders) { + return orders.stream() + .filter(order -> order.getOrderStatus() == OrderStatus.APPROVED) + .map(Order::getTotalPaymentPrice) + .reduce(Money.ZERO, Money::plus); + } + /** 주문 액 기준 총 판매 대금 ( 두둥티켓 , 결제티켓 ) */ + private Money getTotalSalesAmount(List orders) { + return orders.stream() + .filter(order -> order.getOrderStatus().isCanWithDraw()) + .map(Order::getTotalPaymentPrice) + .reduce(Money.ZERO, Money::plus); + } + + /** 토스페이먼츠에서 정산해주는 금액 */ + private Money getSettlementAmount(List transactionSettlements) { + return transactionSettlements.stream() + .map(TransactionSettlement::getSettlementAmount) + .reduce(Money.ZERO, Money::plus); + } + /** 토스페이먼츠의 총 매출액 */ + private Money getTotalPaymentAmount(List transactionSettlements) { + return transactionSettlements.stream() + .map(TransactionSettlement::getPaymentAmount) + .reduce(Money.ZERO, Money::plus); } } diff --git a/DuDoong-Infrastructure/src/main/java/band/gosrock/infrastructure/config/s3/S3PrivateFileService.java b/DuDoong-Infrastructure/src/main/java/band/gosrock/infrastructure/config/s3/S3PrivateFileService.java index 0c6ce673..e505b853 100644 --- a/DuDoong-Infrastructure/src/main/java/band/gosrock/infrastructure/config/s3/S3PrivateFileService.java +++ b/DuDoong-Infrastructure/src/main/java/band/gosrock/infrastructure/config/s3/S3PrivateFileService.java @@ -72,16 +72,24 @@ private ObjectMetadata getPdfObjectMetadata(int contentLength) { return objectMetadata; } - public byte[] downloadEventSettlementPdf(Long eventId) throws IOException { + public byte[] downloadEventSettlementPdf(Long eventId) { S3Object object = amazonS3.getObject(bucket, getEventSettlementPdfKey(eventId)); S3ObjectInputStream finalObject = object.getObjectContent(); - return finalObject.readAllBytes(); + try { + return finalObject.readAllBytes(); + } catch (IOException e) { + throw new RuntimeException(e); + } } - public byte[] downloadEventOrdersExcel(Long eventId) throws IOException { + public byte[] downloadEventOrdersExcel(Long eventId) { S3Object object = amazonS3.getObject(bucket, eventOrdersExcelGetKey(eventId)); S3ObjectInputStream finalObject = object.getObjectContent(); - return finalObject.readAllBytes(); + try { + return finalObject.readAllBytes(); + } catch (IOException e) { + throw new RuntimeException(e); + } } } diff --git a/DuDoong-Infrastructure/src/main/java/band/gosrock/infrastructure/config/ses/AwsSesUtils.java b/DuDoong-Infrastructure/src/main/java/band/gosrock/infrastructure/config/ses/AwsSesUtils.java index bf882a70..9f5c117e 100644 --- a/DuDoong-Infrastructure/src/main/java/band/gosrock/infrastructure/config/ses/AwsSesUtils.java +++ b/DuDoong-Infrastructure/src/main/java/band/gosrock/infrastructure/config/ses/AwsSesUtils.java @@ -11,7 +11,6 @@ import javax.activation.DataSource; import javax.mail.MessagingException; import javax.mail.Session; -import javax.mail.internet.AddressException; import javax.mail.internet.InternetAddress; import javax.mail.internet.MimeBodyPart; import javax.mail.internet.MimeMessage; @@ -70,8 +69,7 @@ private Message newMessage(String subject, String html) { } // The HTML body of the email. - public void sendRawEmails(SendRawEmailDto sendRawEmailDto) - throws AddressException, MessagingException, IOException { + public void sendRawEmails(SendRawEmailDto sendRawEmailDto) throws MessagingException { Session session = Session.getDefaultInstance(new Properties()); // Create a new MimeMessage object.