# RevenueOtbRevenueFutureServiceImpl.java

    package cloud.wconnect.rateshop.service.revenue.impl;

    import cloud.wconnect.commonlib.component.BeanMapper;
    import cloud.wconnect.commonlib.cons.BaseConstant;
    import cloud.wconnect.commonlib.pojo.dto.PropertyDTO;
    import cloud.wconnect.commonlib.pojo.dto.internationalization.InternationalizationNumberDTO;
    import cloud.wconnect.commonlib.redis.PropertyI18nRedisService;
    import cloud.wconnect.commonlib.util.DateTimeUtils;
    import cloud.wconnect.commonlib.util.InternationalizationUtils;
    import cloud.wconnect.commonlib.util.TransactionUtils;
    import cloud.wconnect.rateshop.entity.revenue.RevenueOtbRevenueFuture;
    import cloud.wconnect.rateshop.mapper.revenue.RevenueOtbRevenueFutureMapper;
    import cloud.wconnect.rateshop.pojo.bo.revenue.OtbRevenueFutureBO;
    import cloud.wconnect.rateshop.pojo.dto.revenue.OtbRevenueDTO;
    import cloud.wconnect.rateshop.service.revenue.IRevenueOtbRevenueFutureService;
    import cloud.wconnect.rateshop.service.revenue.IRevenueSendEventService;
    import com.baomidou.dynamic.datasource.annotation.DS;
    import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
    import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
    import com.google.common.collect.Lists;
    import org.apache.commons.collections.CollectionUtils;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Transactional;

    import java.math.BigDecimal;
    import java.math.RoundingMode;
    import java.time.YearMonth;
    import java.util.Comparator;
    import java.util.List;
    import java.util.Objects;
    import java.util.concurrent.Executor;

    /**
     * <p>
     *  服务实现类
     * </p>
     *
     * @author yyt
     * @since 2024-05-08
     */
    @Service
    @DS("rate_shop")
    public class RevenueOtbRevenueFutureServiceImpl extends ServiceImpl<RevenueOtbRevenueFutureMapper, RevenueOtbRevenueFuture> implements IRevenueOtbRevenueFutureService {

        @Autowired
        private BeanMapper beanMapper;
        @Autowired
        private Executor executor;
        @Autowired
        private IRevenueSendEventService revenueSendEventService;
        @Autowired
        private PropertyI18nRedisService propertyI18nRedisService;

        /**
         * 获取 otb revenue
         *
         * @param propertyDTO 资产
         * @param year        年
         * @param month       月
         * @return otb revenue
         * @author yyt
         * @date 2024/5/8
         */
        @Override
        public OtbRevenueDTO getOtbRevenueDTO(PropertyDTO propertyDTO, Integer year, Integer month) {
            // 获取指定年月数据
            RevenueOtbRevenueFuture otbRevenueFuture = getOne(new QueryWrapper<RevenueOtbRevenueFuture>().lambda()
                    .eq(RevenueOtbRevenueFuture::getPropertyId, propertyDTO.getId())
                    .eq(RevenueOtbRevenueFuture::getTheYear, year)
                    .eq(RevenueOtbRevenueFuture::getTheMonth, month));
            if (Objects.isNull(otbRevenueFuture)) {
                return new OtbRevenueDTO();
            }

            OtbRevenueDTO otbRevenueDTO = beanMapper.map(otbRevenueFuture, OtbRevenueDTO.class);
            otbRevenueDTO.setOtbRevPar(otbRevenueFuture.getOtbRevpar());
            return otbRevenueDTO;
        }

        /**
         * 保存 otb
         *
         * @param propertyDTO 资产
         * @param year        年
         * @param month       月
         * @param otb         修改内容
         * @param userId      操作人
         * @author yyt
         * @date 2024/5/11
         */
        @Override
        @Transactional(rollbackFor = Exception.class)
        public void save(PropertyDTO propertyDTO, Integer year, Integer month, OtbRevenueDTO otb, int userId) {
            long now = DateTimeUtils.nowTimestamp();
            RevenueOtbRevenueFuture otbRevenue = beanMapper.map(otb, RevenueOtbRevenueFuture.class);
            otbRevenue.setPropertyId(propertyDTO.getId()).setTheYear(year)
                    .setTheMonth(month).setUpdatedBy(userId).setUpdatedTime(now);
            // 计算 revpar
            calculateRevpar(otbRevenue);
            baseMapper.saveOrUpdate(otbRevenue);

            // 发送 otb revenue 事件
            sentOtbRevenueEvent(propertyDTO, Lists.newArrayList(otbRevenue));
        }

        /**
         * 计算 revpar
         *
         * @param otbRevenue otb revenue
         * @author yyt
         * @date 2024/5/11
         */
        private void calculateRevpar(RevenueOtbRevenueFuture otbRevenue) {
            InternationalizationNumberDTO number = propertyI18nRedisService.get(otbRevenue.getPropertyId())
                    .getInternationalization().getNumber();
            RoundingMode roundingMode = InternationalizationUtils.getRoundingMode(number.getCalculationRule());

            BigDecimal occPercent = otbRevenue.getOtbOccPercent();
            BigDecimal adr = otbRevenue.getOtbAdr();
            if (Objects.nonNull(occPercent) && Objects.nonNull(adr)) {
                // revpar = occ * adr
                BigDecimal otbRevpar = occPercent.multiply(adr).divide(BigDecimal.valueOf(100L), BaseConstant.DATA_PRECISION, roundingMode);
                otbRevenue.setOtbRevpar(otbRevpar);
            } else {
                otbRevenue.setOtbRevpar(null);
            }
        }

        /**
         * 发送 otb revenue 事件
         *
         * @param propertyDTO           资产
         * @param revenueOtbRevenueList otb revenue 集合
         * @author yyt
         * @date 2024/5/11
         */
        @Override
        public void sentOtbRevenueEvent(PropertyDTO propertyDTO, List<RevenueOtbRevenueFuture> revenueOtbRevenueList) {
            if (CollectionUtils.isEmpty(revenueOtbRevenueList)) {
                return;
            }

            // otb revenue 改动发送事件
            TransactionUtils.afterCommitAsyncExecute(executor, () -> {
                revenueSendEventService.sendOtbRevenueFutureEvent(propertyDTO, revenueOtbRevenueList);
            });
        }

        /**
         * 保存 otb revenue future
         *
         * @param propertyDTO            资产
         * @param otbRevenueFutureBOList otb revenue future 集合
         * @param userId                 操作人
         * @author yyt
         * @date 2024/5/20
         */
        @Override
        public void saveOtbRevenueFutureBO(PropertyDTO propertyDTO, List<OtbRevenueFutureBO> otbRevenueFutureBOList, int userId) {
            if (CollectionUtils.isEmpty(otbRevenueFutureBOList)) {
                return;
            }
            long now = DateTimeUtils.nowTimestamp();
            InternationalizationNumberDTO number = propertyDTO.getInternationalization().getNumber();
            int dataPrecision = BaseConstant.DATA_PRECISION;
            RoundingMode roundingMode = InternationalizationUtils.getRoundingMode(number.getCalculationRule());

            List<RevenueOtbRevenueFuture> revenueOtbRevenueFutureList = otbRevenueFutureBOList.stream().map(otbRevenueBO -> {
                YearMonth yearMonth = YearMonth.parse(otbRevenueBO.getMonth());
                RevenueOtbRevenueFuture otbRevenue = new RevenueOtbRevenueFuture().setPropertyId(propertyDTO.getId())
                        .setTheYear(yearMonth.getYear()).setTheMonth(yearMonth.getMonthValue())
                        .setOtbRevenue(Objects.isNull(otbRevenueBO.getOtbRevenue()) ? null
                                : otbRevenueBO.getOtbRevenue().setScale(dataPrecision, roundingMode))
                        .setOtbAdr(Objects.isNull(otbRevenueBO.getOtbAdr()) ? null
                                : otbRevenueBO.getOtbAdr().setScale(dataPrecision, roundingMode))
                        .setOtbOccPercent(Objects.isNull(otbRevenueBO.getOtbOccPercent()) ? null :
                                otbRevenueBO.getOtbOccPercent().setScale(dataPrecision, roundingMode))
                        .setUpdatedBy(userId).setUpdatedTime(now);
                // 计算 revpar
                calculateRevpar(otbRevenue);
                return otbRevenue;
            }).sorted(Comparator.comparing(RevenueOtbRevenueFuture::getTheYear).thenComparing(RevenueOtbRevenueFuture::getTheMonth)).toList();

            // 保存数据
            baseMapper.saveOrUpdateBatchForImport(revenueOtbRevenueFutureList);

            // 发送 otb revenue 事件
            sentOtbRevenueEvent(propertyDTO, revenueOtbRevenueFutureList);
        }

    }