# HistoryAndForecastServiceByOpera.java

    package cloud.wconnect.frontoffice.parsereport.endofshift.impl;

    import cloud.wconnect.commonlib.cons.BaseConstant;
    import cloud.wconnect.commonlib.cons.BaseErrorCodeEnum;
    import cloud.wconnect.commonlib.cons.SystemPlatformEnum;
    import cloud.wconnect.commonlib.exception.ParseReportException;
    import cloud.wconnect.commonlib.pojo.dto.PropertyDTO;
    import cloud.wconnect.commonlib.pojo.dto.internationalization.InternationalizationNumberDTO;
    import cloud.wconnect.commonlib.util.DateTimeUtils;
    import cloud.wconnect.commonlib.util.InternationalizationUtils;
    import cloud.wconnect.frontoffice.parsereport.endofshift.IHistoryAndForecastService;
    import cloud.wconnect.frontoffice.pojo.dto.endofshift.report.HistoryAndForecastForEndOfShiftReportDTO;
    import lombok.extern.slf4j.Slf4j;
    import org.apache.commons.lang3.StringUtils;
    import org.dom4j.Document;
    import org.dom4j.DocumentException;
    import org.dom4j.Element;
    import org.dom4j.Node;
    import org.dom4j.io.SAXReader;
    import org.springframework.stereotype.Component;

    import java.io.InputStream;
    import java.math.BigDecimal;
    import java.math.RoundingMode;
    import java.time.LocalDate;
    import java.time.ZoneId;
    import java.time.format.DateTimeFormatter;
    import java.util.List;
    import java.util.Locale;

    /**
     * 解析 Opera 系统的 History And Forecast/Service 报告
     *
     * @author zc
     * @date 2023/06/01
     */
    @Slf4j
    @Component
    public class HistoryAndForecastServiceByOpera implements IHistoryAndForecastService {

        /**
         * 支持的报告来源
         *
         * @param source 报告来源
         * @return boolean
         * @author zc
         * @date 2023/6/1
         */
        @Override
        public boolean supports(String source) {
            return SystemPlatformEnum.OPERA.getDesc().equals(source);
        }

        /**
         * 解析报告
         *
         * @param in     文件
         * @param property 资产
         * @return HistoryAndForecastForEndOfShiftReportDTO
         * @author zc
         * @date 2023/6/1
         */
        @Override
        public HistoryAndForecastForEndOfShiftReportDTO parse(InputStream in, PropertyDTO property) throws ParseReportException {
            try {
                DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("dd-MMM-yy", Locale.ENGLISH);
                ZoneId zoneId = ZoneId.of(property.getTimezone());

                Document document = new SAXReader().read(in);
                List<Node> nodes = document.selectNodes("//G_CONSIDERED_DATE");

                long dateNowTime = DateTimeUtils.dateNowTimestamp(property.getTimezone());
                for (Node node : nodes) {
                    Element dataElement = (Element) node;

                    String consideredDate = dataElement.element("CONSIDERED_DATE").getTextTrim();
                    String[] consideredDateArr = StringUtils.split(consideredDate, "-");
                    consideredDateArr[1] = DateTimeUtils.capitalize(consideredDateArr[1]);
                    LocalDate localDate = LocalDate.parse(String.join("-", consideredDateArr), dateTimeFormatter);
                    long theDateTimestamp = DateTimeUtils.toTimestamp(localDate.atStartOfDay(zoneId));

                    if (dateNowTime == theDateTimestamp) {
                        HistoryAndForecastForEndOfShiftReportDTO historyAndForecast = new HistoryAndForecastForEndOfShiftReportDTO();
                        historyAndForecast.setTheDate(theDateTimestamp);
                        historyAndForecast.setPropertyId(property.getId());
                        String arrRooms = dataElement.element("ARRIVAL_ROOMS").getTextTrim();
                        historyAndForecast.setArrRooms(StringUtils.isEmpty(arrRooms) ? 0 : Integer.parseInt(arrRooms));
                        String compRooms = dataElement.element("COMPLIMENTARY_ROOMS").getTextTrim();
                        historyAndForecast.setCompRooms(StringUtils.isEmpty(compRooms) ? 0 : Integer.parseInt(compRooms));
                        String occPercent = dataElement.element("CF_OCCUPANCY").getTextTrim();

                        //获取国际化的配置
                        InternationalizationNumberDTO number = property.getInternationalization().getNumber();
                        RoundingMode roundingMode = InternationalizationUtils.getRoundingMode(number.getCalculationRule());
                        historyAndForecast.setOccPercent(StringUtils.isEmpty(occPercent) ? "0" : new BigDecimal(occPercent)
                                .setScale(BaseConstant.DATA_PRECISION, roundingMode).toString());

                        String depRooms = dataElement.element("DEPARTURE_ROOMS").getTextTrim();
                        historyAndForecast.setDepRooms(StringUtils.isEmpty(depRooms) ? 0 : Integer.parseInt(depRooms));
                        String oooRooms = dataElement.element("CF_OOO_ROOMS").getTextTrim();
                        historyAndForecast.setOooRooms(StringUtils.isEmpty(oooRooms) ? 0 : Integer.parseInt(oooRooms));
                        return historyAndForecast;
                    }
                }
                return null;
            } catch (DocumentException e) {
                log.error(e.getMessage(), e);
                throw new ParseReportException(BaseErrorCodeEnum.SYSTEM_ERROR.getI18nCode(),
                        BaseErrorCodeEnum.SYSTEM_ERROR.getCode(),
                        "source=opera, parse [History and forecast/service] report error", e);
            }
        }

    }