SettlementServiceImpl.java 13.1 KB
package com.infoloop.tianting.service.impl;

import com.infoloop.tianting.clientcustomerorderservice.OrderStatusEnum;
import com.infoloop.tianting.clientcustomerorderservice.SingleClientCustomerOrderDetailRpcResponse;
import com.infoloop.tianting.clientcustomerorderservice.SingleClientCustomerOrderRpcResponse;
import com.infoloop.tianting.context.LoginContextHolder;
import com.infoloop.tianting.exception.ClientEndExceptions.BusinessException;
import com.infoloop.tianting.exception.ErrorCodeEnum;
import com.infoloop.tianting.menuservice.SingleMenuDetailRpcResponse;
import com.infoloop.tianting.model.dto.OrderDbDTO.QueryOrderByConditionDto;
import com.infoloop.tianting.model.dto.SettlementDTO;
import com.infoloop.tianting.model.dto.SettlementDTO.SettlementDataDto;
import com.infoloop.tianting.model.dto.SettlementDTO.SettlementMenuSkuDto;
import com.infoloop.tianting.model.dto.SettlementDTO.SettlementRequestDto;
import com.infoloop.tianting.service.SettlementService;
import com.infoloop.tianting.service.client.InventoryServiceRpcClient;
import com.infoloop.tianting.service.client.MenuServiceRpcClient;
import com.infoloop.tianting.service.client.OperatorServiceRpcClient;
import com.infoloop.tianting.service.client.OrderServiceRpcClient;
import com.infoloop.tianting.service.client.SkuServiceRpcClient;
import com.infoloop.tianting.utils.DateUtil;
import java.util.Comparator;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.Cell;
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.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
@Service
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class SettlementServiceImpl implements SettlementService {
  private final OrderServiceRpcClient orderServiceRpcClient;
  private final MenuServiceRpcClient menuServiceRpcClient;
  private final SkuServiceRpcClient skuServiceRpcClient;
  private final InventoryServiceRpcClient inventoryServiceRpcClient;

  @Override
  public ByteArrayOutputStream generateOrderSettlementExcel(SettlementRequestDto settlementRequest) {

    final var startDate =  settlementRequest.getTimeStart().toLocalDate().atStartOfDay();
    final var endDate = settlementRequest.getTimeEnd().toLocalDate().plusDays(1).atStartOfDay();
    final var operatorLoginInfo = LoginContextHolder.getLoginInfo();
    final var queryOrderDto = QueryOrderByConditionDto.builder()
        .enterpriseId(LoginContextHolder.hasLogin() ? operatorLoginInfo.getEnterpriseId() : settlementRequest.getEnterpriseId())
        .shouldFilterCreatedAtTimeStart(true)
        .createdAtTimeStart(startDate)
        .shouldFilterCreatedAtTimeEnd(true)
        .createdAtTimeEnd(endDate)
        .shouldFilterStallIds(!settlementRequest.getStallIds().isEmpty())
        .stallIds(settlementRequest.getStallIds())
        .build();
    final var orderList = orderServiceRpcClient.getOrdersByCondition(queryOrderDto);
    List<Integer> orderIds = orderList.stream()
        .filter(o -> !o.getStatus().equals(OrderStatusEnum.ORDER_CANCELED))
        .map(SingleClientCustomerOrderRpcResponse::getId).distinct()
        .collect(Collectors.toList());
    final var orderDetailList = orderServiceRpcClient.getOrderDetailsByOrderIds(orderIds);
    List<Integer> skuIds = orderDetailList.stream()
        .map(SingleClientCustomerOrderDetailRpcResponse::getSkuId)
        .distinct()
        .collect(Collectors.toList());
    final var skus = skuServiceRpcClient.getDishSkusByIds(skuIds).getResponseList();

    List<Integer> menuIds = orderList.stream().map(
        SingleClientCustomerOrderRpcResponse::getMenuId).distinct()
        .collect(Collectors.toList());
    final var menuList = menuServiceRpcClient
        .getMenusByIds(operatorLoginInfo.getEnterpriseId(), menuIds)
        .getResponsesList();
    final var menuDetailList = menuServiceRpcClient.queryMenuDetailsByMenuIds(
        operatorLoginInfo.getEnterpriseId(), menuIds).getResponsesList();

    Map<String, Map<String, List<SettlementMenuSkuDto>>> classifyOrders = new HashMap<>();

    //找出所有需要的日期
    final var dates = orderList.stream()
        .sorted(Comparator.comparingLong(SingleClientCustomerOrderRpcResponse::getCreatedAt))
        .map(o -> DateUtil.formatDateOfUtc(o.getCreatedAt(), DateUtil.YYYY_MM_DD_UTC))
        .distinct()
        .collect(Collectors.toList());
    for(String date: dates) {

      if (!classifyOrders.containsKey(date)) {
        classifyOrders.put(date, new HashMap<>());
      }
      final var menusMap = classifyOrders.get(date);

      // 找出当天所有的订单
      final var curOrderList = orderList.stream()
          .filter(o -> DateUtil.formatDateOfUtc(o.getCreatedAt(), DateUtil.YYYY_MM_DD_UTC).equals(date))
          .collect(Collectors.toList());
      final var curOrderIds = curOrderList.stream()
          .map(SingleClientCustomerOrderRpcResponse::getId)
          .collect(Collectors.toList());

      // 找出当天已点的所有餐单
      final var curMenuIds = curOrderList.stream()
          .map(SingleClientCustomerOrderRpcResponse::getMenuId)
          .distinct()
          .collect(Collectors.toList());
      for (Integer curMenuId: curMenuIds) {
        final var curMenu = menuList.stream().filter(m -> m.getId() == curMenuId).findFirst();
        if (curMenu.isEmpty()) {
          continue;
        }
        final var curMenuName = curMenu.get().getName();
        if (!menusMap.containsKey(curMenuName)) {
          menusMap.put(curMenuName, new ArrayList<>());
        }
        final var menuSkuList = new ArrayList<SettlementMenuSkuDto>();
        // 找出当天餐单所有的菜品
        final var curMenuDetails = menuDetailList.stream()
            .filter(md -> md.getMenuId() == curMenuId)
            .collect(Collectors.toList());

        final var curMenuDetailIds = curMenuDetails.stream()
            .map(SingleMenuDetailRpcResponse::getId)
            .collect(Collectors.toList());

        //找出当天所有已点的菜品明细
        final var curOrderDetails = orderDetailList.stream()
            .filter(d -> curOrderIds.contains(d.getOrderId()))
            .collect(Collectors.toList());

        for (SingleMenuDetailRpcResponse m: curMenuDetails) {
          // 找出该餐单下该sku所点菜品的明细
          final var curSkuOrderDetails = curOrderDetails.stream()
              .filter(rd-> rd.getMenuDetailId() == m.getId())
              .collect(Collectors.toList());
          final var countList = curSkuOrderDetails.stream()
              .map(SingleClientCustomerOrderDetailRpcResponse::getCount)
              .collect(Collectors.toList());
          int countTotal = countList.stream().mapToInt(Integer::intValue).sum();
          if (countTotal <= 0) {
            continue;
          }
          // 找出该sku的code
          final var curSku = skus.stream().filter(s -> s.getId() == m.getSkuId()).findFirst();
          String skuCode = "";
          if (curSku.isPresent()) {
            skuCode = curSku.get().getCode();
            final var existSku = menuSkuList.stream().filter(s -> s.getSkuCode().equals(curSku.get().getCode())).findFirst();
            if (existSku.isPresent()) {
              final var originalSku = existSku.get();
              final var count = existSku.get().getCount();
              final var newCount = count + countTotal;
              originalSku.setCount(newCount);
              originalSku.setTotalPrice(m.getPrice() * newCount);
              continue;
            }
          }

          final var settlementMenuSku = SettlementMenuSkuDto.builder()
              .skuCode(skuCode)
              .count(countTotal)
              .showName(m.getShowName())
              .price(m.getPrice())
              .totalPrice(m.getPrice() * countTotal)
              .build();
          menuSkuList.add(settlementMenuSku);

        }
        menusMap.get(curMenuName).addAll(menuSkuList);

      }
    }
    final var client = inventoryServiceRpcClient.getClientById(operatorLoginInfo.getEnterpriseId(),
        settlementRequest.getClientId()).getClient();
    final var settlementDataDto = SettlementDataDto.builder()
        .classifyOrders(classifyOrders)
        .client(client.getName())
        .startTime(DateUtil.formatDate(settlementRequest.getTimeStart(), DateUtil.YYYY_MM_DD))
        .endTime(DateUtil.formatDate(settlementRequest.getTimeEnd(), DateUtil.YYYY_MM_DD))
        .build();
    try {
       final var bytes = writeToExcel(settlementDataDto);
       return bytes;
    } catch (IOException e) {
      throw BusinessException.build(ErrorCodeEnum.GENERATE_EXCEL_ERROR);
    }

  }

  public static ByteArrayOutputStream writeToExcel(SettlementDataDto settlementDataDto)
      throws IOException {
    Workbook workbook = new XSSFWorkbook();
    Sheet sheet = workbook.createSheet("订单数据");

    final var classifyOrders = settlementDataDto.getClassifyOrders();

    int rowNum = 0;
    Row sheetTitleRow = sheet.createRow(rowNum++);
    Cell sheetTitleCell = sheetTitleRow.createCell(0);
    sheetTitleCell.setCellValue(settlementDataDto.getClient());
    Row dateRangeRow = sheet.createRow(rowNum++);
    Cell dateRangeCell = dateRangeRow.createCell(0);
    final var dateRange = settlementDataDto.getStartTime() + "至" + settlementDataDto.getEndTime();
    dateRangeCell.setCellValue(dateRange);
    Row titleRow = sheet.createRow(rowNum++);
    Cell dateTitleCell = titleRow.createCell(0);
    dateTitleCell.setCellValue("点餐日期");
    Cell menuTitleCell = titleRow.createCell(1);
    menuTitleCell.setCellValue("餐单名称");
    Cell skuCodeTitleCell = titleRow.createCell(2);
    skuCodeTitleCell.setCellValue("菜品编号");

    Cell skuNameTitleCell = titleRow.createCell(3);
    skuNameTitleCell.setCellValue("菜品名称");
    Cell skuPriceTitleCell = titleRow.createCell(4);
    skuPriceTitleCell.setCellValue("单价");
    Cell skuCountTitleCell = titleRow.createCell(5);
    skuCountTitleCell.setCellValue("数量");
    Cell skuTotalPriceTitleCell = titleRow.createCell(6);
    skuTotalPriceTitleCell.setCellValue("合计金额");

    for (Map.Entry<String, Map<String, List<SettlementMenuSkuDto>>> outerEntry : classifyOrders.entrySet()) {
      String orderDate = outerEntry.getKey();
      Map<String, List<SettlementMenuSkuDto>> innerMap = outerEntry.getValue();
      Integer curDateTotalRow = 0;
      for (Map.Entry<String, List<SettlementMenuSkuDto>> innerEntry : innerMap.entrySet()) {
        curDateTotalRow += innerEntry.getValue().size();
      }

      // 写入日期列并合并单元格
      int startRowForDate = rowNum;
      for (int i = 0; i < curDateTotalRow; i++) {
        Row dateRow = sheet.createRow(rowNum++);
        Cell dateCell = dateRow.createCell(0);
        dateCell.setCellValue(orderDate);
      }
      int endRowForDate = rowNum - 1;
      if (endRowForDate > startRowForDate) {
        CellRangeAddress dateRegion = new CellRangeAddress(startRowForDate, endRowForDate, 0, 0);
        sheet.addMergedRegion(dateRegion);
      }

      rowNum = startRowForDate;
      for (Map.Entry<String, List<SettlementMenuSkuDto>> innerEntry : innerMap.entrySet()) {
        String menuName = innerEntry.getKey();
        List<SettlementMenuSkuDto> skuList = innerEntry.getValue();

        // 写入菜单ID列并合并单元格
        int startRowForMenu = rowNum;
        for (int i = 0; i < skuList.size(); i++) {
          Row menuRow = sheet.getRow(rowNum++);
          Cell menuCell = menuRow.createCell(1);
          menuCell.setCellValue(menuName);
        }
        int endRowForMenu = rowNum - 1;
        if (endRowForMenu > startRowForMenu) {
          CellRangeAddress menuRegion = new CellRangeAddress(startRowForMenu, endRowForMenu, 1, 1);
          sheet.addMergedRegion(menuRegion);
        }

        // 写入SKU列
        rowNum = startRowForMenu;
        for (SettlementMenuSkuDto skuDto : skuList) {
          Row skuRow = sheet.getRow(rowNum++);
          Cell skuCodeCell = skuRow.createCell(2);
          skuCodeCell.setCellValue(skuDto.getSkuCode());
          Cell showNameCell = skuRow.createCell(3);
          showNameCell.setCellValue(skuDto.getShowName());
          Cell priceCell = skuRow.createCell(4);
          priceCell.setCellValue((double)skuDto.getPrice()/100);
          Cell countCell = skuRow.createCell(5);
          countCell.setCellValue(skuDto.getCount());
          Cell totalPriceCell = skuRow.createCell(6);
          totalPriceCell.setCellValue((double)skuDto.getTotalPrice()/100);
        }
      }
    }

    // 自动调整列宽
    for (int i = 0; i < 7; i++) {
      sheet.autoSizeColumn(i);
    }

    // 将工作簿内容写入字节数组输出流
    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
    workbook.write(outputStream);
    workbook.close();

    return outputStream;
  }

}