# LatestRateManualServiceImpl.java

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

    import cloud.wconnect.commonlib.component.BeanMapper;
    import cloud.wconnect.commonlib.pojo.dto.PropertyDTO;
    import cloud.wconnect.commonlib.util.UpdateLogUtil;
    import cloud.wconnect.rateshop.cons.revenue.RevenueCons;
    import cloud.wconnect.rateshop.entity.rateshop.Hotel;
    import cloud.wconnect.rateshop.entity.rateshop.PropertyHotel;
    import cloud.wconnect.rateshop.entity.rateshop.Setting;
    import cloud.wconnect.rateshop.entity.revenue.LatestRateManual;
    import cloud.wconnect.rateshop.mapper.revenue.LatestRateManualMapper;
    import cloud.wconnect.rateshop.pojo.dto.revenue.LatestRateManualDTO;
    import cloud.wconnect.rateshop.pojo.dto.revenue.UpdateRateDTO;
    import cloud.wconnect.rateshop.service.rateshop.IHotelService;
    import cloud.wconnect.rateshop.service.rateshop.IPropertyHotelService;
    import cloud.wconnect.rateshop.service.rateshop.ISettingService;
    import cloud.wconnect.rateshop.service.revenue.ILatestRateManualService;
    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 jakarta.annotation.Resource;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Transactional;

    import java.util.*;
    import java.util.function.Function;
    import java.util.stream.Collectors;

    /**
     * <p>
     * 手动编辑的最新房价表 服务实现类
     * </p>
     *
     * @author lichen
     * @since 2024-05-14
     */
    @Service
    @DS("rate_shop")
    public class LatestRateManualServiceImpl extends ServiceImpl<LatestRateManualMapper, LatestRateManual> implements ILatestRateManualService {

        @Autowired
        private IHotelService hotelService;
        @Autowired
        private ISettingService settingService;
        @Autowired
        private IPropertyHotelService propertyHotelService;
        @Resource
        private LatestRateManualMapper latestRateManualMapper;
        @Autowired
        private BeanMapper beanMapper;
        @Autowired
        private UpdateLogUtil updateLogUtil;

        /**
         * 查询租户下，指定酒店、指定币种、指定日期范围手动编辑的房价
         *
         * @param hotelId    酒店ID
         * @param currencyId 币种ID
         * @param startDate  开始日期（yyyyMMdd）
         * @param endDate    结束日期（yyyyMMdd）
         * @param propertyId 资产ID
         * @param pos        销售地区
         * @return java.util.List<cloud.wconnect.rateshop.entity.revenue.LatestRateManual>
         * @author lichen
         * @date 2024/5/16
         */
        @Override
        public List<LatestRateManual> list(Integer hotelId, Integer currencyId, Integer startDate, Integer endDate, Integer propertyId, String pos) {
            return list(new LambdaQueryWrapper<LatestRateManual>()
                    .eq(LatestRateManual::getPropertyId, propertyId)
                    .eq(LatestRateManual::getHotelId, hotelId)
                    .eq(LatestRateManual::getCurrencyId, currencyId)
                    .eq(LatestRateManual::getPos, pos)
                    .between(LatestRateManual::getCheckInDate, startDate, endDate));
        }

        /**
         * 修改房价
         *
         * @param propertyDTO             资产DTO
         * @param roomRates               修改的房价集合
         * @param syncOtherProperty       是否同步其他资产
         * @param userId                  更新人
         * @param propertiesByCurrentUser 当前操作人的所属资产
         * @return void
         * @author lichen
         * @date 2024/5/16
         */
        @Override
        @Transactional(rollbackFor = Exception.class)
        public void updateRates(PropertyDTO propertyDTO, List<UpdateRateDTO> roomRates, Boolean syncOtherProperty, int userId, List<Integer> propertiesByCurrentUser) {
            Setting setting = settingService.getByPropertyId(propertyDTO.getId());
            Integer currencyId = setting.getCurrencyId();
            Integer containTaxFlag = setting.getContainTaxFlag();
            String pos = setting.getPos();
            //酒店集合
            Map<String, Integer> hotelIdBySymbol = hotelService.listEffectiveBySymbols(roomRates.stream()
                            .map(UpdateRateDTO::getHotelSymbol).collect(Collectors.toSet()))
                    .stream().collect(Collectors.toMap(Hotel::getSymbol, Hotel::getId));
            Collection<Integer> hotelIds = hotelIdBySymbol.values();

            //酒店 和 需要同步的资产ID集合
            Map<Integer, List<Integer>> hotelId2PropertyIds = new HashMap<>();
            if (syncOtherProperty) {// 如果勾选了同步其他资产，则需要同步更新其他资产下的当前酒店的房价信息
                //查询酒店在指定币种下的关联关系 且 当前操作人有权限的资产
                List<PropertyHotel> propertyHotelList = propertyHotelService.listByHotelIdsAndCurrencyId(hotelIds, setting.getCurrencyId(), pos)
                        .stream().filter(propertyHotel -> propertiesByCurrentUser.contains(propertyHotel.getPropertyId()))
                        .toList();
                hotelId2PropertyIds = propertyHotelList.stream()
                        .collect(Collectors.groupingBy(PropertyHotel::getHotelId, Collectors.mapping(PropertyHotel::getPropertyId, Collectors.toList())));
            } else {
                for (Integer hotelId : hotelIds) {
                    hotelId2PropertyIds.put(hotelId, Collections.singletonList(propertyDTO.getId()));
                }
            }

            //要更新的房价集合
            ArrayList<LatestRateManualDTO> latestRateManualDTOS = new ArrayList<>();
            for (UpdateRateDTO roomRate : roomRates) {
                //获取资产ID
                Integer hotelId = hotelIdBySymbol.get(roomRate.getHotelSymbol());
                //获取需要同步的资产ID集合
                List<Integer> updatePropertyIds = hotelId2PropertyIds.get(hotelId);
                for (Integer updatePropertyId : updatePropertyIds) {
                    //来源
                    int source = updatePropertyId.equals(propertyDTO.getId()) ? RevenueCons.SELF_PROPERTY_MANUAL : RevenueCons.ELSE_PROPERTY_MANUAL;

                    latestRateManualDTOS.add(new LatestRateManualDTO().setPropertyId(updatePropertyId).setHotelId(hotelId)
                            .setCurrencyId(currencyId)
                            .setCheckInDate(Integer.valueOf(roomRate.getCheckInDate().replace("-", "")))
                            .setRateType(roomRate.getRateType()).setPrice(roomRate.getPrice())
                            .setPlatformId(roomRate.getPlatformId()).setSource(source)
                            .setPos(pos));
                }
            }

            //根据唯一索引查询手动维护的房价
            Map<String, LatestRateManual> uniqueKey2LatestRateManual = latestRateManualMapper.listByUnique(latestRateManualDTOS).stream()
                    .collect(Collectors.toMap(LatestRateManual::generate, Function.identity()));

            int size = roomRates.size();
            List<LatestRateManual> insertRates = Lists.newArrayListWithExpectedSize(size);
            List<LatestRateManual> updateRates = Lists.newArrayListWithExpectedSize(size);

            for (LatestRateManualDTO latestRateManualDTO : latestRateManualDTOS) {
                String uniqueKey = beanMapper.map(latestRateManualDTO, LatestRateManual.class).generate();
                //更新前的数据
                LatestRateManual oriLatestRateManual = uniqueKey2LatestRateManual.get(uniqueKey);

                if (Objects.isNull(oriLatestRateManual)) {//新增数据
                    LatestRateManual insertEntity = new LatestRateManual().setTenantId(propertyDTO.getTenantId())
                            .setPropertyId(latestRateManualDTO.getPropertyId())
                            .setHotelId(latestRateManualDTO.getHotelId()).setCurrencyId(latestRateManualDTO.getCurrencyId())
                            .setCheckInDate(latestRateManualDTO.getCheckInDate()).setPlatformId(latestRateManualDTO.getPlatformId())
                            .setRateType(latestRateManualDTO.getRateType()).setSource(latestRateManualDTO.getSource())
                            .setPos(pos)
                            .setUpdateLog(updateLogUtil.get(userId));
                    if (containTaxFlag == Setting.BEFORE_TAX_RATE) {
                        insertEntity.setRate(latestRateManualDTO.getPrice());
                    } else {
                        insertEntity.setAfterTaxRate(latestRateManualDTO.getPrice());
                    }
                    insertRates.add(insertEntity);
                } else {//修改数据
                    //最新的更新日志
                    String updateLog = updateLogUtil.append(oriLatestRateManual.getUpdateLog(), userId);

                    LatestRateManual updateEntity = new LatestRateManual().setId(oriLatestRateManual.getId())
                            .setPlatformId(latestRateManualDTO.getPlatformId())
                            .setSource(latestRateManualDTO.getSource()).setUpdateLog(updateLog)
                            //税前和税后房价先设置为原值
                            .setRate(oriLatestRateManual.getRate())
                            .setAfterTaxRate(oriLatestRateManual.getAfterTaxRate());
                    if (containTaxFlag == Setting.BEFORE_TAX_RATE) {
                        updateEntity.setRate(latestRateManualDTO.getPrice());
                    } else {
                        updateEntity.setAfterTaxRate(latestRateManualDTO.getPrice());
                    }
                    updateRates.add(updateEntity);
                }
            }
            //新增
            saveBatch(insertRates);
            //修改
            updateBatchById(updateRates);
        }
    }