# WMRevenueHistoryAndForecastParseServiceByOther.java

    package cloud.wconnect.rateshop.service.weeklymonthlyrevenue.historyandforecast;

    import cloud.wconnect.commonlib.cons.BaseConstant;
    import cloud.wconnect.commonlib.cons.BaseErrorCodeEnum;
    import cloud.wconnect.commonlib.cons.SystemPlatformEnum;
    import cloud.wconnect.commonlib.exception.InternalServerErrorException;
    import cloud.wconnect.commonlib.exception.ParseReportException;
    import cloud.wconnect.commonlib.pojo.dto.PropertyDTO;
    import cloud.wconnect.commonlib.util.*;
    import cloud.wconnect.rateshop.pojo.bo.weeklymonthlyrevenue.WMRevenueHistoryAndForecastBO;
    import com.baomidou.dynamic.datasource.annotation.DS;
    import com.google.common.collect.Lists;
    import lombok.extern.slf4j.Slf4j;
    import org.apache.commons.lang3.StringUtils;
    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.usermodel.WorkbookFactory;
    import org.springframework.stereotype.Component;

    import java.io.IOException;
    import java.io.InputStream;
    import java.math.BigDecimal;
    import java.math.RoundingMode;
    import java.util.List;

    /**
     * 解析 Other 的 History And Forecast/Service 报告
     *
     * @author zc
     * @date 2024/05/17
     */
    @Slf4j
    @Component
    @DS("rate_shop")
    public class WMRevenueHistoryAndForecastParseServiceByOther implements IWMRevenueHistoryAndForecastParseService{

        /**
         * 支持的报告来源
         *
         * @param source 报告来源
         * @return boolean
         * @author zc
         * @date 2024/5/17
         */
        @Override
        public boolean supports(String source) {
            return SystemPlatformEnum.OTHER.getDesc().equals(source);
        }

        /**
         * 解析报告
         *
         * @param in          报告文件流
         * @param propertyDTO 资产
         * @param dateRange   报告数据日期范围(yyyyMMdd)
         * @return WMRevenueHistoryAndForecastBO 集合
         * @author zc
         * @date 2024/8/22
         */
        @Override
        public List<WMRevenueHistoryAndForecastBO> parse(PropertyDTO propertyDTO, InputStream in, List<Long> dateRange) throws ParseReportException {
            try (Workbook workbook = WorkbookFactory.create(in)) {
                List<WMRevenueHistoryAndForecastBO> historyAndForecastBOList = Lists.newArrayList();

                long startDate = dateRange.get(0);
                long endDate = dateRange.get(1);

                RoundingMode roundingMode = InternationalizationUtils.getRoundingMode(propertyDTO
                        .getInternationalization().getNumber().getCalculationRule());

                Sheet sheet = workbook.getSheetAt(0);
                // 获取最大行数
                int lastRowNum = sheet.getLastRowNum();
                for (int i = 1; i <= lastRowNum; i++) {
                    Row row = sheet.getRow(i);

                    // Date
                    String dateStr = CellUtils.convertCellStr(row.getCell(0));
                    long date = Long.parseLong(DateTimeUtils.localDateToStr(DateTimeUtils.strToLocalDate(dateStr,
                            BaseConstant.DATE_FORMAT_YYYY_MM_DD), BaseConstant.DATE_FORMAT_YYYYMMDD));
                    // 判断数据日期是否在开始日期 和 结束日期之间
                    if (date < startDate || date > endDate) {
                        continue;
                    }

                    historyAndForecastBOList.add(convert2Bo(row, roundingMode));
                }

                return historyAndForecastBOList;
            } catch (IOException e) {
                log.error(e.getMessage(), e);
                throw new InternalServerErrorException(BaseErrorCodeEnum.SYSTEM_ERROR.getI18nCode(),
                        BaseErrorCodeEnum.SYSTEM_ERROR.getCode(),
                        "Handle parse Weekly Monthly Revenue History and Forecast Other report error.", e);
            }
        }

        /**
         * 转换为BO
         *
         * @param row          行
         * @param roundingMode 舍入模式
         * @return WMRevenueHistoryAndForecastBO
         * @author zc
         * @date 2025/5/21
         */
        private WMRevenueHistoryAndForecastBO convert2Bo(Row row, RoundingMode roundingMode) {
            WMRevenueHistoryAndForecastBO bo = new WMRevenueHistoryAndForecastBO();

            int scale = BaseConstant.DATA_PRECISION;
            String dateStr = CellUtils.convertCellStr(row.getCell(0));
            bo.setTheDay(dateStr);

            // Inventory rooms
            String inventoryRoomsStr = CellUtils.convertCellStr(row.getCell(1));
            bo.setInventoryRooms(StringUtils.isBlank(inventoryRoomsStr) ? null : Integer.parseInt(inventoryRoomsStr));
            // Sell Inventory rooms
            String sellInventoryRoomsStr = CellUtils.convertCellStr(row.getCell(2));
            bo.setSellInventoryRooms(StringUtils.isBlank(sellInventoryRoomsStr) ? null : Integer.parseInt(sellInventoryRoomsStr));
            // Revenue
            String revenueStr = CellUtils.convertCellStr(row.getCell(3));
            bo.setRoomRevenue(StringUtils.isEmpty(revenueStr) ? null : new BigDecimal(revenueStr)
                    .setScale(scale, roundingMode));
            // Deduct individual
            String deductIndividualStr = CellUtils.convertCellStr(row.getCell(4));
            bo.setDeductIndividual(StringUtils.isBlank(deductIndividualStr) ? null : Integer.parseInt(deductIndividualStr));
            // Deduct individual revenue
            String deductIndividualRevenueStr = CellUtils.convertCellStr(row.getCell(5));
            bo.setDeductIndividualRevenue(StringUtils.isEmpty(deductIndividualRevenueStr) ? null :
                    new BigDecimal(deductIndividualRevenueStr).setScale(scale, roundingMode));
            // Non deduct individual
            String nonDeductIndividualStr = CellUtils.convertCellStr(row.getCell(6));
            bo.setNonDeductIndividual(StringUtils.isBlank(nonDeductIndividualStr) ? null : Integer.parseInt(nonDeductIndividualStr));
            // Non deduct individual revenue
            String nonDeductIndividualRevenueStr = CellUtils.convertCellStr(row.getCell(7));
            bo.setNonDeductIndividualRevenue(StringUtils.isEmpty(nonDeductIndividualRevenueStr) ? null :
                    new BigDecimal(nonDeductIndividualRevenueStr).setScale(scale, roundingMode));
            // Deduct group
            String deductGroupStr = CellUtils.convertCellStr(row.getCell(8));
            bo.setDeductGroup(StringUtils.isBlank(deductGroupStr) ? null : Integer.parseInt(deductGroupStr));
            // Deduct group revenue
            String deductGroupRevenueStr = CellUtils.convertCellStr(row.getCell(9));
            bo.setDeductGroupRevenue(StringUtils.isEmpty(deductGroupRevenueStr) ? null :
                    new BigDecimal(deductGroupRevenueStr).setScale(scale, roundingMode));
            // Non deduct group
            String nonDeductGroupStr = CellUtils.convertCellStr(row.getCell(10));
            bo.setNonDeductGroup(StringUtils.isBlank(nonDeductGroupStr) ? null : Integer.parseInt(nonDeductGroupStr));
            // Non deduct group revenue
            String nonDeductGroupRevenueStr = CellUtils.convertCellStr(row.getCell(11));
            bo.setNonDeductGroupRevenue(StringUtils.isEmpty(nonDeductGroupRevenueStr) ? null :
                    new BigDecimal(nonDeductGroupRevenueStr).setScale(scale, roundingMode));
            // Number of persons
            String numberOfPersonsStr = CellUtils.convertCellStr(row.getCell(12));
            bo.setNumberOfPersons(StringUtils.isBlank(numberOfPersonsStr) ? null : Integer.parseInt(numberOfPersonsStr));
            // Arrival rooms
            String arrivalRoomsStr = CellUtils.convertCellStr(row.getCell(13));
            bo.setArrivalRooms(StringUtils.isBlank(arrivalRoomsStr) ? null : Integer.parseInt(arrivalRoomsStr));
            // Departure rooms
            String departureRoomsStr = CellUtils.convertCellStr(row.getCell(14));
            bo.setDepartureRooms(StringUtils.isBlank(departureRoomsStr) ? null : Integer.parseInt(departureRoomsStr));
            // Complimentary rooms
            String compRoomsStr = CellUtils.convertCellStr(row.getCell(15));
            bo.setComplimentaryRooms(StringUtils.isBlank(compRoomsStr) ? null : Integer.parseInt(compRoomsStr));
            // House Use rooms
            String houseUseRoomsStr = CellUtils.convertCellStr(row.getCell(16));
            bo.setHouseUseRooms(StringUtils.isBlank(houseUseRoomsStr) ? null : Integer.parseInt(houseUseRoomsStr));
            // Day Use rooms
            String dayUseRoomsStr = CellUtils.convertCellStr(row.getCell(17));
            bo.setDayUseRooms(StringUtils.isBlank(dayUseRoomsStr) ? null : Integer.parseInt(dayUseRoomsStr));
            // No show rooms
            String noShowRoomsStr = CellUtils.convertCellStr(row.getCell(18));
            bo.setNoShowRooms(StringUtils.isBlank(noShowRoomsStr) ? null : Integer.parseInt(noShowRoomsStr));
            // Out of order rooms
            String outOfOrderRoomsStr = CellUtils.convertCellStr(row.getCell(19));
            bo.setOooRooms(StringUtils.isBlank(outOfOrderRoomsStr) ? null : Integer.parseInt(outOfOrderRoomsStr));
            // Occ rooms
            String occRoomsStr = CellUtils.convertCellStr(row.getCell(20));
            bo.setTotalOcc(StringUtils.isBlank(occRoomsStr) ? null : Integer.parseInt(occRoomsStr));
            // Average room rate
            String avgRoomRateStr = CellUtils.convertCellStr(row.getCell(21));
            bo.setAverageRate(StringUtils.isEmpty(avgRoomRateStr) ? null : new BigDecimal(avgRoomRateStr)
                    .setScale(scale, roundingMode));
            // Occupancy
            String occupancyStr = CellUtils.convertCellStr(row.getCell(22));
            bo.setOccupancy(StringUtils.isBlank(occupancyStr) ? null : new BigDecimal(occupancyStr)
                    .setScale(scale, roundingMode));

            return bo;
        }
    }