# WalkRoomDateinRateServiceImpl.java

    package cloud.wconnect.frontoffice.service.walkroomrequest.impl;

    import cloud.wconnect.commonlib.component.SessionContext;
    import cloud.wconnect.commonlib.util.DateTimeUtils;
    import cloud.wconnect.commonlib.util.TransactionUtils;
    import cloud.wconnect.frontoffice.entity.walkroomrequest.*;
    import cloud.wconnect.frontoffice.mapper.walkroomrequest.WalkRoomDateinRateMapper;
    import cloud.wconnect.frontoffice.pojo.dto.walkroomrequest.WalkRateDTO;
    import cloud.wconnect.frontoffice.service.walkroomrequest.*;
    import com.baomidou.dynamic.datasource.annotation.DS;
    import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
    import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
    import com.google.common.collect.Lists;
    import com.google.common.collect.Maps;
    import org.apache.commons.collections.CollectionUtils;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Lazy;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Transactional;

    import java.math.BigDecimal;
    import java.util.*;
    import java.util.concurrent.Executor;
    import java.util.function.Function;
    import java.util.stream.Collectors;

    /**
     * <p>
     * 服务实现类
     * </p>
     *
     * @author lichen
     * @since 2023-07-08
     */
    @Service
    @DS("logbook")
    public class WalkRoomDateinRateServiceImpl extends ServiceImpl<WalkRoomDateinRateMapper, WalkRoomDateinRate> implements IWalkRoomDateinRateService {

        @Autowired
        private SessionContext sessionContext;
        @Autowired
        private IWalkRoomRateService walkRoomRateService;
        @Autowired
        private WalkRoomDateinRateMapper walkRoomDateinRateMapper;
        @Autowired
        @Lazy
        private IWalkRoomDateinOtherService walkRoomDateinOtherService;
        @Autowired
        @Lazy
        private IWalkRoomApproveLevelService approveLevelService;
        @Autowired
        @Lazy
        private IWalkRoomRequestService walkRoomRequestService;
        @Autowired
        private Executor executor;
        @Autowired
        @Lazy
        private IWalkRoomNotifyService walkRoomNotifyService;

        /**
         * 根据walkRoom主键id集合 和 入住日期集合 查询walk-rate数据
         *
         * @param reqIds walkRoom主键id集合
         * @param dates  入住日期集合(yyyyMMdd)
         * @return walk rate集合
         * @author lichen
         * @date 2023/7/24
         */
        @Override
        public List<WalkRoomDateinRate> listByReqIdAndDate(Collection<Long> reqIds, Collection<Integer> dates) {
            if (CollectionUtils.isEmpty(reqIds) && CollectionUtils.isEmpty(dates)) return Collections.emptyList();
            return list(new LambdaQueryWrapper<WalkRoomDateinRate>()
                    .in(CollectionUtils.isNotEmpty(reqIds), WalkRoomDateinRate::getReqId, reqIds)
                    .in(CollectionUtils.isNotEmpty(dates), WalkRoomDateinRate::getDate, dates));
        }

        /**
         * 修改walk rate记录的接收方
         *
         * @param reqId      walk room主键id
         * @param receiverId 修改后的接收方资产id
         * @return void
         * @author lichen
         * @date 2023/7/14
         */
        @Override
        @Transactional(rollbackFor = Exception.class)
        public void updateReceiverByReqId(Long reqId, Integer receiverId, int loginUserId) {
            //查询walkRoom所有的walk rate明细
            List<WalkRoomDateinRate> dateinRateList = list(new LambdaQueryWrapper<WalkRoomDateinRate>()
                    .eq(WalkRoomDateinRate::getReqId, reqId));
            if (CollectionUtils.isEmpty(dateinRateList)) return;

            //收集入住日
            List<Integer> dates = dateinRateList.stream().map(WalkRoomDateinRate::getDate).collect(Collectors.toList());

            //查询接收方在入住日批量设置的rate值
            Map<Integer, BigDecimal> date2Rate = walkRoomRateService.listByPropertyIdAndDates(receiverId, dates)
                    .stream().collect(Collectors.toMap(WalkRoomRate::getTheDate, WalkRoomRate::getRoomRate));

            dateinRateList.forEach(dateinRate -> {
                //设置接收方
                dateinRate.setToPropertyId(receiverId);
                //设置批量设置的rate
                dateinRate.setRate(date2Rate.get(dateinRate.getDate()));
                //单独设置的rate
                dateinRate.setRateByHand(null);
                //设置更新人
                dateinRate.setUpdateBy(loginUserId);
                //设置更新时间
                dateinRate.setUpdateTime(DateTimeUtils.nowTimestamp());
            });
            //批量修改
            updateBatchById(dateinRateList);
        }

        /**
         * 设置walk room某日的walk rate
         *
         * @param walkRoomRequest walk room数据
         * @param walkRateDTO     walk rate dto
         * @return void
         * @author lichen
         * @date 2023/7/19
         */
        @Override
        @Transactional(rollbackFor = Exception.class)
        public void setWalkRate(WalkRoomRequest walkRoomRequest, WalkRateDTO walkRateDTO) {
            //构建WalkRoomDateinRate
            WalkRoomDateinRate walkRoomDateinRate = new WalkRoomDateinRate();
            walkRoomDateinRate.setReqId(walkRoomRequest.getId());
            walkRoomDateinRate.setFromPropertyId(walkRoomRequest.getFromPropertyId());
            walkRoomDateinRate.setToPropertyId(walkRoomRequest.getToPropertyId());
            walkRoomDateinRate.setDate(walkRateDTO.getDate());
            walkRoomDateinRate.setRateByHand(walkRateDTO.getRate());//单独设置的rate值
            walkRoomDateinRate.setUpdateBy(sessionContext.getLoginUserId());
            walkRoomDateinRate.setUpdateTime(DateTimeUtils.nowTimestamp());
            //根据唯一索引保存或更新walk rate单独设置的值
            walkRoomDateinRateMapper.saveOrUpdateRateByHand(walkRoomDateinRate);

            //查询发送方和接收方的审批层级
            Integer fromPropertyId = walkRoomRequest.getFromPropertyId();
            Integer toPropertyId = walkRoomRequest.getToPropertyId();
            Map<String, List<WalkRoomApproveLevel>> propertyIdAndType2Levels = approveLevelService.listByPropertyIds(Arrays.asList(fromPropertyId, toPropertyId)).stream()
                    .collect(Collectors.groupingBy(item -> WalkRoomApproveLevel.generateKey(item.getPropertyId(), item.getType())));

            /**
             * 处理目标日期的入住记录和审批信息
             * 1.如果目标日期的入住记录存在则清空审批信息
             * 2.如果目标日期的入住记录不存在则生成入住记录
             */
            WalkRoomDateinOther dateinOther = walkRoomDateinOtherService.saveDateinOtherAndResetApproveInfo(walkRoomRequest, walkRateDTO.getDate(), propertyIdAndType2Levels, null);

            //更新finalOtherId
            walkRoomRequestService.updateFinalOtherIdAndFinalCrsNumber(walkRoomRequest);

            //发送审批通知
            TransactionUtils.afterCommitAsyncExecute(executor, () -> {
                walkRoomNotifyService.dateinOtherApproveResetSendApproveNotify(Lists.newArrayList(dateinOther));
            });
        }

        /**
         * 根据walkRoom主键id集合 和 入住日期集合 查询walk-rate数据
         *
         * @param reqIds walk room主键id集合
         * @param dates  入住日集合(yyyyMMdd)
         * @return java.util.Map<java.lang.String, java.math.BigDecimal>
         * @author lichen
         * @date 2023/7/24
         */
        @Override
        public Map<String, BigDecimal> listReqIdAndDateMapByReqIdAndDate(Collection<Long> reqIds, Collection<Integer> dates) {
            Map<String, WalkRoomDateinRate> reqIdAnddate2dateinWalkRateMap = listByReqIdAndDate(reqIds, dates).stream()
                    .collect(Collectors.toMap(dateinRate -> WalkRoomDateinRate.generateKey(dateinRate.getReqId(), dateinRate.getDate()),
                            Function.identity()));

            HashMap<String, BigDecimal> date2RateMap = Maps.newHashMapWithExpectedSize(reqIdAnddate2dateinWalkRateMap.size());
            for (Map.Entry<String, WalkRoomDateinRate> entry : reqIdAnddate2dateinWalkRateMap.entrySet()) {
                WalkRoomDateinRate dateinWalkRate = entry.getValue();
                BigDecimal rate;
                //当单独设置的walk rate不为空时，优先返回
                if (Objects.nonNull(dateinWalkRate.getRateByHand())) {
                    rate = dateinWalkRate.getRateByHand();
                } else {
                    rate = dateinWalkRate.getRate();
                }
                date2RateMap.put(entry.getKey(), rate);
            }
            return date2RateMap;
        }

        /**
         * 根据walkRoom主键id集合 和 入住日期集合 查询walk-rate数据
         *
         * @param reqId walk room主键id集合
         * @param dates 入住日集合(yyyyMMdd)
         * @return java.util.Map<java.lang.Integer, java.math.BigDecimal>
         * @author lichen
         * @date 2023/7/24
         */
        @Override
        public Map<Integer, BigDecimal> listDateMapByReqIdAndDate(Long reqId, Collection<Integer> dates) {
            //按照日期分组
            Map<Integer, WalkRoomDateinRate> date2dateinWalkRateMap = listByReqIdAndDate(Collections.singletonList(reqId), dates).stream()
                    .collect(Collectors.toMap(WalkRoomDateinRate::getDate, Function.identity()));

            HashMap<Integer, BigDecimal> date2RateMap = Maps.newHashMapWithExpectedSize(date2dateinWalkRateMap.size());
            for (Map.Entry<Integer, WalkRoomDateinRate> entry : date2dateinWalkRateMap.entrySet()) {
                WalkRoomDateinRate dateinWalkRate = entry.getValue();
                BigDecimal rate;
                //当单独设置的walk rate不为空时，优先返回
                if (Objects.nonNull(dateinWalkRate.getRateByHand())) {
                    rate = dateinWalkRate.getRateByHand();
                } else {
                    rate = dateinWalkRate.getRate();
                }
                date2RateMap.put(entry.getKey(), rate);
            }
            return date2RateMap;
        }

        /**
         * 删除walk rate
         *
         * @param reqId walk room主键id
         * @return void
         * @author lichen
         * @date 2023/7/25
         */
        @Override
        public void removeByReqId(Long reqId) {
            remove(new LambdaQueryWrapper<WalkRoomDateinRate>().eq(WalkRoomDateinRate::getReqId, reqId));
        }

        /**
         * 根据walk room主键id和日期范围 删除日期范围以外的walk rate
         *
         * @param reqId           walk room主键id
         * @param checkInDate     入住日期(yyyyMMdd)
         * @param checkOutDate    离店日期(yyyyMMdd)
         * @param isEarlyCheckOut 是否提前离店
         * @return void
         * @author lichen
         * @date 2023/7/25
         */
        @Override
        public void removeByReqIdAndDateRange(Long reqId, Integer checkInDate, Integer checkOutDate, boolean isEarlyCheckOut) {
            LambdaQueryWrapper<WalkRoomDateinRate> removeWrapper = new LambdaQueryWrapper<WalkRoomDateinRate>()
                    .eq(WalkRoomDateinRate::getReqId, reqId);
            if (isEarlyCheckOut) {
                //提前退房时，不删除checkOutDate当日的数据
                removeWrapper.and(queryWrapper -> queryWrapper.lt(Objects.nonNull(checkInDate), WalkRoomDateinRate::getDate, checkInDate)
                        .or().gt(Objects.nonNull(checkOutDate), WalkRoomDateinRate::getDate, checkOutDate));
            } else {
                //非提前退房时，删除checkOutDate当日的数据
                removeWrapper.and(queryWrapper -> queryWrapper.lt(Objects.nonNull(checkInDate), WalkRoomDateinRate::getDate, checkInDate)
                        .or().ge(Objects.nonNull(checkOutDate), WalkRoomDateinRate::getDate, checkOutDate));
            }
            remove(removeWrapper);
        }

    }