Skip to content

Commit

Permalink
feature : 이벤트 정산 도메인 관련 1차 (#383)
Browse files Browse the repository at this point in the history
* feat : 주문 목록 엑셀화 틀잡기

* feat : excel 형식 맞추기

* feat : 엑셀 형식 지정 완료

* feat : s3 엑셀 업로드

* feat : s3 private 파일 업로드

* feat : 정산 요청 feign client

* feat : feign settlement json 파싱 테스트 틀

* feat : 파싱 테스트 완료

* feat : 정산 관련 엔티티 추가

* feat : 정산 정보 저장

* style : spotless apply

* fix : 테스트 임포트 수정
  • Loading branch information
ImNM authored Feb 20, 2023
1 parent 928d09c commit dd4f29d
Show file tree
Hide file tree
Showing 36 changed files with 1,222 additions and 6 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,6 @@ out/
.env
.env.*

*.xlsx

DuDoong-Domain/src/main/generated/**/*.java
2 changes: 2 additions & 0 deletions DuDoong-Batch/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ dependencies {
implementation project(':DuDoong-Common')
implementation project(':DuDoong-Infrastructure')
testImplementation('org.springframework.batch:spring-batch-test')
implementation 'org.apache.poi:poi:5.2.0'
implementation 'org.apache.poi:poi-ooxml:5.2.0'
}

test {
Expand Down
39 changes: 39 additions & 0 deletions DuDoong-Batch/src/main/java/band/gosrock/excel/ExcelOrderDto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package band.gosrock.excel;


import band.gosrock.domain.common.vo.Money;
import band.gosrock.domain.domains.order.domain.Order;
import band.gosrock.domain.domains.order.domain.OrderMethod;
import band.gosrock.domain.domains.order.domain.OrderStatus;
import java.time.LocalDateTime;
import lombok.Builder;
import lombok.Getter;

@Getter
@Builder
public class ExcelOrderDto {

private final String orderNo;
private final OrderMethod orderMethod;
private final OrderStatus orderStatus;
private final String orderName;
private final Long userId;
private final Money amount;
private final Long quantity;
private final LocalDateTime createdAt;
private final LocalDateTime refundAt;

public static ExcelOrderDto from(Order order) {
return ExcelOrderDto.builder()
.amount(order.getTotalPaymentPrice())
.orderNo(order.getOrderNo())
.orderMethod(order.getOrderMethod())
.orderStatus(order.getOrderStatus())
.orderName(order.getOrderName())
.userId(order.getUserId())
.quantity(order.getTotalQuantity())
.createdAt(order.getCreatedAt())
.refundAt(order.getWithDrawAt())
.build();
}
}
120 changes: 120 additions & 0 deletions DuDoong-Batch/src/main/java/band/gosrock/excel/ExcelOrderHelper.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
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<ExcelOrderDto> excelOrders) {
Workbook workbook = new XSSFWorkbook();

Field[] declaredFields = ExcelOrderDto.class.getDeclaredFields();

List<String> 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;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
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.TransactionSettlement;
import band.gosrock.parameter.EventJobParameter;
import java.util.List;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.JobScope;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Slf4j
@RequiredArgsConstructor
@Configuration
public class EventForClientSettlement {

private static final String JOB_NAME = "이벤트클라이언트정산";
private static final String BEAN_PREFIX = JOB_NAME + "_";

private final JobBuilderFactory jobBuilderFactory;
private final StepBuilderFactory stepBuilderFactory;
private final EventAdaptor eventAdaptor;
private final OrderAdaptor orderAdaptor;

@Qualifier(BEAN_PREFIX + "eventJobParameter")
private final EventJobParameter eventJobParameter;

private final EventSettlementAdaptor eventSettlementAdaptor;

private final TransactionSettlementAdaptor transactionSettlementAdaptor;

@Bean(BEAN_PREFIX + "eventJobParameter")
@JobScope
public EventJobParameter eventJobParameter() {
return new EventJobParameter(eventAdaptor);
}

@Bean(JOB_NAME)
public Job slackUserStatisticJob() {
return jobBuilderFactory.get(JOB_NAME).preventRestart().start(eventSettlement()).build();
}

@Bean(BEAN_PREFIX + "step")
@JobScope
public Step eventSettlement() {
return stepBuilderFactory
.get(BEAN_PREFIX + "step")
.tasklet(
(contribution, chunkContext) -> {
Event event = eventJobParameter.getEvent();
Long eventId = event.getId();
List<Order> orders = orderAdaptor.findByEventId(eventId);
// 오더중에 승인 주문중 두둥 총
Money approveOrderTotalSales =
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);
// 오더중에 토스 페이먼츠로 결제를 진행한 목록중 쿠폰 할인 금액.
Money paymentOrderDiscountAmount =
orders.stream()
.filter(
order ->
order.getOrderStatus()
== OrderStatus.CONFIRM)
.map(Order::getTotalDiscountPrice)
.reduce(Money.ZERO, Money::plus);

// 이벤트 트랜잭션 저장 목록 중에서 결제 대행 수수료 저장
List<TransactionSettlement> transactionSettlements =
transactionSettlementAdaptor.findByEventId(eventId);
Money paymentAmount =
transactionSettlements.stream()
.map(TransactionSettlement::getPaymentAmount)
.reduce(Money.ZERO, Money::plus);

transactionSettlements.stream()
.map(TransactionSettlement::getSettlementAmount)
.reduce(Money.ZERO, Money::plus);
// 중개 수수료 계산 공식? 그냥 정액으로..

// 최종 정산 금액 계산.

EventSettlement eventSettlement =
eventSettlementAdaptor.upsertByEventId(eventId);
return RepeatStatus.FINISHED;
})
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package band.gosrock.job;


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.settlement.service.EventSettlementDomainService;
import band.gosrock.excel.ExcelOrderDto;
import band.gosrock.excel.ExcelOrderHelper;
import band.gosrock.infrastructure.config.s3.S3PrivateFileUploadService;
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;
import org.springframework.batch.core.configuration.annotation.JobScope;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Slf4j
@RequiredArgsConstructor
@Configuration
public class EventOrdersToExcel {

private static final String JOB_NAME = "이벤트주문목록_엑셀업로드";
private static final String BEAN_PREFIX = JOB_NAME + "_";

private final JobBuilderFactory jobBuilderFactory;
private final StepBuilderFactory stepBuilderFactory;

private final ExcelOrderHelper excelOrderHelper;
private final EventAdaptor eventAdaptor;
private final OrderAdaptor orderAdaptor;

private final EventSettlementDomainService eventSettlementDomainService;

@Qualifier(BEAN_PREFIX + "eventJobParameter")
private final EventJobParameter eventJobParameter;

private final S3PrivateFileUploadService s3PrivateFileUploadService;

@Bean(BEAN_PREFIX + "eventJobParameter")
@JobScope
public EventJobParameter eventJobParameter() {
return new EventJobParameter(eventAdaptor);
}

@Bean(JOB_NAME)
public Job slackUserStatisticJob() {
return jobBuilderFactory.get(JOB_NAME).preventRestart().start(userStatisticStep()).build();
}

@Bean(BEAN_PREFIX + "step")
@JobScope
public Step userStatisticStep() {
return stepBuilderFactory
.get(BEAN_PREFIX + "step")
.tasklet(
(contribution, chunkContext) -> {
Event event = eventJobParameter.getEvent();
List<Order> eventOrders = orderAdaptor.findByEventId(event.getId());

// 주문 상태가 결제 완료, 승인 완료 , 환불 , 취소 인것만 가져오도록 필터링.
List<ExcelOrderDto> 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.excelUpload(
event.getId(), outputStream);
// 이벤트 정산용 엑셀 파일 업로드 정보 저장
eventSettlementDomainService.updateEventOrderListExcelFileKey(
event.getId(), fileKey);

return RepeatStatus.FINISHED;
})
.build();
}
}
Loading

0 comments on commit dd4f29d

Please sign in to comment.